LCOV - code coverage report
Current view: top level - lib/dpkg - trigdeferred.c (source / functions) Coverage Total Hit
Test: dpkg 1.22.7-3-g89f48 C code coverage Lines: 80.8 % 120 97
Test Date: 2024-07-17 02:53:43 Functions: 87.5 % 8 7
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 68.3 % 104 71

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * libdpkg - Debian packaging suite library routines
       3                 :             :  * trigdeferred.c - parsing of triggers/Unincorp (was …/Deferred)
       4                 :             :  *
       5                 :             :  * Copyright © 2007 Canonical Ltd
       6                 :             :  * written by Ian Jackson <ijackson@chiark.greenend.org.uk>
       7                 :             :  * Copyright © 2008-2016 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/stat.h>
      27                 :             : 
      28                 :             : #include <errno.h>
      29                 :             : #include <fcntl.h>
      30                 :             : #include <limits.h>
      31                 :             : #include <stdlib.h>
      32                 :             : 
      33                 :             : #include <dpkg/i18n.h>
      34                 :             : #include <dpkg/dpkg.h>
      35                 :             : #include <dpkg/dpkg-db.h>
      36                 :             : #include <dpkg/c-ctype.h>
      37                 :             : #include <dpkg/file.h>
      38                 :             : #include <dpkg/dir.h>
      39                 :             : #include <dpkg/trigdeferred.h>
      40                 :             : #include <dpkg/triglib.h>
      41                 :             : 
      42                 :             : static struct varbuf fn, newfn;
      43                 :             : 
      44                 :             : static const struct trigdefmeths *trigdef;
      45                 :             : 
      46                 :             : /*---------- Deferred file handling ----------*/
      47                 :             : 
      48                 :             : static char *triggersdir;
      49                 :             : static int lock_fd = -1;
      50                 :             : static FILE *old_deferred;
      51                 :             : static FILE *trig_new_deferred;
      52                 :             : 
      53                 :             : static void
      54                 :          95 : constructfn(struct varbuf *vb, const char *dir, const char *tail)
      55                 :             : {
      56                 :          95 :         varbuf_reset(vb);
      57                 :          95 :         varbuf_add_dir(vb, dir);
      58                 :          95 :         varbuf_add_str(vb, tail);
      59                 :          95 : }
      60                 :             : 
      61                 :             : /**
      62                 :             :  * Start processing of the triggers deferred file.
      63                 :             :  *
      64                 :             :  * @retval -1 Lock ENOENT with O_CREAT (directory does not exist).
      65                 :             :  * @retval -2 Unincorp empty, TDUF_WRITE_IF_EMPTY unset.
      66                 :             :  * @retval -3 Unincorp ENOENT, TDUF_WRITE_IF_ENOENT unset.
      67                 :             :  * @retval  1 Unincorp ENOENT, TDUF_WRITE_IF_ENOENT set.
      68                 :             :  * @retval  2 Ok.
      69                 :             :  *
      70                 :             :  * For positive return values the caller must call trigdef_update_done!
      71                 :             :  */
      72                 :             : enum trigdef_update_status
      73                 :          81 : trigdef_update_start(enum trigdef_update_flags uf)
      74                 :             : {
      75                 :          81 :         free(triggersdir);
      76                 :          81 :         triggersdir = dpkg_db_get_path(TRIGGERSDIR);
      77                 :             : 
      78         [ +  + ]:          81 :         if (uf & TDUF_WRITE) {
      79                 :           7 :                 constructfn(&fn, triggersdir, TRIGGERSLOCKFILE);
      80         [ +  - ]:           7 :                 if (lock_fd < 0) {
      81                 :           7 :                         lock_fd = open(fn.buf, O_RDWR | O_CREAT | O_TRUNC, 0600);
      82         [ -  + ]:           7 :                         if (lock_fd < 0) {
      83   [ #  #  #  # ]:           0 :                                 if (!(errno == ENOENT && (uf & TDUF_NO_LOCK_OK)))
      84                 :           0 :                                         ohshite(_("unable to open/create "
      85                 :             :                                                   "triggers lock file '%.250s'"),
      86                 :             :                                                 fn.buf);
      87                 :           0 :                                 return TDUS_ERROR_NO_DIR;
      88                 :             :                         }
      89                 :             :                 }
      90                 :             : 
      91                 :           7 :                 file_lock(&lock_fd, FILE_LOCK_WAIT, fn.buf,
      92                 :           7 :                           _("triggers database lock"));
      93                 :             :         }
      94                 :             : 
      95                 :          81 :         constructfn(&fn, triggersdir, TRIGGERSDEFERREDFILE);
      96                 :             : 
      97         [ -  + ]:          81 :         if (old_deferred)
      98                 :           0 :                 fclose(old_deferred);
      99                 :          81 :         old_deferred = fopen(fn.buf, "r");
     100         [ +  + ]:          81 :         if (!old_deferred) {
     101         [ -  + ]:          74 :                 if (errno != ENOENT)
     102                 :           0 :                         ohshite(_("unable to open triggers deferred file '%.250s'"),
     103                 :             :                                 fn.buf);
     104         [ +  - ]:          74 :                 if (!(uf & TDUF_WRITE_IF_ENOENT)) {
     105         [ -  + ]:          74 :                         if (uf & TDUF_WRITE)
     106                 :           0 :                                 pop_cleanup(ehflag_normaltidy);
     107                 :          74 :                         return TDUS_ERROR_NO_DEFERRED;
     108                 :             :                 }
     109                 :             :         } else {
     110                 :             :                 struct stat stab;
     111                 :             :                 int rc;
     112                 :             : 
     113                 :           7 :                 setcloexec(fileno(old_deferred), fn.buf);
     114                 :             : 
     115                 :           7 :                 rc = fstat(fileno(old_deferred), &stab);
     116         [ -  + ]:           7 :                 if (rc < 0)
     117                 :           0 :                         ohshite(_("unable to stat triggers deferred file '%.250s'"),
     118                 :             :                                 fn.buf);
     119                 :             : 
     120   [ -  +  -  - ]:           7 :                 if (stab.st_size == 0 && !(uf & TDUF_WRITE_IF_EMPTY)) {
     121         [ #  # ]:           0 :                         if (uf & TDUF_WRITE)
     122                 :           0 :                                 pop_cleanup(ehflag_normaltidy);
     123                 :           0 :                         return TDUS_ERROR_EMPTY_DEFERRED;
     124                 :             :                 }
     125                 :             :         }
     126                 :             : 
     127         [ +  - ]:           7 :         if (uf & TDUF_WRITE) {
     128                 :           7 :                 constructfn(&newfn, triggersdir, TRIGGERSDEFERREDFILE ".new");
     129         [ -  + ]:           7 :                 if (trig_new_deferred)
     130                 :           0 :                         fclose(trig_new_deferred);
     131                 :           7 :                 trig_new_deferred = fopen(newfn.buf, "w");
     132         [ -  + ]:           7 :                 if (!trig_new_deferred)
     133                 :           0 :                         ohshite(_("unable to open/create new triggers deferred file '%.250s'"),
     134                 :             :                                 newfn.buf);
     135                 :             : 
     136                 :           7 :                 setcloexec(fileno(trig_new_deferred), newfn.buf);
     137                 :             :         }
     138                 :             : 
     139         [ -  + ]:           7 :         if (!old_deferred)
     140                 :           0 :                 return TDUS_NO_DEFERRED;
     141                 :             : 
     142                 :           7 :         return TDUS_OK;
     143                 :             : }
     144                 :             : 
     145                 :             : void
     146                 :          81 : trigdef_set_methods(const struct trigdefmeths *methods)
     147                 :             : {
     148                 :          81 :         trigdef = methods;
     149                 :          81 : }
     150                 :             : 
     151                 :             : void
     152                 :           0 : trigdef_update_printf(const char *format, ...)
     153                 :             : {
     154                 :             :         va_list ap;
     155                 :             : 
     156                 :           0 :         va_start(ap, format);
     157                 :           0 :         vfprintf(trig_new_deferred, format, ap);
     158                 :           0 :         va_end(ap);
     159                 :           0 : }
     160                 :             : 
     161                 :             : static void
     162                 :           4 : trigdef_parse_error(int line_num, const char *line, const char *ptr)
     163                 :             : {
     164                 :           4 :         ohshit(_("syntax error in triggers deferred file '%.250s' at "
     165                 :             :                  "line %d character %zd '%s'"),
     166                 :           4 :                fn.buf, line_num, ptr - line + 1, ptr);
     167                 :             : }
     168                 :             : 
     169                 :             : /* Trim leading space. */
     170                 :             : static char *
     171                 :          27 : trigdef_skip_whitespace(char *ptr)
     172                 :             : {
     173         [ +  + ]:          60 :         while (*ptr) {
     174         [ +  + ]:          59 :                 if (!c_iswhite(*ptr))
     175                 :          26 :                         break;
     176                 :          33 :                 ptr++;
     177                 :             :         }
     178                 :             : 
     179                 :          27 :         return ptr;
     180                 :             : }
     181                 :             : 
     182                 :             : int
     183                 :           7 : trigdef_parse(void)
     184                 :             : {
     185                 :             :         char line[_POSIX2_LINE_MAX];
     186                 :             :         char *ptr, *ptr_ini;
     187                 :           7 :         int line_num = 0;
     188                 :             : 
     189         [ +  + ]:          14 :         while (fgets_checked(line, sizeof(line), old_deferred, fn.buf) > 0) {
     190                 :          12 :                 line_num++;
     191                 :             : 
     192                 :          12 :                 ptr = trigdef_skip_whitespace(line);
     193                 :             : 
     194                 :             :                 /* Skip comments and empty lines. */
     195   [ +  +  +  + ]:          12 :                 if (*ptr == '\0' || *ptr == '#')
     196                 :           3 :                         continue;
     197                 :             : 
     198                 :             :                 /* Parse the trigger directive. */
     199                 :           9 :                 ptr_ini = ptr;
     200         [ +  - ]:         104 :                 while (*ptr) {
     201   [ +  +  +  - ]:         104 :                         if (*ptr < 0x21 || *ptr > 0x7e)
     202                 :             :                                 break;
     203                 :          95 :                         ptr++;
     204                 :             :                 }
     205                 :             : 
     206   [ +  -  +  + ]:           9 :                 if (*ptr == '\0' || ptr_ini == ptr)
     207                 :           1 :                         trigdef_parse_error(line_num, line, ptr);
     208                 :           8 :                 *ptr++ = '\0';
     209                 :             : 
     210                 :             :                 /* Set the trigger directive. */
     211                 :           8 :                 trigdef->trig_begin(ptr_ini);
     212                 :             : 
     213                 :             :                 /* Parse the package names. */
     214         [ +  + ]:          19 :                 while (*ptr) {
     215                 :          15 :                         ptr = trigdef_skip_whitespace(ptr);
     216                 :             : 
     217                 :          15 :                         ptr_ini = ptr;
     218         [ +  - ]:          15 :                         if (*ptr == '\0' ||
     219   [ +  +  +  +  :          15 :                             !(c_isdigit(*ptr) || c_islower(*ptr) || *ptr == '-'))
                   +  + ]
     220                 :           3 :                                 trigdef_parse_error(line_num, line, ptr);
     221                 :             : 
     222         [ +  + ]:          55 :                         while (*++ptr) {
     223   [ +  +  +  + ]:          50 :                                 if (!c_isdigit(*ptr) && !c_islower(*ptr) &&
     224   [ +  +  +  + ]:          17 :                                     *ptr != '-' && *ptr != ':' &&
     225   [ +  +  +  + ]:           9 :                                     *ptr != '+' && *ptr != '.')
     226                 :           7 :                                         break;
     227                 :             :                         }
     228                 :             : 
     229   [ +  +  +  -  :          12 :                         if (*ptr != '\0' && *ptr != '#' && !c_iswhite(*ptr))
                   -  + ]
     230                 :           0 :                                 trigdef_parse_error(line_num, line, ptr);
     231                 :          12 :                         *ptr++ = '\0';
     232                 :             : 
     233   [ +  +  +  + ]:          12 :                         if (ptr_ini[0] == '-' && ptr_ini[1])
     234                 :           1 :                                 ohshit(_("invalid package name '%.250s' in "
     235                 :             :                                          "triggers deferred file '%.250s'"),
     236                 :             :                                        ptr_ini, fn.buf);
     237                 :             : 
     238                 :             :                         /* Set the package name. */
     239                 :          11 :                         trigdef->package(ptr_ini);
     240                 :             :                 }
     241                 :             : 
     242                 :           4 :                 trigdef->trig_end();
     243                 :             :         }
     244                 :             : 
     245                 :           1 :         return 0;
     246                 :             : }
     247                 :             : 
     248                 :             : void
     249                 :           1 : trigdef_process_done(void)
     250                 :             : {
     251         [ +  - ]:           1 :         if (old_deferred) {
     252         [ -  + ]:           1 :                 if (ferror(old_deferred))
     253                 :           0 :                         ohshite(_("error reading triggers deferred file '%.250s'"),
     254                 :             :                                 fn.buf);
     255                 :           1 :                 fclose(old_deferred);
     256                 :           1 :                 old_deferred = NULL;
     257                 :             :         }
     258                 :             : 
     259         [ +  - ]:           1 :         if (trig_new_deferred) {
     260                 :             :                 int rc;
     261                 :             : 
     262         [ -  + ]:           1 :                 if (ferror(trig_new_deferred))
     263                 :           0 :                         ohshite(_("unable to write new triggers deferred "
     264                 :             :                                   "file '%.250s'"), newfn.buf);
     265                 :           1 :                 rc = fclose(trig_new_deferred);
     266                 :           1 :                 trig_new_deferred = NULL;
     267         [ -  + ]:           1 :                 if (rc)
     268                 :           0 :                         ohshite(_("unable to close new triggers deferred "
     269                 :             :                                   "file '%.250s'"), newfn.buf);
     270                 :             : 
     271         [ -  + ]:           1 :                 if (rename(newfn.buf, fn.buf))
     272                 :           0 :                         ohshite(_("unable to install new triggers deferred "
     273                 :             :                                   "file '%.250s'"), fn.buf);
     274                 :             : 
     275                 :           1 :                 dir_sync_path(triggersdir);
     276                 :             :         }
     277                 :             : 
     278                 :           1 :         free(triggersdir);
     279                 :           1 :         triggersdir = NULL;
     280                 :             : 
     281                 :             :         /* Unlock. */
     282         [ +  - ]:           1 :         if (lock_fd >= 0)
     283                 :           1 :                 pop_cleanup(ehflag_normaltidy);
     284                 :           1 : }
        

Generated by: LCOV version 2.0-1