LCOV - code coverage report
Current view: top level - lib/dpkg - trigdeferred.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 98 121 81.0 %
Date: 2022-12-03 00:40:01 Functions: 7 8 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 71 104 68.3 %

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

Generated by: LCOV version 1.16