LCOV - code coverage report
Current view: top level - lib/dpkg - triglib.c (source / functions) Coverage Total Hit
Test: dpkg 1.22.7-3-g89f48 C code coverage Lines: 7.9 % 353 28
Test Date: 2024-07-17 02:53:43 Functions: 8.9 % 45 4
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 3.9 % 207 8

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * libdpkg - Debian packaging suite library routines
       3                 :             :  * triglib.c - trigger handling
       4                 :             :  *
       5                 :             :  * Copyright © 2007 Canonical Ltd
       6                 :             :  * Written by Ian Jackson <ijackson@chiark.greenend.org.uk>
       7                 :             :  * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
       8                 :             :  *
       9                 :             :  * This is free software; you can redistribute it and/or modify
      10                 :             :  * it under the terms of the GNU General Public License as published by
      11                 :             :  * the Free Software Foundation; either version 2 of the License, or
      12                 :             :  * (at your option) any later version.
      13                 :             :  *
      14                 :             :  * This is distributed in the hope that it will be useful,
      15                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17                 :             :  * GNU General Public License for more details.
      18                 :             :  *
      19                 :             :  * You should have received a copy of the GNU General Public License
      20                 :             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21                 :             :  */
      22                 :             : 
      23                 :             : #include <config.h>
      24                 :             : #include <compat.h>
      25                 :             : 
      26                 :             : #include <sys/types.h>
      27                 :             : #include <sys/stat.h>
      28                 :             : 
      29                 :             : #include <errno.h>
      30                 :             : #include <stdlib.h>
      31                 :             : #include <unistd.h>
      32                 :             : 
      33                 :             : #include <dpkg/i18n.h>
      34                 :             : #include <dpkg/c-ctype.h>
      35                 :             : #include <dpkg/dpkg.h>
      36                 :             : #include <dpkg/dpkg-db.h>
      37                 :             : #include <dpkg/pkg.h>
      38                 :             : #include <dpkg/dlist.h>
      39                 :             : #include <dpkg/dir.h>
      40                 :             : #include <dpkg/pkg-spec.h>
      41                 :             : #include <dpkg/trigdeferred.h>
      42                 :             : #include <dpkg/triglib.h>
      43                 :             : 
      44                 :             : /*========== Recording triggers. ==========*/
      45                 :             : 
      46                 :             : static char *triggersdir, *triggersfilefile;
      47                 :             : 
      48                 :             : static char *
      49                 :          74 : trig_get_filename(const char *dir, const char *filename)
      50                 :             : {
      51                 :          74 :         return str_fmt("%s/%s", dir, filename);
      52                 :             : }
      53                 :             : 
      54                 :             : static struct trig_hooks trigh;
      55                 :             : 
      56                 :             : /*---------- Noting trigger activation in memory. ----------*/
      57                 :             : 
      58                 :             : /*
      59                 :             :  * Called via trig_*activate* et al from:
      60                 :             :  *   - trig_incorporate: reading of Unincorp (explicit trigger activations)
      61                 :             :  *   - various places: processing start (‘activate’ in triggers ci file)
      62                 :             :  *   - namenodetouse: file triggers during unpack / remove
      63                 :             :  *   - deferred_configure: file triggers during config file processing
      64                 :             :  *
      65                 :             :  * Not called from trig_transitional_activation; that runs
      66                 :             :  * trig_note_pend directly which means that (a) awaiters are not
      67                 :             :  * recorded (how would we know?) and (b) we don't enqueue them for
      68                 :             :  * deferred processing in this run.
      69                 :             :  *
      70                 :             :  * We add the trigger to Triggers-Pending first. This makes it
      71                 :             :  * harder to get into the state where Triggers-Awaited for aw lists
      72                 :             :  * pend but Triggers-Pending for pend is empty. (See also the
      73                 :             :  * comment in deppossi_ok_found regarding this situation.)
      74                 :             :  */
      75                 :             : 
      76                 :             : /*
      77                 :             :  * aw might be NULL.
      78                 :             :  * trig is not copied!
      79                 :             :  */
      80                 :             : static void
      81                 :           0 : trig_record_activation(struct pkginfo *pend, struct pkginfo *aw, const char *trig)
      82                 :             : {
      83         [ #  # ]:           0 :         if (pend->status < PKG_STAT_TRIGGERSAWAITED)
      84                 :           0 :                 return; /* Not interested then. */
      85                 :             : 
      86         [ #  # ]:           0 :         if (trig_note_pend(pend, trig))
      87                 :           0 :                 modstatdb_note_ifwrite(pend);
      88                 :             : 
      89         [ #  # ]:           0 :         if (trigh.enqueue_deferred)
      90                 :           0 :                 trigh.enqueue_deferred(pend);
      91                 :             : 
      92   [ #  #  #  # ]:           0 :         if (aw && pend->status > PKG_STAT_CONFIGFILES)
      93         [ #  # ]:           0 :                 if (trig_note_aw(pend, aw)) {
      94         [ #  # ]:           0 :                         if (aw->status > PKG_STAT_TRIGGERSAWAITED)
      95                 :           0 :                                 pkg_set_status(aw, PKG_STAT_TRIGGERSAWAITED);
      96                 :           0 :                         modstatdb_note_ifwrite(aw);
      97                 :             :                 }
      98                 :             : }
      99                 :             : 
     100                 :             : void
     101                 :           0 : trig_clear_awaiters(struct pkginfo *notpend)
     102                 :             : {
     103                 :             :         struct trigaw *ta;
     104                 :             : 
     105         [ #  # ]:           0 :         if (notpend->trigpend_head)
     106                 :           0 :                 internerr("package %s has pending triggers",
     107                 :             :                           pkg_name(notpend, pnaw_always));
     108                 :             : 
     109                 :           0 :         ta = notpend->othertrigaw_head;
     110                 :           0 :         notpend->othertrigaw_head = NULL;
     111         [ #  # ]:           0 :         for (; ta; ta = ta->samepend_next) {
     112                 :             :                 struct pkginfo *aw;
     113                 :             : 
     114                 :           0 :                 aw = ta->aw;
     115         [ #  # ]:           0 :                 if (!aw)
     116                 :           0 :                         continue;
     117   [ #  #  #  # ]:           0 :                 LIST_UNLINK_PART(aw->trigaw, ta, sameaw);
     118   [ #  #  #  # ]:           0 :                 if (!aw->trigaw.head && aw->status == PKG_STAT_TRIGGERSAWAITED) {
     119         [ #  # ]:           0 :                         if (aw->trigpend_head)
     120                 :           0 :                                 pkg_set_status(aw, PKG_STAT_TRIGGERSPENDING);
     121                 :             :                         else
     122                 :           0 :                                 pkg_set_status(aw, PKG_STAT_INSTALLED);
     123                 :           0 :                         modstatdb_note(aw);
     124                 :             :                 }
     125                 :             :         }
     126                 :           0 : }
     127                 :             : 
     128                 :             : /*
     129                 :             :  * Fix up packages in state triggers-awaited w/o the corresponding package
     130                 :             :  * with pending triggers. This can happen when dpkg was interrupted
     131                 :             :  * while in modstatdb_note, and the package in triggers-pending had its
     132                 :             :  * state modified but dpkg could not finish clearing the awaiters.
     133                 :             :  *
     134                 :             :  * XXX: Possibly get rid of some of the checks done somewhere else for
     135                 :             :  *      this condition at run-time.
     136                 :             :  */
     137                 :             : void
     138                 :          74 : trig_fixup_awaiters(enum modstatdb_rw cstatus)
     139                 :             : {
     140         [ +  - ]:          74 :         if (cstatus < msdbrw_write)
     141                 :          74 :                 return;
     142                 :             : 
     143                 :           0 :         trig_awaited_pend_foreach(trig_clear_awaiters);
     144                 :           0 :         trig_awaited_pend_free();
     145                 :             : }
     146                 :             : 
     147                 :             : /*---------- Generalized handling of trigger kinds. ----------*/
     148                 :             : 
     149                 :             : struct trigkindinfo {
     150                 :             :         /* Only for trig_activate_start. */
     151                 :             :         void (*activate_start)(void);
     152                 :             : 
     153                 :             :         /* Rest are for everyone: */
     154                 :             :         void (*activate_awaiter)(struct pkginfo *pkg /* may be NULL */);
     155                 :             :         void (*activate_done)(void);
     156                 :             :         void (*interest_change)(const char *name, struct pkginfo *pkg,
     157                 :             :                                 struct pkgbin *pkgbin,
     158                 :             :                                 int signum, enum trig_options opts);
     159                 :             : };
     160                 :             : 
     161                 :             : static const struct trigkindinfo tki_explicit, tki_file, tki_unknown;
     162                 :             : static const struct trigkindinfo *dtki;
     163                 :             : 
     164                 :             : /* As passed into activate_start. */
     165                 :             : static char *trig_activating_name;
     166                 :             : 
     167                 :             : static const struct trigkindinfo *
     168                 :           0 : trig_classify_byname(const char *name)
     169                 :             : {
     170         [ #  # ]:           0 :         if (name[0] == '/') {
     171                 :             :                 const char *slash;
     172                 :             : 
     173                 :           0 :                 slash = name;
     174         [ #  # ]:           0 :                 while (slash) {
     175   [ #  #  #  # ]:           0 :                         if (slash[1] == '\0' || slash[1] == '/')
     176                 :           0 :                                 goto invalid;
     177                 :             : 
     178                 :           0 :                         slash = strchr(slash + 2, '/');
     179                 :             :                 }
     180                 :           0 :                 return &tki_file;
     181                 :             :         }
     182                 :             : 
     183   [ #  #  #  # ]:           0 :         if (!pkg_name_is_illegal(name) && !strchr(name, '_'))
     184                 :           0 :                 return &tki_explicit;
     185                 :             : 
     186                 :           0 : invalid:
     187                 :           0 :         return &tki_unknown;
     188                 :             : }
     189                 :             : 
     190                 :             : static const char *
     191                 :           0 : trig_dump_trigger_options(enum trig_options opts)
     192                 :             : {
     193         [ #  # ]:           0 :         if (opts == TRIG_NOAWAIT)
     194                 :           0 :                 return "/noawait";
     195                 :           0 :         return "";
     196                 :             : }
     197                 :             : 
     198                 :             : /*
     199                 :             :  * Modifies the trigger string by removing the options at the ‘/’ delimiter
     200                 :             :  * and truncating it with a NUL character.
     201                 :             :  */
     202                 :             : static enum trig_options
     203                 :           0 : trig_parse_trigger_options(char *trigger)
     204                 :             : {
     205                 :             :         char *slash;
     206                 :             : 
     207                 :           0 :         slash = strchr(trigger, '/');
     208         [ #  # ]:           0 :         if (slash == NULL)
     209                 :           0 :                 return TRIG_AWAIT;
     210                 :             : 
     211                 :           0 :         *slash++ = '\0';
     212         [ #  # ]:           0 :         if (strcmp("noawait", slash) == 0)
     213                 :           0 :                 return TRIG_NOAWAIT;
     214         [ #  # ]:           0 :         if (strcmp("await", slash) == 0)
     215                 :           0 :                 return TRIG_AWAIT;
     216                 :             : 
     217                 :             :         /* XXX: Should perhaps warn or error for unknown keywords. */
     218                 :             : 
     219                 :           0 :         return TRIG_AWAIT;
     220                 :             : }
     221                 :             : 
     222                 :             : /*
     223                 :             :  * Calling sequence is:
     224                 :             :  *  trig_activate_start(triggername);
     225                 :             :  *  dtki->activate_awaiter(awaiting_package); } zero or more times
     226                 :             :  *  dtki->activate_awaiter(NULL);             }  in any order
     227                 :             :  *  dtki->activate_done();
     228                 :             :  */
     229                 :             : static void
     230                 :           0 : trig_activate_start(const char *name)
     231                 :             : {
     232                 :           0 :         dtki = trig_classify_byname(name);
     233                 :           0 :         trig_activating_name = nfstrsave(name);
     234                 :           0 :         dtki->activate_start();
     235                 :           0 : }
     236                 :             : 
     237                 :             : /*---------- Unknown trigger kinds. ----------*/
     238                 :             : 
     239                 :             : static void
     240                 :           0 : trk_unknown_activate_start(void)
     241                 :             : {
     242                 :           0 : }
     243                 :             : 
     244                 :             : static void
     245                 :           0 : trk_unknown_activate_awaiter(struct pkginfo *aw)
     246                 :             : {
     247                 :           0 : }
     248                 :             : 
     249                 :             : static void
     250                 :           0 : trk_unknown_activate_done(void)
     251                 :             : {
     252                 :           0 : }
     253                 :             : 
     254                 :             : static void DPKG_ATTR_NORET
     255                 :           0 : trk_unknown_interest_change(const char *trig, struct pkginfo *pkg,
     256                 :             :                             struct pkgbin *pkgbin, int signum,
     257                 :             :                             enum trig_options opts)
     258                 :             : {
     259                 :           0 :         ohshit(_("invalid or unknown syntax in trigger name '%.250s'"
     260                 :             :                  " (in trigger interests for package '%.250s')"),
     261                 :             :                trig, pkgbin_name(pkg, pkgbin, pnaw_nonambig));
     262                 :             : }
     263                 :             : 
     264                 :             : static const struct trigkindinfo tki_unknown = {
     265                 :             :         .activate_start = trk_unknown_activate_start,
     266                 :             :         .activate_awaiter = trk_unknown_activate_awaiter,
     267                 :             :         .activate_done = trk_unknown_activate_done,
     268                 :             :         .interest_change = trk_unknown_interest_change,
     269                 :             : };
     270                 :             : 
     271                 :             : /*---------- Explicit triggers. ----------*/
     272                 :             : 
     273                 :             : static FILE *trk_explicit_f;
     274                 :             : static struct varbuf trk_explicit_fn;
     275                 :             : static char *trk_explicit_trig;
     276                 :             : 
     277                 :             : static void
     278                 :           0 : trk_explicit_activate_done(void)
     279                 :             : {
     280         [ #  # ]:           0 :         if (trk_explicit_f) {
     281                 :           0 :                 fclose(trk_explicit_f);
     282                 :           0 :                 trk_explicit_f = NULL;
     283                 :             :         }
     284                 :           0 : }
     285                 :             : 
     286                 :             : static void
     287                 :           0 : trk_explicit_start(const char *trig)
     288                 :             : {
     289                 :           0 :         trk_explicit_activate_done();
     290                 :             : 
     291                 :           0 :         varbuf_reset(&trk_explicit_fn);
     292                 :           0 :         varbuf_add_dir(&trk_explicit_fn, triggersdir);
     293                 :           0 :         varbuf_add_str(&trk_explicit_fn, trig);
     294                 :             : 
     295                 :           0 :         trk_explicit_f = fopen(trk_explicit_fn.buf, "r");
     296         [ #  # ]:           0 :         if (!trk_explicit_f) {
     297         [ #  # ]:           0 :                 if (errno != ENOENT)
     298                 :           0 :                         ohshite(_("failed to open trigger interest list file '%.250s'"),
     299                 :             :                                 trk_explicit_fn.buf);
     300                 :             :         }
     301                 :           0 : }
     302                 :             : 
     303                 :             : static int
     304                 :           0 : trk_explicit_fgets(char *buf, size_t sz)
     305                 :             : {
     306                 :           0 :         return fgets_checked(buf, sz, trk_explicit_f, trk_explicit_fn.buf);
     307                 :             : }
     308                 :             : 
     309                 :             : static void
     310                 :           0 : trk_explicit_activate_start(void)
     311                 :             : {
     312                 :           0 :         trk_explicit_start(trig_activating_name);
     313                 :           0 :         trk_explicit_trig = trig_activating_name;
     314                 :           0 : }
     315                 :             : 
     316                 :             : static void
     317                 :           0 : trk_explicit_activate_awaiter(struct pkginfo *aw)
     318                 :             : {
     319                 :             :         char buf[1024];
     320                 :             : 
     321         [ #  # ]:           0 :         if (!trk_explicit_f)
     322                 :           0 :                 return;
     323                 :             : 
     324         [ #  # ]:           0 :         if (fseek(trk_explicit_f, 0, SEEK_SET))
     325                 :           0 :                 ohshite(_("failed to rewind trigger interest file '%.250s'"),
     326                 :             :                         trk_explicit_fn.buf);
     327                 :             : 
     328         [ #  # ]:           0 :         while (trk_explicit_fgets(buf, sizeof(buf)) >= 0) {
     329                 :             :                 struct pkginfo *pend;
     330                 :             :                 struct dpkg_error err;
     331                 :             :                 enum trig_options opts;
     332                 :             : 
     333                 :           0 :                 opts = trig_parse_trigger_options(buf);
     334                 :             : 
     335                 :           0 :                 pend = pkg_spec_parse_pkg(buf, &err);
     336         [ #  # ]:           0 :                 if (pend == NULL)
     337                 :           0 :                         ohshit(_("trigger interest file '%.250s' syntax error; "
     338                 :             :                                  "illegal package name '%.250s': %.250s"),
     339                 :             :                                trk_explicit_fn.buf, buf, err.str);
     340                 :             : 
     341         [ #  # ]:           0 :                 trig_record_activation(pend, opts == TRIG_NOAWAIT ? NULL : aw,
     342                 :             :                                        trk_explicit_trig);
     343                 :             :         }
     344                 :             : }
     345                 :             : 
     346                 :             : static void
     347                 :           0 : trk_explicit_interest_change(const char *trig,  struct pkginfo *pkg,
     348                 :             :                              struct pkgbin *pkgbin, int signum,
     349                 :             :                              enum trig_options opts)
     350                 :             : {
     351                 :             :         char buf[1024];
     352                 :             :         struct atomic_file *file;
     353                 :           0 :         bool empty = true;
     354                 :             : 
     355                 :           0 :         trk_explicit_start(trig);
     356                 :           0 :         file = atomic_file_new(trk_explicit_fn.buf, 0);
     357                 :           0 :         atomic_file_open(file);
     358                 :             : 
     359   [ #  #  #  # ]:           0 :         while (trk_explicit_f && trk_explicit_fgets(buf, sizeof(buf)) >= 0) {
     360                 :             :                 enum trig_options trig_opts;
     361                 :             :                 struct pkginfo *pkg_parsed;
     362                 :             :                 struct dpkg_error err;
     363                 :             : 
     364                 :           0 :                 trig_opts = trig_parse_trigger_options(buf);
     365                 :             : 
     366                 :           0 :                 pkg_parsed = pkg_spec_parse_pkg(buf, &err);
     367         [ #  # ]:           0 :                 if (pkg_parsed == NULL)
     368                 :           0 :                         ohshit(_("trigger interest file '%.250s' syntax error; "
     369                 :             :                                  "illegal package name '%.250s': %.250s"),
     370                 :             :                                trk_explicit_fn.buf, buf, err.str);
     371                 :             : 
     372         [ #  # ]:           0 :                 if (pkg == pkg_parsed &&
     373         [ #  # ]:           0 :                     (pkgbin == &pkg_parsed->installed ||
     374         [ #  # ]:           0 :                      pkgbin == &pkg_parsed->available))
     375                 :           0 :                         continue;
     376                 :             : 
     377                 :           0 :                 fprintf(file->fp, "%s%s\n", buf,
     378                 :             :                         trig_dump_trigger_options(trig_opts));
     379                 :           0 :                 empty = false;
     380                 :             :         }
     381         [ #  # ]:           0 :         if (signum > 0) {
     382                 :           0 :                 fprintf(file->fp, "%s%s\n",
     383                 :             :                         pkgbin_name(pkg, pkgbin, pnaw_same),
     384                 :             :                         trig_dump_trigger_options(opts));
     385                 :           0 :                 empty = false;
     386                 :             :         }
     387                 :             : 
     388         [ #  # ]:           0 :         if (!empty)
     389                 :           0 :                 atomic_file_sync(file);
     390                 :             : 
     391                 :           0 :         atomic_file_close(file);
     392                 :             : 
     393         [ #  # ]:           0 :         if (empty)
     394                 :           0 :                 atomic_file_remove(file);
     395                 :             :         else
     396                 :           0 :                 atomic_file_commit(file);
     397                 :             : 
     398                 :           0 :         atomic_file_free(file);
     399                 :             : 
     400                 :           0 :         dir_sync_path(triggersdir);
     401                 :           0 : }
     402                 :             : 
     403                 :             : static const struct trigkindinfo tki_explicit = {
     404                 :             :         .activate_start = trk_explicit_activate_start,
     405                 :             :         .activate_awaiter = trk_explicit_activate_awaiter,
     406                 :             :         .activate_done = trk_explicit_activate_done,
     407                 :             :         .interest_change = trk_explicit_interest_change,
     408                 :             : };
     409                 :             : 
     410                 :             : /*---------- File triggers. ----------*/
     411                 :             : 
     412                 :             : static struct {
     413                 :             :         struct trigfileint *head, *tail;
     414                 :             : } filetriggers;
     415                 :             : 
     416                 :             : /*
     417                 :             :  * Values:
     418                 :             :  *  -1: Not read.
     419                 :             :  *   0: Not edited.
     420                 :             :  *   1: Edited
     421                 :             :  */
     422                 :             : static int filetriggers_edited = -1;
     423                 :             : 
     424                 :             : /*
     425                 :             :  * Called by various people with signum -1 and +1 to mean remove and add
     426                 :             :  * and also by trig_file_interests_ensure() with signum +2 meaning add
     427                 :             :  * but die if already present.
     428                 :             :  */
     429                 :             : static void
     430                 :           0 : trk_file_interest_change(const char *trig, struct pkginfo *pkg,
     431                 :             :                          struct pkgbin *pkgbin, int signum,
     432                 :             :                          enum trig_options opts)
     433                 :             : {
     434                 :             :         struct fsys_namenode *fnn;
     435                 :             :         struct trigfileint **search, *tfi;
     436                 :             : 
     437                 :           0 :         fnn = trigh.namenode_find(trig, signum <= 0);
     438         [ #  # ]:           0 :         if (!fnn) {
     439         [ #  # ]:           0 :                 if (signum >= 0)
     440                 :           0 :                         internerr("lost filename node '%s' for package %s "
     441                 :             :                                   "triggered to add", trig,
     442                 :             :                                   pkgbin_name(pkg, pkgbin, pnaw_always));
     443                 :           0 :                 return;
     444                 :             :         }
     445                 :             : 
     446                 :           0 :         for (search = trigh.namenode_interested(fnn);
     447         [ #  # ]:           0 :              (tfi = *search);
     448                 :           0 :              search = &tfi->samefile_next)
     449         [ #  # ]:           0 :                 if (tfi->pkg == pkg)
     450                 :           0 :                         goto found;
     451                 :             : 
     452                 :             :         /* Not found. */
     453         [ #  # ]:           0 :         if (signum < 0)
     454                 :           0 :                 return;
     455                 :             : 
     456                 :           0 :         tfi = nfmalloc(sizeof(*tfi));
     457                 :           0 :         tfi->pkg = pkg;
     458                 :           0 :         tfi->pkgbin = pkgbin;
     459                 :           0 :         tfi->fnn = fnn;
     460                 :           0 :         tfi->options = opts;
     461                 :           0 :         tfi->samefile_next = *trigh.namenode_interested(fnn);
     462                 :           0 :         *trigh.namenode_interested(fnn) = tfi;
     463                 :             : 
     464         [ #  # ]:           0 :         LIST_LINK_TAIL_PART(filetriggers, tfi, inoverall);
     465                 :           0 :         goto edited;
     466                 :             : 
     467                 :           0 : found:
     468                 :           0 :         tfi->options = opts;
     469         [ #  # ]:           0 :         if (signum > 1)
     470                 :           0 :                 ohshit(_("duplicate file trigger interest for filename '%.250s' "
     471                 :             :                          "and package '%.250s'"), trig,
     472                 :             :                        pkgbin_name(pkg, pkgbin, pnaw_nonambig));
     473         [ #  # ]:           0 :         if (signum > 0)
     474                 :           0 :                 return;
     475                 :             : 
     476                 :             :         /* Remove it: */
     477                 :           0 :         *search = tfi->samefile_next;
     478   [ #  #  #  # ]:           0 :         LIST_UNLINK_PART(filetriggers, tfi, inoverall);
     479                 :           0 : edited:
     480                 :           0 :         filetriggers_edited = 1;
     481                 :             : }
     482                 :             : 
     483                 :             : static void
     484                 :           0 : trig_file_interests_remove(void)
     485                 :             : {
     486   [ #  #  #  # ]:           0 :         if (unlink(triggersfilefile) && errno != ENOENT)
     487                 :           0 :                 ohshite(_("cannot remove '%.250s'"), triggersfilefile);
     488                 :           0 : }
     489                 :             : 
     490                 :             : static void
     491                 :           0 : trig_file_interests_update(void)
     492                 :             : {
     493                 :             :         struct trigfileint *tfi;
     494                 :             :         struct atomic_file *file;
     495                 :             : 
     496                 :           0 :         file = atomic_file_new(triggersfilefile, 0);
     497                 :           0 :         atomic_file_open(file);
     498                 :             : 
     499         [ #  # ]:           0 :         for (tfi = filetriggers.head; tfi; tfi = tfi->inoverall.next)
     500                 :           0 :                 fprintf(file->fp, "%s %s%s\n", trigh.namenode_name(tfi->fnn),
     501                 :             :                         pkgbin_name(tfi->pkg, tfi->pkgbin, pnaw_same),
     502                 :             :                         trig_dump_trigger_options(tfi->options));
     503                 :             : 
     504                 :           0 :         atomic_file_sync(file);
     505                 :           0 :         atomic_file_close(file);
     506                 :           0 :         atomic_file_commit(file);
     507                 :           0 :         atomic_file_free(file);
     508                 :           0 : }
     509                 :             : 
     510                 :             : void
     511                 :           0 : trig_file_interests_save(void)
     512                 :             : {
     513         [ #  # ]:           0 :         if (filetriggers_edited <= 0)
     514                 :           0 :                 return;
     515                 :             : 
     516         [ #  # ]:           0 :         if (!filetriggers.head)
     517                 :           0 :                 trig_file_interests_remove();
     518                 :             :         else
     519                 :           0 :                 trig_file_interests_update();
     520                 :             : 
     521                 :           0 :         dir_sync_path(triggersdir);
     522                 :             : 
     523                 :           0 :         filetriggers_edited = 0;
     524                 :             : }
     525                 :             : 
     526                 :             : void
     527                 :          74 : trig_file_interests_ensure(void)
     528                 :             : {
     529                 :             :         FILE *f;
     530                 :             :         char linebuf[1024], *space;
     531                 :             :         struct pkginfo *pkg;
     532                 :             :         struct pkgbin *pkgbin;
     533                 :             : 
     534         [ -  + ]:          74 :         if (filetriggers_edited >= 0)
     535                 :           0 :                 return;
     536                 :             : 
     537                 :          74 :         f = fopen(triggersfilefile, "r");
     538         [ +  - ]:          74 :         if (!f) {
     539         [ +  - ]:          74 :                 if (errno == ENOENT)
     540                 :          74 :                         goto ok;
     541                 :           0 :                 ohshite(_("unable to read file triggers file '%.250s'"),
     542                 :             :                         triggersfilefile);
     543                 :             :         }
     544                 :             : 
     545                 :           0 :         push_cleanup(cu_closestream, ~0, 1, f);
     546         [ #  # ]:           0 :         while (fgets_checked(linebuf, sizeof(linebuf), f, triggersfilefile) >= 0) {
     547                 :             :                 struct dpkg_error err;
     548                 :             :                 enum trig_options trig_opts;
     549                 :             : 
     550                 :           0 :                 space = strchr(linebuf, ' ');
     551   [ #  #  #  # ]:           0 :                 if (!space || linebuf[0] != '/')
     552                 :           0 :                         ohshit(_("syntax error in file triggers file '%.250s'"),
     553                 :             :                                triggersfilefile);
     554                 :           0 :                 *space++ = '\0';
     555                 :             : 
     556                 :           0 :                 trig_opts = trig_parse_trigger_options(space);
     557                 :             : 
     558                 :           0 :                 pkg = pkg_spec_parse_pkg(space, &err);
     559         [ #  # ]:           0 :                 if (pkg == NULL)
     560                 :           0 :                         ohshit(_("file triggers record mentions illegal "
     561                 :             :                                  "package name '%.250s' (for interest in file "
     562                 :             :                                  "'%.250s'): %.250s"), space, linebuf, err.str);
     563                 :           0 :                 pkgbin = &pkg->installed;
     564                 :             : 
     565                 :           0 :                 trk_file_interest_change(linebuf, pkg, pkgbin, +2, trig_opts);
     566                 :             :         }
     567                 :           0 :         pop_cleanup(ehflag_normaltidy);
     568                 :          74 : ok:
     569                 :          74 :         filetriggers_edited = 0;
     570                 :             : }
     571                 :             : 
     572                 :             : void
     573                 :           0 : trig_file_activate_byname(const char *trig, struct pkginfo *aw)
     574                 :             : {
     575                 :           0 :         struct fsys_namenode *fnn = trigh.namenode_find(trig, 1);
     576                 :             : 
     577         [ #  # ]:           0 :         if (fnn)
     578                 :           0 :                 trig_file_activate(fnn, aw);
     579                 :           0 : }
     580                 :             : 
     581                 :             : void
     582                 :           0 : trig_file_activate(struct fsys_namenode *trig, struct pkginfo *aw)
     583                 :             : {
     584                 :             :         struct trigfileint *tfi;
     585                 :             : 
     586         [ #  # ]:           0 :         for (tfi = *trigh.namenode_interested(trig); tfi;
     587                 :           0 :              tfi = tfi->samefile_next)
     588         [ #  # ]:           0 :                 trig_record_activation(tfi->pkg, (tfi->options == TRIG_NOAWAIT) ?
     589                 :           0 :                                        NULL : aw, trigh.namenode_name(trig));
     590                 :           0 : }
     591                 :             : 
     592                 :             : static void
     593                 :           0 : trig_file_activate_parents(const char *trig, struct pkginfo *aw)
     594                 :             : {
     595                 :             :         char *path, *slash;
     596                 :             : 
     597                 :             :         /* Traverse the whole pathname to activate all of its components. */
     598                 :           0 :         path = m_strdup(trig);
     599                 :             : 
     600         [ #  # ]:           0 :         while ((slash = strrchr(path, '/'))) {
     601                 :           0 :                 *slash = '\0';
     602                 :           0 :                 trig_file_activate_byname(path, aw);
     603                 :             :         }
     604                 :             : 
     605                 :           0 :         free(path);
     606                 :           0 : }
     607                 :             : 
     608                 :             : void
     609                 :           0 : trig_path_activate(struct fsys_namenode *trig, struct pkginfo *aw)
     610                 :             : {
     611                 :           0 :         trig_file_activate(trig, aw);
     612                 :           0 :         trig_file_activate_parents(trigh.namenode_name(trig), aw);
     613                 :           0 : }
     614                 :             : 
     615                 :             : static void
     616                 :           0 : trig_path_activate_byname(const char *trig, struct pkginfo *aw)
     617                 :             : {
     618                 :           0 :         struct fsys_namenode *fnn = trigh.namenode_find(trig, 1);
     619                 :             : 
     620         [ #  # ]:           0 :         if (fnn)
     621                 :           0 :                 trig_file_activate(fnn, aw);
     622                 :             : 
     623                 :           0 :         trig_file_activate_parents(trig, aw);
     624                 :           0 : }
     625                 :             : 
     626                 :             : static const char *trk_file_trig;
     627                 :             : 
     628                 :             : static void
     629                 :           0 : trk_file_activate_start(void)
     630                 :             : {
     631                 :           0 :         trk_file_trig = trig_activating_name;
     632                 :           0 : }
     633                 :             : 
     634                 :             : static void
     635                 :           0 : trk_file_activate_awaiter(struct pkginfo *aw)
     636                 :             : {
     637                 :           0 :         trig_path_activate_byname(trk_file_trig, aw);
     638                 :           0 : }
     639                 :             : 
     640                 :             : static void
     641                 :           0 : trk_file_activate_done(void)
     642                 :             : {
     643                 :           0 : }
     644                 :             : 
     645                 :             : static const struct trigkindinfo tki_file = {
     646                 :             :         .activate_start = trk_file_activate_start,
     647                 :             :         .activate_awaiter = trk_file_activate_awaiter,
     648                 :             :         .activate_done = trk_file_activate_done,
     649                 :             :         .interest_change = trk_file_interest_change,
     650                 :             : };
     651                 :             : 
     652                 :             : /*---------- Trigger control info file. ----------*/
     653                 :             : 
     654                 :             : static void
     655                 :           0 : trig_cicb_interest_change(const char *trig, struct pkginfo *pkg,
     656                 :             :                           struct pkgbin *pkgbin, int signum,
     657                 :             :                           enum trig_options opts)
     658                 :             : {
     659                 :           0 :         const struct trigkindinfo *tki = trig_classify_byname(trig);
     660                 :             : 
     661         [ #  # ]:           0 :         if (filetriggers_edited < 0)
     662                 :           0 :                 internerr("trigger control file for package %s not read",
     663                 :             :                           pkgbin_name(pkg, pkgbin, pnaw_always));
     664                 :             : 
     665                 :           0 :         tki->interest_change(trig, pkg, pkgbin, signum, opts);
     666                 :           0 : }
     667                 :             : 
     668                 :             : void
     669                 :           0 : trig_cicb_interest_delete(const char *trig, struct pkginfo *pkg,
     670                 :             :                           struct pkgbin *pkgbin, enum trig_options opts)
     671                 :             : {
     672                 :           0 :         trig_cicb_interest_change(trig, pkg, pkgbin, -1, opts);
     673                 :           0 : }
     674                 :             : 
     675                 :             : void
     676                 :           0 : trig_cicb_interest_add(const char *trig, struct pkginfo *pkg,
     677                 :             :                        struct pkgbin *pkgbin, enum trig_options opts)
     678                 :             : {
     679                 :           0 :         trig_cicb_interest_change(trig, pkg, pkgbin, +1, opts);
     680                 :           0 : }
     681                 :             : 
     682                 :             : void
     683                 :           0 : trig_cicb_statuschange_activate(const char *trig, struct pkginfo *pkg,
     684                 :             :                                 struct pkgbin *pkgbin, enum trig_options opts)
     685                 :             : {
     686                 :           0 :         struct pkginfo *aw = pkg;
     687                 :             : 
     688                 :           0 :         trig_activate_start(trig);
     689         [ #  # ]:           0 :         dtki->activate_awaiter((opts == TRIG_NOAWAIT) ? NULL : aw);
     690                 :           0 :         dtki->activate_done();
     691                 :           0 : }
     692                 :             : 
     693                 :             : static void
     694                 :           0 : parse_ci_call(const char *file, const char *cmd, trig_parse_cicb *cb,
     695                 :             :               const char *trig, struct pkginfo *pkg, struct pkgbin *pkgbin,
     696                 :             :               enum trig_options opts)
     697                 :             : {
     698                 :             :         const char *emsg;
     699                 :             : 
     700                 :           0 :         emsg = trig_name_is_illegal(trig);
     701         [ #  # ]:           0 :         if (emsg)
     702                 :           0 :                 ohshit(_("triggers ci file '%.250s' contains illegal trigger "
     703                 :             :                          "syntax in trigger name '%.250s': %.250s"),
     704                 :             :                        file, trig, emsg);
     705         [ #  # ]:           0 :         if (cb)
     706                 :           0 :                 cb(trig, pkg, pkgbin, opts);
     707                 :           0 : }
     708                 :             : 
     709                 :             : void
     710                 :           0 : trig_parse_ci(const char *file, trig_parse_cicb *interest,
     711                 :             :               trig_parse_cicb *activate, struct pkginfo *pkg,
     712                 :             :               struct pkgbin *pkgbin)
     713                 :             : {
     714                 :             :         FILE *f;
     715                 :             :         char linebuf[MAXTRIGDIRECTIVE], *cmd, *spc, *eol;
     716                 :             :         int l;
     717                 :             : 
     718                 :           0 :         f = fopen(file, "r");
     719         [ #  # ]:           0 :         if (!f) {
     720         [ #  # ]:           0 :                 if (errno == ENOENT)
     721                 :           0 :                         return; /* No file is just like an empty one. */
     722                 :           0 :                 ohshite(_("unable to open triggers ci file '%.250s'"), file);
     723                 :             :         }
     724                 :           0 :         push_cleanup(cu_closestream, ~0, 1, f);
     725                 :             : 
     726         [ #  # ]:           0 :         while ((l = fgets_checked(linebuf, sizeof(linebuf), f, file)) >= 0) {
     727         [ #  # ]:           0 :                 for (cmd = linebuf; c_iswhite(*cmd); cmd++) ;
     728         [ #  # ]:           0 :                 if (*cmd == '#')
     729                 :           0 :                         continue;
     730   [ #  #  #  # ]:           0 :                 for (eol = linebuf + l; eol > cmd && c_iswhite(eol[-1]); eol--) ;
     731         [ #  # ]:           0 :                 if (eol == cmd)
     732                 :           0 :                         continue;
     733                 :           0 :                 *eol = '\0';
     734                 :             : 
     735   [ #  #  #  # ]:           0 :                 for (spc = cmd; *spc && !c_iswhite(*spc); spc++) ;
     736         [ #  # ]:           0 :                 if (!*spc)
     737                 :           0 :                         ohshit(_("triggers ci file contains unknown directive syntax"));
     738                 :           0 :                 *spc++ = '\0';
     739         [ #  # ]:           0 :                 while (c_iswhite(*spc))
     740                 :           0 :                         spc++;
     741         [ #  # ]:           0 :                 if (strcmp(cmd, "interest") == 0 ||
     742         [ #  # ]:           0 :                     strcmp(cmd, "interest-await") == 0) {
     743                 :           0 :                         parse_ci_call(file, cmd, interest, spc, pkg, pkgbin, TRIG_AWAIT);
     744         [ #  # ]:           0 :                 } else if (strcmp(cmd, "interest-noawait") == 0) {
     745                 :           0 :                         parse_ci_call(file, cmd, interest, spc, pkg, pkgbin, TRIG_NOAWAIT);
     746         [ #  # ]:           0 :                 } else if (strcmp(cmd, "activate") == 0 ||
     747         [ #  # ]:           0 :                            strcmp(cmd, "activate-await") == 0) {
     748                 :           0 :                         parse_ci_call(file, cmd, activate, spc, pkg, pkgbin, TRIG_AWAIT);
     749         [ #  # ]:           0 :                 } else if (strcmp(cmd, "activate-noawait") == 0) {
     750                 :           0 :                         parse_ci_call(file, cmd, activate, spc, pkg, pkgbin, TRIG_NOAWAIT);
     751                 :             :                 } else {
     752                 :           0 :                         ohshit(_("triggers ci file contains unknown directive '%.250s'"),
     753                 :             :                                cmd);
     754                 :             :                 }
     755                 :             :         }
     756                 :           0 :         pop_cleanup(ehflag_normaltidy); /* fclose() */
     757                 :             : }
     758                 :             : 
     759                 :             : /*---------- Unincorp file incorporation. ----------*/
     760                 :             : 
     761                 :             : static void
     762                 :           0 : tdm_incorp_trig_begin(const char *trig)
     763                 :             : {
     764                 :           0 :         trig_activate_start(trig);
     765                 :           0 : }
     766                 :             : 
     767                 :             : static void
     768                 :           0 : tdm_incorp_package(const char *awname)
     769                 :             : {
     770                 :             :         struct pkginfo *aw;
     771                 :             : 
     772         [ #  # ]:           0 :         if (strcmp(awname, "-") == 0)
     773                 :           0 :                 aw = NULL;
     774                 :             :         else
     775                 :           0 :                 aw = pkg_spec_parse_pkg(awname, NULL);
     776                 :             : 
     777                 :           0 :         dtki->activate_awaiter(aw);
     778                 :           0 : }
     779                 :             : 
     780                 :             : static void
     781                 :           0 : tdm_incorp_trig_end(void)
     782                 :             : {
     783                 :           0 :         dtki->activate_done();
     784                 :           0 : }
     785                 :             : 
     786                 :             : static const struct trigdefmeths tdm_incorp = {
     787                 :             :         .trig_begin = tdm_incorp_trig_begin,
     788                 :             :         .package = tdm_incorp_package,
     789                 :             :         .trig_end = tdm_incorp_trig_end
     790                 :             : };
     791                 :             : 
     792                 :             : void
     793                 :          74 : trig_incorporate(enum modstatdb_rw cstatus)
     794                 :             : {
     795                 :             :         enum trigdef_update_status ur;
     796                 :             :         enum trigdef_update_flags tduf;
     797                 :             : 
     798                 :          74 :         free(triggersdir);
     799                 :          74 :         triggersdir = dpkg_db_get_path(TRIGGERSDIR);
     800                 :             : 
     801                 :          74 :         free(triggersfilefile);
     802                 :          74 :         triggersfilefile = trig_get_filename(triggersdir, TRIGGERSFILEFILE);
     803                 :             : 
     804                 :          74 :         trigdef_set_methods(&tdm_incorp);
     805                 :          74 :         trig_file_interests_ensure();
     806                 :             : 
     807                 :          74 :         tduf = TDUF_NO_LOCK_OK;
     808         [ -  + ]:          74 :         if (cstatus >= msdbrw_write) {
     809                 :           0 :                 tduf |= TDUF_WRITE;
     810         [ #  # ]:           0 :                 if (trigh.transitional_activate)
     811                 :           0 :                         tduf |= TDUF_WRITE_IF_ENOENT;
     812                 :             :         }
     813                 :             : 
     814                 :          74 :         ur = trigdef_update_start(tduf);
     815   [ -  +  -  - ]:          74 :         if (ur == TDUS_ERROR_NO_DIR && cstatus >= msdbrw_write) {
     816         [ #  # ]:           0 :                 if (mkdir(triggersdir, 0755)) {
     817         [ #  # ]:           0 :                         if (errno != EEXIST)
     818                 :           0 :                                 ohshite(_("unable to create triggers state"
     819                 :             :                                           " directory '%.250s'"), triggersdir);
     820                 :             :                 }
     821                 :           0 :                 ur = trigdef_update_start(tduf);
     822                 :             :         }
     823   [ -  +  -  -  :          74 :         switch (ur) {
                      - ]
     824                 :           0 :         case TDUS_ERROR_EMPTY_DEFERRED:
     825                 :           0 :                 return;
     826                 :          74 :         case TDUS_ERROR_NO_DIR:
     827                 :             :         case TDUS_ERROR_NO_DEFERRED:
     828         [ +  - ]:          74 :                 if (!trigh.transitional_activate)
     829                 :          74 :                         return;
     830                 :             :         /* Fall through. */
     831                 :             :         case TDUS_NO_DEFERRED:
     832                 :           0 :                 trigh.transitional_activate(cstatus);
     833                 :           0 :                 break;
     834                 :           0 :         case TDUS_OK:
     835                 :             :                 /* Read and incorporate triggers. */
     836                 :           0 :                 trigdef_parse();
     837                 :           0 :                 break;
     838                 :           0 :         default:
     839                 :           0 :                 internerr("unknown trigdef_update_start return value '%d'", ur);
     840                 :             :         }
     841                 :             : 
     842                 :             :         /* Right, that's it. New (empty) Unincorp can be installed. */
     843                 :           0 :         trigdef_process_done();
     844                 :             : }
     845                 :             : 
     846                 :             : /*---------- Default hooks. ----------*/
     847                 :             : 
     848         [ #  # ]:           0 : TRIGHOOKS_DEFINE_NAMENODE_ACCESSORS
     849                 :             : 
     850                 :             : static struct trig_hooks trigh = {
     851                 :             :         .enqueue_deferred = NULL,
     852                 :             :         .transitional_activate = NULL,
     853                 :             :         .namenode_find = th_nn_find,
     854                 :             :         .namenode_interested = th_nn_interested,
     855                 :             :         .namenode_name = th_nn_name,
     856                 :             : };
     857                 :             : 
     858                 :             : void
     859                 :           0 : trig_override_hooks(const struct trig_hooks *hooks)
     860                 :             : {
     861                 :           0 :         trigh = *hooks;
     862                 :           0 : }
        

Generated by: LCOV version 2.0-1