LCOV - code coverage report
Current view: top level - lib/dpkg - triglib.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 28 354 7.9 %
Date: 2022-12-03 00:40:01 Functions: 4 45 8.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 8 207 3.9 %

           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                 :            :         struct pkginfo *aw;
     105                 :            : 
     106         [ #  # ]:          0 :         if (notpend->trigpend_head)
     107                 :          0 :                 internerr("package %s has pending triggers",
     108                 :            :                           pkg_name(notpend, pnaw_always));
     109                 :            : 
     110                 :          0 :         ta = notpend->othertrigaw_head;
     111                 :          0 :         notpend->othertrigaw_head = NULL;
     112         [ #  # ]:          0 :         for (; ta; ta = ta->samepend_next) {
     113                 :          0 :                 aw = ta->aw;
     114         [ #  # ]:          0 :                 if (!aw)
     115                 :          0 :                         continue;
     116   [ #  #  #  # ]:          0 :                 LIST_UNLINK_PART(aw->trigaw, ta, sameaw);
     117   [ #  #  #  # ]:          0 :                 if (!aw->trigaw.head && aw->status == PKG_STAT_TRIGGERSAWAITED) {
     118         [ #  # ]:          0 :                         if (aw->trigpend_head)
     119                 :          0 :                                 pkg_set_status(aw, PKG_STAT_TRIGGERSPENDING);
     120                 :            :                         else
     121                 :          0 :                                 pkg_set_status(aw, PKG_STAT_INSTALLED);
     122                 :          0 :                         modstatdb_note(aw);
     123                 :            :                 }
     124                 :            :         }
     125                 :          0 : }
     126                 :            : 
     127                 :            : /*
     128                 :            :  * Fix up packages in state triggers-awaited w/o the corresponding package
     129                 :            :  * with pending triggers. This can happen when dpkg was interrupted
     130                 :            :  * while in modstatdb_note, and the package in triggers-pending had its
     131                 :            :  * state modified but dpkg could not finish clearing the awaiters.
     132                 :            :  *
     133                 :            :  * XXX: Possibly get rid of some of the checks done somewhere else for
     134                 :            :  *      this condition at run-time.
     135                 :            :  */
     136                 :            : void
     137                 :         74 : trig_fixup_awaiters(enum modstatdb_rw cstatus)
     138                 :            : {
     139         [ +  - ]:         74 :         if (cstatus < msdbrw_write)
     140                 :         74 :                 return;
     141                 :            : 
     142                 :          0 :         trig_awaited_pend_foreach(trig_clear_awaiters);
     143                 :          0 :         trig_awaited_pend_free();
     144                 :            : }
     145                 :            : 
     146                 :            : /*---------- Generalized handling of trigger kinds. ----------*/
     147                 :            : 
     148                 :            : struct trigkindinfo {
     149                 :            :         /* Only for trig_activate_start. */
     150                 :            :         void (*activate_start)(void);
     151                 :            : 
     152                 :            :         /* Rest are for everyone: */
     153                 :            :         void (*activate_awaiter)(struct pkginfo *pkg /* may be NULL */);
     154                 :            :         void (*activate_done)(void);
     155                 :            :         void (*interest_change)(const char *name, struct pkginfo *pkg,
     156                 :            :                                 struct pkgbin *pkgbin,
     157                 :            :                                 int signum, enum trig_options opts);
     158                 :            : };
     159                 :            : 
     160                 :            : static const struct trigkindinfo tki_explicit, tki_file, tki_unknown;
     161                 :            : static const struct trigkindinfo *dtki;
     162                 :            : 
     163                 :            : /* As passed into activate_start. */
     164                 :            : static char *trig_activating_name;
     165                 :            : 
     166                 :            : static const struct trigkindinfo *
     167                 :          0 : trig_classify_byname(const char *name)
     168                 :            : {
     169         [ #  # ]:          0 :         if (name[0] == '/') {
     170                 :            :                 const char *slash;
     171                 :            : 
     172                 :          0 :                 slash = name;
     173         [ #  # ]:          0 :                 while (slash) {
     174   [ #  #  #  # ]:          0 :                         if (slash[1] == '\0' || slash[1] == '/')
     175                 :          0 :                                 goto invalid;
     176                 :            : 
     177                 :          0 :                         slash = strchr(slash + 2, '/');
     178                 :            :                 }
     179                 :          0 :                 return &tki_file;
     180                 :            :         }
     181                 :            : 
     182   [ #  #  #  # ]:          0 :         if (!pkg_name_is_illegal(name) && !strchr(name, '_'))
     183                 :          0 :                 return &tki_explicit;
     184                 :            : 
     185                 :          0 : invalid:
     186                 :          0 :         return &tki_unknown;
     187                 :            : }
     188                 :            : 
     189                 :            : static const char *
     190                 :          0 : trig_dump_trigger_options(enum trig_options opts)
     191                 :            : {
     192         [ #  # ]:          0 :         if (opts == TRIG_NOAWAIT)
     193                 :          0 :                 return "/noawait";
     194                 :          0 :         return "";
     195                 :            : }
     196                 :            : 
     197                 :            : /*
     198                 :            :  * Modifies the trigger string by removing the options at the ‘/’ delimiter
     199                 :            :  * and truncating it with a NUL character.
     200                 :            :  */
     201                 :            : static enum trig_options
     202                 :          0 : trig_parse_trigger_options(char *trigger)
     203                 :            : {
     204                 :            :         char *slash;
     205                 :            : 
     206                 :          0 :         slash = strchr(trigger, '/');
     207         [ #  # ]:          0 :         if (slash == NULL)
     208                 :          0 :                 return TRIG_AWAIT;
     209                 :            : 
     210                 :          0 :         *slash++ = '\0';
     211         [ #  # ]:          0 :         if (strcmp("noawait", slash) == 0)
     212                 :          0 :                 return TRIG_NOAWAIT;
     213         [ #  # ]:          0 :         if (strcmp("await", slash) == 0)
     214                 :          0 :                 return TRIG_AWAIT;
     215                 :            : 
     216                 :            :         /* XXX: Should perhaps warn or error for unknown keywords. */
     217                 :            : 
     218                 :          0 :         return TRIG_AWAIT;
     219                 :            : }
     220                 :            : 
     221                 :            : /*
     222                 :            :  * Calling sequence is:
     223                 :            :  *  trig_activate_start(triggername);
     224                 :            :  *  dtki->activate_awaiter(awaiting_package); } zero or more times
     225                 :            :  *  dtki->activate_awaiter(NULL);             }  in any order
     226                 :            :  *  dtki->activate_done();
     227                 :            :  */
     228                 :            : static void
     229                 :          0 : trig_activate_start(const char *name)
     230                 :            : {
     231                 :          0 :         dtki = trig_classify_byname(name);
     232                 :          0 :         trig_activating_name = nfstrsave(name);
     233                 :          0 :         dtki->activate_start();
     234                 :          0 : }
     235                 :            : 
     236                 :            : /*---------- Unknown trigger kinds. ----------*/
     237                 :            : 
     238                 :            : static void
     239                 :          0 : trk_unknown_activate_start(void)
     240                 :            : {
     241                 :          0 : }
     242                 :            : 
     243                 :            : static void
     244                 :          0 : trk_unknown_activate_awaiter(struct pkginfo *aw)
     245                 :            : {
     246                 :          0 : }
     247                 :            : 
     248                 :            : static void
     249                 :          0 : trk_unknown_activate_done(void)
     250                 :            : {
     251                 :          0 : }
     252                 :            : 
     253                 :            : static void DPKG_ATTR_NORET
     254                 :          0 : trk_unknown_interest_change(const char *trig, struct pkginfo *pkg,
     255                 :            :                             struct pkgbin *pkgbin, int signum,
     256                 :            :                             enum trig_options opts)
     257                 :            : {
     258                 :          0 :         ohshit(_("invalid or unknown syntax in trigger name '%.250s'"
     259                 :            :                  " (in trigger interests for package '%.250s')"),
     260                 :            :                trig, pkgbin_name(pkg, pkgbin, pnaw_nonambig));
     261                 :            : }
     262                 :            : 
     263                 :            : static const struct trigkindinfo tki_unknown = {
     264                 :            :         .activate_start = trk_unknown_activate_start,
     265                 :            :         .activate_awaiter = trk_unknown_activate_awaiter,
     266                 :            :         .activate_done = trk_unknown_activate_done,
     267                 :            :         .interest_change = trk_unknown_interest_change,
     268                 :            : };
     269                 :            : 
     270                 :            : /*---------- Explicit triggers. ----------*/
     271                 :            : 
     272                 :            : static FILE *trk_explicit_f;
     273                 :            : static struct varbuf trk_explicit_fn;
     274                 :            : static char *trk_explicit_trig;
     275                 :            : 
     276                 :            : static void
     277                 :          0 : trk_explicit_activate_done(void)
     278                 :            : {
     279         [ #  # ]:          0 :         if (trk_explicit_f) {
     280                 :          0 :                 fclose(trk_explicit_f);
     281                 :          0 :                 trk_explicit_f = NULL;
     282                 :            :         }
     283                 :          0 : }
     284                 :            : 
     285                 :            : static void
     286                 :          0 : trk_explicit_start(const char *trig)
     287                 :            : {
     288                 :          0 :         trk_explicit_activate_done();
     289                 :            : 
     290                 :          0 :         varbuf_reset(&trk_explicit_fn);
     291                 :          0 :         varbuf_add_dir(&trk_explicit_fn, triggersdir);
     292                 :          0 :         varbuf_add_str(&trk_explicit_fn, trig);
     293                 :          0 :         varbuf_end_str(&trk_explicit_fn);
     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                 :            :         struct pkginfo *pend;
     321                 :            : 
     322         [ #  # ]:          0 :         if (!trk_explicit_f)
     323                 :          0 :                 return;
     324                 :            : 
     325         [ #  # ]:          0 :         if (fseek(trk_explicit_f, 0, SEEK_SET))
     326                 :          0 :                 ohshite(_("failed to rewind trigger interest file '%.250s'"),
     327                 :            :                         trk_explicit_fn.buf);
     328                 :            : 
     329         [ #  # ]:          0 :         while (trk_explicit_fgets(buf, sizeof(buf)) >= 0) {
     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                 :            :         /* cppcheck-suppress[unusedStructMember]:
     414                 :            :          * False positive, macros from dlist.h use the tail member. */
     415                 :            :         struct trigfileint *head, *tail;
     416                 :            : } filetriggers;
     417                 :            : 
     418                 :            : /*
     419                 :            :  * Values:
     420                 :            :  *  -1: Not read.
     421                 :            :  *   0: Not edited.
     422                 :            :  *   1: Edited
     423                 :            :  */
     424                 :            : static int filetriggers_edited = -1;
     425                 :            : 
     426                 :            : /*
     427                 :            :  * Called by various people with signum -1 and +1 to mean remove and add
     428                 :            :  * and also by trig_file_interests_ensure() with signum +2 meaning add
     429                 :            :  * but die if already present.
     430                 :            :  */
     431                 :            : static void
     432                 :          0 : trk_file_interest_change(const char *trig, struct pkginfo *pkg,
     433                 :            :                          struct pkgbin *pkgbin, int signum,
     434                 :            :                          enum trig_options opts)
     435                 :            : {
     436                 :            :         struct fsys_namenode *fnn;
     437                 :            :         struct trigfileint **search, *tfi;
     438                 :            : 
     439                 :          0 :         fnn = trigh.namenode_find(trig, signum <= 0);
     440         [ #  # ]:          0 :         if (!fnn) {
     441         [ #  # ]:          0 :                 if (signum >= 0)
     442                 :          0 :                         internerr("lost filename node '%s' for package %s "
     443                 :            :                                   "triggered to add", trig,
     444                 :            :                                   pkgbin_name(pkg, pkgbin, pnaw_always));
     445                 :          0 :                 return;
     446                 :            :         }
     447                 :            : 
     448                 :          0 :         for (search = trigh.namenode_interested(fnn);
     449         [ #  # ]:          0 :              (tfi = *search);
     450                 :          0 :              search = &tfi->samefile_next)
     451         [ #  # ]:          0 :                 if (tfi->pkg == pkg)
     452                 :          0 :                         goto found;
     453                 :            : 
     454                 :            :         /* Not found. */
     455         [ #  # ]:          0 :         if (signum < 0)
     456                 :          0 :                 return;
     457                 :            : 
     458                 :          0 :         tfi = nfmalloc(sizeof(*tfi));
     459                 :          0 :         tfi->pkg = pkg;
     460                 :          0 :         tfi->pkgbin = pkgbin;
     461                 :          0 :         tfi->fnn = fnn;
     462                 :          0 :         tfi->options = opts;
     463                 :          0 :         tfi->samefile_next = *trigh.namenode_interested(fnn);
     464                 :          0 :         *trigh.namenode_interested(fnn) = tfi;
     465                 :            : 
     466         [ #  # ]:          0 :         LIST_LINK_TAIL_PART(filetriggers, tfi, inoverall);
     467                 :          0 :         goto edited;
     468                 :            : 
     469                 :          0 : found:
     470                 :          0 :         tfi->options = opts;
     471         [ #  # ]:          0 :         if (signum > 1)
     472                 :          0 :                 ohshit(_("duplicate file trigger interest for filename '%.250s' "
     473                 :            :                          "and package '%.250s'"), trig,
     474                 :            :                        pkgbin_name(pkg, pkgbin, pnaw_nonambig));
     475         [ #  # ]:          0 :         if (signum > 0)
     476                 :          0 :                 return;
     477                 :            : 
     478                 :            :         /* Remove it: */
     479                 :          0 :         *search = tfi->samefile_next;
     480   [ #  #  #  # ]:          0 :         LIST_UNLINK_PART(filetriggers, tfi, inoverall);
     481                 :          0 : edited:
     482                 :          0 :         filetriggers_edited = 1;
     483                 :            : }
     484                 :            : 
     485                 :            : static void
     486                 :          0 : trig_file_interests_remove(void)
     487                 :            : {
     488   [ #  #  #  # ]:          0 :         if (unlink(triggersfilefile) && errno != ENOENT)
     489                 :          0 :                 ohshite(_("cannot remove '%.250s'"), triggersfilefile);
     490                 :          0 : }
     491                 :            : 
     492                 :            : static void
     493                 :          0 : trig_file_interests_update(void)
     494                 :            : {
     495                 :            :         struct trigfileint *tfi;
     496                 :            :         struct atomic_file *file;
     497                 :            : 
     498                 :          0 :         file = atomic_file_new(triggersfilefile, 0);
     499                 :          0 :         atomic_file_open(file);
     500                 :            : 
     501         [ #  # ]:          0 :         for (tfi = filetriggers.head; tfi; tfi = tfi->inoverall.next)
     502                 :          0 :                 fprintf(file->fp, "%s %s%s\n", trigh.namenode_name(tfi->fnn),
     503                 :            :                         pkgbin_name(tfi->pkg, tfi->pkgbin, pnaw_same),
     504                 :            :                         trig_dump_trigger_options(tfi->options));
     505                 :            : 
     506                 :          0 :         atomic_file_sync(file);
     507                 :          0 :         atomic_file_close(file);
     508                 :          0 :         atomic_file_commit(file);
     509                 :          0 :         atomic_file_free(file);
     510                 :          0 : }
     511                 :            : 
     512                 :            : void
     513                 :          0 : trig_file_interests_save(void)
     514                 :            : {
     515         [ #  # ]:          0 :         if (filetriggers_edited <= 0)
     516                 :          0 :                 return;
     517                 :            : 
     518         [ #  # ]:          0 :         if (!filetriggers.head)
     519                 :          0 :                 trig_file_interests_remove();
     520                 :            :         else
     521                 :          0 :                 trig_file_interests_update();
     522                 :            : 
     523                 :          0 :         dir_sync_path(triggersdir);
     524                 :            : 
     525                 :          0 :         filetriggers_edited = 0;
     526                 :            : }
     527                 :            : 
     528                 :            : void
     529                 :         74 : trig_file_interests_ensure(void)
     530                 :            : {
     531                 :            :         FILE *f;
     532                 :            :         char linebuf[1024], *space;
     533                 :            :         struct pkginfo *pkg;
     534                 :            :         struct pkgbin *pkgbin;
     535                 :            : 
     536         [ -  + ]:         74 :         if (filetriggers_edited >= 0)
     537                 :          0 :                 return;
     538                 :            : 
     539                 :         74 :         f = fopen(triggersfilefile, "r");
     540         [ +  - ]:         74 :         if (!f) {
     541         [ +  - ]:         74 :                 if (errno == ENOENT)
     542                 :         74 :                         goto ok;
     543                 :          0 :                 ohshite(_("unable to read file triggers file '%.250s'"),
     544                 :            :                         triggersfilefile);
     545                 :            :         }
     546                 :            : 
     547                 :          0 :         push_cleanup(cu_closestream, ~0, 1, f);
     548         [ #  # ]:          0 :         while (fgets_checked(linebuf, sizeof(linebuf), f, triggersfilefile) >= 0) {
     549                 :            :                 struct dpkg_error err;
     550                 :            :                 enum trig_options trig_opts;
     551                 :            : 
     552                 :          0 :                 space = strchr(linebuf, ' ');
     553   [ #  #  #  # ]:          0 :                 if (!space || linebuf[0] != '/')
     554                 :          0 :                         ohshit(_("syntax error in file triggers file '%.250s'"),
     555                 :            :                                triggersfilefile);
     556                 :          0 :                 *space++ = '\0';
     557                 :            : 
     558                 :          0 :                 trig_opts = trig_parse_trigger_options(space);
     559                 :            : 
     560                 :          0 :                 pkg = pkg_spec_parse_pkg(space, &err);
     561         [ #  # ]:          0 :                 if (pkg == NULL)
     562                 :          0 :                         ohshit(_("file triggers record mentions illegal "
     563                 :            :                                  "package name '%.250s' (for interest in file "
     564                 :            :                                  "'%.250s'): %.250s"), space, linebuf, err.str);
     565                 :          0 :                 pkgbin = &pkg->installed;
     566                 :            : 
     567                 :          0 :                 trk_file_interest_change(linebuf, pkg, pkgbin, +2, trig_opts);
     568                 :            :         }
     569                 :          0 :         pop_cleanup(ehflag_normaltidy);
     570                 :         74 : ok:
     571                 :         74 :         filetriggers_edited = 0;
     572                 :            : }
     573                 :            : 
     574                 :            : void
     575                 :          0 : trig_file_activate_byname(const char *trig, struct pkginfo *aw)
     576                 :            : {
     577                 :          0 :         struct fsys_namenode *fnn = trigh.namenode_find(trig, 1);
     578                 :            : 
     579         [ #  # ]:          0 :         if (fnn)
     580                 :          0 :                 trig_file_activate(fnn, aw);
     581                 :          0 : }
     582                 :            : 
     583                 :            : void
     584                 :          0 : trig_file_activate(struct fsys_namenode *trig, struct pkginfo *aw)
     585                 :            : {
     586                 :            :         struct trigfileint *tfi;
     587                 :            : 
     588         [ #  # ]:          0 :         for (tfi = *trigh.namenode_interested(trig); tfi;
     589                 :          0 :              tfi = tfi->samefile_next)
     590         [ #  # ]:          0 :                 trig_record_activation(tfi->pkg, (tfi->options == TRIG_NOAWAIT) ?
     591                 :          0 :                                        NULL : aw, trigh.namenode_name(trig));
     592                 :          0 : }
     593                 :            : 
     594                 :            : static void
     595                 :          0 : trig_file_activate_parents(const char *trig, struct pkginfo *aw)
     596                 :            : {
     597                 :            :         char *path, *slash;
     598                 :            : 
     599                 :            :         /* Traverse the whole pathname to activate all of its components. */
     600                 :          0 :         path = m_strdup(trig);
     601                 :            : 
     602         [ #  # ]:          0 :         while ((slash = strrchr(path, '/'))) {
     603                 :          0 :                 *slash = '\0';
     604                 :          0 :                 trig_file_activate_byname(path, aw);
     605                 :            :         }
     606                 :            : 
     607                 :          0 :         free(path);
     608                 :          0 : }
     609                 :            : 
     610                 :            : void
     611                 :          0 : trig_path_activate(struct fsys_namenode *trig, struct pkginfo *aw)
     612                 :            : {
     613                 :          0 :         trig_file_activate(trig, aw);
     614                 :          0 :         trig_file_activate_parents(trigh.namenode_name(trig), aw);
     615                 :          0 : }
     616                 :            : 
     617                 :            : static void
     618                 :          0 : trig_path_activate_byname(const char *trig, struct pkginfo *aw)
     619                 :            : {
     620                 :          0 :         struct fsys_namenode *fnn = trigh.namenode_find(trig, 1);
     621                 :            : 
     622         [ #  # ]:          0 :         if (fnn)
     623                 :          0 :                 trig_file_activate(fnn, aw);
     624                 :            : 
     625                 :          0 :         trig_file_activate_parents(trig, aw);
     626                 :          0 : }
     627                 :            : 
     628                 :            : static const char *trk_file_trig;
     629                 :            : 
     630                 :            : static void
     631                 :          0 : trk_file_activate_start(void)
     632                 :            : {
     633                 :          0 :         trk_file_trig = trig_activating_name;
     634                 :          0 : }
     635                 :            : 
     636                 :            : static void
     637                 :          0 : trk_file_activate_awaiter(struct pkginfo *aw)
     638                 :            : {
     639                 :          0 :         trig_path_activate_byname(trk_file_trig, aw);
     640                 :          0 : }
     641                 :            : 
     642                 :            : static void
     643                 :          0 : trk_file_activate_done(void)
     644                 :            : {
     645                 :          0 : }
     646                 :            : 
     647                 :            : static const struct trigkindinfo tki_file = {
     648                 :            :         .activate_start = trk_file_activate_start,
     649                 :            :         .activate_awaiter = trk_file_activate_awaiter,
     650                 :            :         .activate_done = trk_file_activate_done,
     651                 :            :         .interest_change = trk_file_interest_change,
     652                 :            : };
     653                 :            : 
     654                 :            : /*---------- Trigger control info file. ----------*/
     655                 :            : 
     656                 :            : static void
     657                 :          0 : trig_cicb_interest_change(const char *trig, struct pkginfo *pkg,
     658                 :            :                           struct pkgbin *pkgbin, int signum,
     659                 :            :                           enum trig_options opts)
     660                 :            : {
     661                 :          0 :         const struct trigkindinfo *tki = trig_classify_byname(trig);
     662                 :            : 
     663         [ #  # ]:          0 :         if (filetriggers_edited < 0)
     664                 :          0 :                 internerr("trigger control file for package %s not read",
     665                 :            :                           pkgbin_name(pkg, pkgbin, pnaw_always));
     666                 :            : 
     667                 :          0 :         tki->interest_change(trig, pkg, pkgbin, signum, opts);
     668                 :          0 : }
     669                 :            : 
     670                 :            : void
     671                 :          0 : trig_cicb_interest_delete(const char *trig, struct pkginfo *pkg,
     672                 :            :                           struct pkgbin *pkgbin, enum trig_options opts)
     673                 :            : {
     674                 :          0 :         trig_cicb_interest_change(trig, pkg, pkgbin, -1, opts);
     675                 :          0 : }
     676                 :            : 
     677                 :            : void
     678                 :          0 : trig_cicb_interest_add(const char *trig, struct pkginfo *pkg,
     679                 :            :                        struct pkgbin *pkgbin, enum trig_options opts)
     680                 :            : {
     681                 :          0 :         trig_cicb_interest_change(trig, pkg, pkgbin, +1, opts);
     682                 :          0 : }
     683                 :            : 
     684                 :            : void
     685                 :          0 : trig_cicb_statuschange_activate(const char *trig, struct pkginfo *pkg,
     686                 :            :                                 struct pkgbin *pkgbin, enum trig_options opts)
     687                 :            : {
     688                 :          0 :         struct pkginfo *aw = pkg;
     689                 :            : 
     690                 :          0 :         trig_activate_start(trig);
     691         [ #  # ]:          0 :         dtki->activate_awaiter((opts == TRIG_NOAWAIT) ? NULL : aw);
     692                 :          0 :         dtki->activate_done();
     693                 :          0 : }
     694                 :            : 
     695                 :            : static void
     696                 :          0 : parse_ci_call(const char *file, const char *cmd, trig_parse_cicb *cb,
     697                 :            :               const char *trig, struct pkginfo *pkg, struct pkgbin *pkgbin,
     698                 :            :               enum trig_options opts)
     699                 :            : {
     700                 :            :         const char *emsg;
     701                 :            : 
     702                 :          0 :         emsg = trig_name_is_illegal(trig);
     703         [ #  # ]:          0 :         if (emsg)
     704                 :          0 :                 ohshit(_("triggers ci file '%.250s' contains illegal trigger "
     705                 :            :                          "syntax in trigger name '%.250s': %.250s"),
     706                 :            :                        file, trig, emsg);
     707         [ #  # ]:          0 :         if (cb)
     708                 :          0 :                 cb(trig, pkg, pkgbin, opts);
     709                 :          0 : }
     710                 :            : 
     711                 :            : void
     712                 :          0 : trig_parse_ci(const char *file, trig_parse_cicb *interest,
     713                 :            :               trig_parse_cicb *activate, struct pkginfo *pkg,
     714                 :            :               struct pkgbin *pkgbin)
     715                 :            : {
     716                 :            :         FILE *f;
     717                 :            :         char linebuf[MAXTRIGDIRECTIVE], *cmd, *spc, *eol;
     718                 :            :         int l;
     719                 :            : 
     720                 :          0 :         f = fopen(file, "r");
     721         [ #  # ]:          0 :         if (!f) {
     722         [ #  # ]:          0 :                 if (errno == ENOENT)
     723                 :          0 :                         return; /* No file is just like an empty one. */
     724                 :          0 :                 ohshite(_("unable to open triggers ci file '%.250s'"), file);
     725                 :            :         }
     726                 :          0 :         push_cleanup(cu_closestream, ~0, 1, f);
     727                 :            : 
     728         [ #  # ]:          0 :         while ((l = fgets_checked(linebuf, sizeof(linebuf), f, file)) >= 0) {
     729         [ #  # ]:          0 :                 for (cmd = linebuf; c_iswhite(*cmd); cmd++) ;
     730         [ #  # ]:          0 :                 if (*cmd == '#')
     731                 :          0 :                         continue;
     732   [ #  #  #  # ]:          0 :                 for (eol = linebuf + l; eol > cmd && c_iswhite(eol[-1]); eol--) ;
     733         [ #  # ]:          0 :                 if (eol == cmd)
     734                 :          0 :                         continue;
     735                 :          0 :                 *eol = '\0';
     736                 :            : 
     737   [ #  #  #  # ]:          0 :                 for (spc = cmd; *spc && !c_iswhite(*spc); spc++) ;
     738         [ #  # ]:          0 :                 if (!*spc)
     739                 :          0 :                         ohshit(_("triggers ci file contains unknown directive syntax"));
     740                 :          0 :                 *spc++ = '\0';
     741         [ #  # ]:          0 :                 while (c_iswhite(*spc))
     742                 :          0 :                         spc++;
     743         [ #  # ]:          0 :                 if (strcmp(cmd, "interest") == 0 ||
     744         [ #  # ]:          0 :                     strcmp(cmd, "interest-await") == 0) {
     745                 :          0 :                         parse_ci_call(file, cmd, interest, spc, pkg, pkgbin, TRIG_AWAIT);
     746         [ #  # ]:          0 :                 } else if (strcmp(cmd, "interest-noawait") == 0) {
     747                 :          0 :                         parse_ci_call(file, cmd, interest, spc, pkg, pkgbin, TRIG_NOAWAIT);
     748         [ #  # ]:          0 :                 } else if (strcmp(cmd, "activate") == 0 ||
     749         [ #  # ]:          0 :                            strcmp(cmd, "activate-await") == 0) {
     750                 :          0 :                         parse_ci_call(file, cmd, activate, spc, pkg, pkgbin, TRIG_AWAIT);
     751         [ #  # ]:          0 :                 } else if (strcmp(cmd, "activate-noawait") == 0) {
     752                 :          0 :                         parse_ci_call(file, cmd, activate, spc, pkg, pkgbin, TRIG_NOAWAIT);
     753                 :            :                 } else {
     754                 :          0 :                         ohshit(_("triggers ci file contains unknown directive '%.250s'"),
     755                 :            :                                cmd);
     756                 :            :                 }
     757                 :            :         }
     758                 :          0 :         pop_cleanup(ehflag_normaltidy); /* fclose() */
     759                 :            : }
     760                 :            : 
     761                 :            : /*---------- Unincorp file incorporation. ----------*/
     762                 :            : 
     763                 :            : static void
     764                 :          0 : tdm_incorp_trig_begin(const char *trig)
     765                 :            : {
     766                 :          0 :         trig_activate_start(trig);
     767                 :          0 : }
     768                 :            : 
     769                 :            : static void
     770                 :          0 : tdm_incorp_package(const char *awname)
     771                 :            : {
     772                 :            :         struct pkginfo *aw;
     773                 :            : 
     774         [ #  # ]:          0 :         if (strcmp(awname, "-") == 0)
     775                 :          0 :                 aw = NULL;
     776                 :            :         else
     777                 :          0 :                 aw = pkg_spec_parse_pkg(awname, NULL);
     778                 :            : 
     779                 :          0 :         dtki->activate_awaiter(aw);
     780                 :          0 : }
     781                 :            : 
     782                 :            : static void
     783                 :          0 : tdm_incorp_trig_end(void)
     784                 :            : {
     785                 :          0 :         dtki->activate_done();
     786                 :          0 : }
     787                 :            : 
     788                 :            : static const struct trigdefmeths tdm_incorp = {
     789                 :            :         .trig_begin = tdm_incorp_trig_begin,
     790                 :            :         .package = tdm_incorp_package,
     791                 :            :         .trig_end = tdm_incorp_trig_end
     792                 :            : };
     793                 :            : 
     794                 :            : void
     795                 :         74 : trig_incorporate(enum modstatdb_rw cstatus)
     796                 :            : {
     797                 :            :         enum trigdef_update_status ur;
     798                 :            :         enum trigdef_update_flags tduf;
     799                 :            : 
     800                 :         74 :         free(triggersdir);
     801                 :         74 :         triggersdir = dpkg_db_get_path(TRIGGERSDIR);
     802                 :            : 
     803                 :         74 :         free(triggersfilefile);
     804                 :         74 :         triggersfilefile = trig_get_filename(triggersdir, TRIGGERSFILEFILE);
     805                 :            : 
     806                 :         74 :         trigdef_set_methods(&tdm_incorp);
     807                 :         74 :         trig_file_interests_ensure();
     808                 :            : 
     809                 :         74 :         tduf = TDUF_NO_LOCK_OK;
     810         [ -  + ]:         74 :         if (cstatus >= msdbrw_write) {
     811                 :          0 :                 tduf |= TDUF_WRITE;
     812         [ #  # ]:          0 :                 if (trigh.transitional_activate)
     813                 :          0 :                         tduf |= TDUF_WRITE_IF_ENOENT;
     814                 :            :         }
     815                 :            : 
     816                 :         74 :         ur = trigdef_update_start(tduf);
     817   [ -  +  -  - ]:         74 :         if (ur == TDUS_ERROR_NO_DIR && cstatus >= msdbrw_write) {
     818         [ #  # ]:          0 :                 if (mkdir(triggersdir, 0755)) {
     819         [ #  # ]:          0 :                         if (errno != EEXIST)
     820                 :          0 :                                 ohshite(_("unable to create triggers state"
     821                 :            :                                           " directory '%.250s'"), triggersdir);
     822                 :            :                 }
     823                 :          0 :                 ur = trigdef_update_start(tduf);
     824                 :            :         }
     825   [ -  +  -  -  :         74 :         switch (ur) {
                      - ]
     826                 :          0 :         case TDUS_ERROR_EMPTY_DEFERRED:
     827                 :          0 :                 return;
     828                 :         74 :         case TDUS_ERROR_NO_DIR:
     829                 :            :         case TDUS_ERROR_NO_DEFERRED:
     830         [ +  - ]:         74 :                 if (!trigh.transitional_activate)
     831                 :         74 :                         return;
     832                 :            :         /* Fall through. */
     833                 :            :         case TDUS_NO_DEFERRED:
     834                 :          0 :                 trigh.transitional_activate(cstatus);
     835                 :          0 :                 break;
     836                 :          0 :         case TDUS_OK:
     837                 :            :                 /* Read and incorporate triggers. */
     838                 :          0 :                 trigdef_parse();
     839                 :          0 :                 break;
     840                 :          0 :         default:
     841                 :          0 :                 internerr("unknown trigdef_update_start return value '%d'", ur);
     842                 :            :         }
     843                 :            : 
     844                 :            :         /* Right, that's it. New (empty) Unincorp can be installed. */
     845                 :          0 :         trigdef_process_done();
     846                 :            : }
     847                 :            : 
     848                 :            : /*---------- Default hooks. ----------*/
     849                 :            : 
     850         [ #  # ]:          0 : TRIGHOOKS_DEFINE_NAMENODE_ACCESSORS
     851                 :            : 
     852                 :            : static struct trig_hooks trigh = {
     853                 :            :         .enqueue_deferred = NULL,
     854                 :            :         .transitional_activate = NULL,
     855                 :            :         .namenode_find = th_nn_find,
     856                 :            :         .namenode_interested = th_nn_interested,
     857                 :            :         .namenode_name = th_nn_name,
     858                 :            : };
     859                 :            : 
     860                 :            : void
     861                 :          0 : trig_override_hooks(const struct trig_hooks *hooks)
     862                 :            : {
     863                 :          0 :         trigh = *hooks;
     864                 :          0 : }

Generated by: LCOV version 1.16