2 * libdpkg - Debian packaging suite library routines
3 * triglib.c - trigger handling
5 * Copyright © 2007 Canonical Ltd
6 * Written by Ian Jackson <ijackson@chiark.greenend.org.uk>
7 * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
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.
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.
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/>.
26 #include <sys/types.h>
33 #include <dpkg/i18n.h>
34 #include <dpkg/c-ctype.h>
35 #include <dpkg/dpkg.h>
36 #include <dpkg/dpkg-db.h>
38 #include <dpkg/dlist.h>
40 #include <dpkg/pkg-spec.h>
41 #include <dpkg/trigdeferred.h>
42 #include <dpkg/triglib.h>
44 /*========== Recording triggers. ==========*/
46 static char *triggersdir
, *triggersfilefile
;
49 trig_get_filename(const char *dir
, const char *filename
)
51 return str_fmt("%s/%s", dir
, filename
);
54 static struct trig_hooks trigh
;
56 /*---------- Noting trigger activation in memory. ----------*/
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
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.
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.)
81 trig_record_activation(struct pkginfo
*pend
, struct pkginfo
*aw
, const char *trig
)
83 if (pend
->status
< PKG_STAT_TRIGGERSAWAITED
)
84 return; /* Not interested then. */
86 if (trig_note_pend(pend
, trig
))
87 modstatdb_note_ifwrite(pend
);
89 if (trigh
.enqueue_deferred
)
90 trigh
.enqueue_deferred(pend
);
92 if (aw
&& pend
->status
> PKG_STAT_CONFIGFILES
)
93 if (trig_note_aw(pend
, aw
)) {
94 if (aw
->status
> PKG_STAT_TRIGGERSAWAITED
)
95 pkg_set_status(aw
, PKG_STAT_TRIGGERSAWAITED
);
96 modstatdb_note_ifwrite(aw
);
101 trig_clear_awaiters(struct pkginfo
*notpend
)
106 if (notpend
->trigpend_head
)
107 internerr("package %s has pending triggers",
108 pkg_name(notpend
, pnaw_always
));
110 ta
= notpend
->othertrigaw_head
;
111 notpend
->othertrigaw_head
= NULL
;
112 for (; ta
; ta
= ta
->samepend_next
) {
116 LIST_UNLINK_PART(aw
->trigaw
, ta
, sameaw
);
117 if (!aw
->trigaw
.head
&& aw
->status
== PKG_STAT_TRIGGERSAWAITED
) {
118 if (aw
->trigpend_head
)
119 pkg_set_status(aw
, PKG_STAT_TRIGGERSPENDING
);
121 pkg_set_status(aw
, PKG_STAT_INSTALLED
);
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.
133 * XXX: Possibly get rid of some of the checks done somewhere else for
134 * this condition at run-time.
137 trig_fixup_awaiters(enum modstatdb_rw cstatus
)
139 if (cstatus
< msdbrw_write
)
142 trig_awaited_pend_foreach(trig_clear_awaiters
);
143 trig_awaited_pend_free();
146 /*---------- Generalized handling of trigger kinds. ----------*/
148 struct trigkindinfo
{
149 /* Only for trig_activate_start. */
150 void (*activate_start
)(void);
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
);
160 static const struct trigkindinfo tki_explicit
, tki_file
, tki_unknown
;
161 static const struct trigkindinfo
*dtki
;
163 /* As passed into activate_start. */
164 static char *trig_activating_name
;
166 static const struct trigkindinfo
*
167 trig_classify_byname(const char *name
)
169 if (name
[0] == '/') {
174 if (slash
[1] == '\0' || slash
[1] == '/')
177 slash
= strchr(slash
+ 2, '/');
182 if (!pkg_name_is_illegal(name
) && !strchr(name
, '_'))
183 return &tki_explicit
;
190 * Calling sequence is:
191 * trig_activate_start(triggername);
192 * dtki->activate_awaiter(awaiting_package); } zero or more times
193 * dtki->activate_awaiter(NULL); } in any order
194 * dtki->activate_done();
197 trig_activate_start(const char *name
)
199 dtki
= trig_classify_byname(name
);
200 trig_activating_name
= nfstrsave(name
);
201 dtki
->activate_start();
204 /*---------- Unknown trigger kinds. ----------*/
207 trk_unknown_activate_start(void)
212 trk_unknown_activate_awaiter(struct pkginfo
*aw
)
217 trk_unknown_activate_done(void)
221 static void DPKG_ATTR_NORET
222 trk_unknown_interest_change(const char *trig
, struct pkginfo
*pkg
,
223 struct pkgbin
*pkgbin
, int signum
,
224 enum trig_options opts
)
226 ohshit(_("invalid or unknown syntax in trigger name '%.250s'"
227 " (in trigger interests for package '%.250s')"),
228 trig
, pkgbin_name(pkg
, pkgbin
, pnaw_nonambig
));
231 static const struct trigkindinfo tki_unknown
= {
232 .activate_start
= trk_unknown_activate_start
,
233 .activate_awaiter
= trk_unknown_activate_awaiter
,
234 .activate_done
= trk_unknown_activate_done
,
235 .interest_change
= trk_unknown_interest_change
,
238 /*---------- Explicit triggers. ----------*/
240 static FILE *trk_explicit_f
;
241 static struct varbuf trk_explicit_fn
;
242 static char *trk_explicit_trig
;
245 trk_explicit_activate_done(void)
247 if (trk_explicit_f
) {
248 fclose(trk_explicit_f
);
249 trk_explicit_f
= NULL
;
254 trk_explicit_start(const char *trig
)
256 trk_explicit_activate_done();
258 varbuf_reset(&trk_explicit_fn
);
259 varbuf_add_str(&trk_explicit_fn
, triggersdir
);
260 varbuf_add_char(&trk_explicit_fn
, '/');
261 varbuf_add_str(&trk_explicit_fn
, trig
);
262 varbuf_end_str(&trk_explicit_fn
);
264 trk_explicit_f
= fopen(trk_explicit_fn
.buf
, "r");
265 if (!trk_explicit_f
) {
267 ohshite(_("failed to open trigger interest list file '%.250s'"),
268 trk_explicit_fn
.buf
);
273 trk_explicit_fgets(char *buf
, size_t sz
)
275 return fgets_checked(buf
, sz
, trk_explicit_f
, trk_explicit_fn
.buf
);
279 trk_explicit_activate_start(void)
281 trk_explicit_start(trig_activating_name
);
282 trk_explicit_trig
= trig_activating_name
;
286 trk_explicit_activate_awaiter(struct pkginfo
*aw
)
289 struct pkginfo
*pend
;
294 if (fseek(trk_explicit_f
, 0, SEEK_SET
))
295 ohshite(_("failed to rewind trigger interest file '%.250s'"),
296 trk_explicit_fn
.buf
);
298 while (trk_explicit_fgets(buf
, sizeof(buf
)) >= 0) {
299 struct dpkg_error err
;
301 bool noawait
= false;
302 slash
= strchr(buf
, '/');
303 if (slash
&& strcmp("/noawait", slash
) == 0) {
307 if (slash
&& strcmp("/await", slash
) == 0) {
312 pend
= pkg_spec_parse_pkg(buf
, &err
);
314 ohshit(_("trigger interest file '%.250s' syntax error; "
315 "illegal package name '%.250s': %.250s"),
316 trk_explicit_fn
.buf
, buf
, err
.str
);
318 trig_record_activation(pend
, noawait
? NULL
: aw
,
324 trk_explicit_interest_change(const char *trig
, struct pkginfo
*pkg
,
325 struct pkgbin
*pkgbin
, int signum
,
326 enum trig_options opts
)
329 struct atomic_file
*file
;
332 trk_explicit_start(trig
);
333 file
= atomic_file_new(trk_explicit_fn
.buf
, 0);
334 atomic_file_open(file
);
336 while (trk_explicit_f
&& trk_explicit_fgets(buf
, sizeof(buf
)) >= 0) {
337 const char *pkgname
= pkgbin_name(pkg
, pkgbin
, pnaw_nonambig
);
338 size_t len
= strlen(pkgname
);
340 if (strncmp(buf
, pkgname
, len
) == 0 && len
< sizeof(buf
) &&
341 (buf
[len
] == '\0' || buf
[len
] == '/'))
343 fprintf(file
->fp
, "%s\n", buf
);
347 fprintf(file
->fp
, "%s%s\n",
348 pkgbin_name(pkg
, pkgbin
, pnaw_nonambig
),
349 (opts
== TRIG_NOAWAIT
) ? "/noawait" : "");
354 atomic_file_sync(file
);
356 atomic_file_close(file
);
359 atomic_file_remove(file
);
361 atomic_file_commit(file
);
363 atomic_file_free(file
);
365 dir_sync_path(triggersdir
);
368 static const struct trigkindinfo tki_explicit
= {
369 .activate_start
= trk_explicit_activate_start
,
370 .activate_awaiter
= trk_explicit_activate_awaiter
,
371 .activate_done
= trk_explicit_activate_done
,
372 .interest_change
= trk_explicit_interest_change
,
375 /*---------- File triggers. ----------*/
378 struct trigfileint
*head
, *tail
;
387 static int filetriggers_edited
= -1;
390 * Called by various people with signum -1 and +1 to mean remove and add
391 * and also by trig_file_interests_ensure() with signum +2 meaning add
392 * but die if already present.
395 trk_file_interest_change(const char *trig
, struct pkginfo
*pkg
,
396 struct pkgbin
*pkgbin
, int signum
,
397 enum trig_options opts
)
399 struct fsys_namenode
*fnn
;
400 struct trigfileint
**search
, *tfi
;
402 fnn
= trigh
.namenode_find(trig
, signum
<= 0);
405 internerr("lost filename node '%s' for package %s "
406 "triggered to add", trig
,
407 pkgbin_name(pkg
, pkgbin
, pnaw_always
));
411 for (search
= trigh
.namenode_interested(fnn
);
413 search
= &tfi
->samefile_next
)
421 tfi
= nfmalloc(sizeof(*tfi
));
423 tfi
->pkgbin
= pkgbin
;
426 tfi
->samefile_next
= *trigh
.namenode_interested(fnn
);
427 *trigh
.namenode_interested(fnn
) = tfi
;
429 LIST_LINK_TAIL_PART(filetriggers
, tfi
, inoverall
);
435 ohshit(_("duplicate file trigger interest for filename '%.250s' "
436 "and package '%.250s'"), trig
,
437 pkgbin_name(pkg
, pkgbin
, pnaw_nonambig
));
442 *search
= tfi
->samefile_next
;
443 LIST_UNLINK_PART(filetriggers
, tfi
, inoverall
);
445 filetriggers_edited
= 1;
449 trig_file_interests_remove(void)
451 if (unlink(triggersfilefile
) && errno
!= ENOENT
)
452 ohshite(_("cannot remove '%.250s'"), triggersfilefile
);
456 trig_file_interests_update(void)
458 struct trigfileint
*tfi
;
459 struct atomic_file
*file
;
461 file
= atomic_file_new(triggersfilefile
, 0);
462 atomic_file_open(file
);
464 for (tfi
= filetriggers
.head
; tfi
; tfi
= tfi
->inoverall
.next
)
465 fprintf(file
->fp
, "%s %s%s\n", trigh
.namenode_name(tfi
->fnn
),
466 pkgbin_name(tfi
->pkg
, tfi
->pkgbin
, pnaw_nonambig
),
467 (tfi
->options
== TRIG_NOAWAIT
) ? "/noawait" : "");
469 atomic_file_sync(file
);
470 atomic_file_close(file
);
471 atomic_file_commit(file
);
472 atomic_file_free(file
);
476 trig_file_interests_save(void)
478 if (filetriggers_edited
<= 0)
481 if (!filetriggers
.head
)
482 trig_file_interests_remove();
484 trig_file_interests_update();
486 dir_sync_path(triggersdir
);
488 filetriggers_edited
= 0;
492 trig_file_interests_ensure(void)
495 char linebuf
[1024], *space
;
497 struct pkgbin
*pkgbin
;
499 if (filetriggers_edited
>= 0)
502 f
= fopen(triggersfilefile
, "r");
506 ohshite(_("unable to read file triggers file '%.250s'"),
510 push_cleanup(cu_closestream
, ~0, 1, f
);
511 while (fgets_checked(linebuf
, sizeof(linebuf
), f
, triggersfilefile
) >= 0) {
512 struct dpkg_error err
;
514 enum trig_options trig_opts
= TRIG_AWAIT
;
515 space
= strchr(linebuf
, ' ');
516 if (!space
|| linebuf
[0] != '/')
517 ohshit(_("syntax error in file triggers file '%.250s'"),
521 slash
= strchr(space
, '/');
522 if (slash
&& strcmp("/noawait", slash
) == 0) {
523 trig_opts
= TRIG_NOAWAIT
;
526 if (slash
&& strcmp("/await", slash
) == 0) {
527 trig_opts
= TRIG_AWAIT
;
531 pkg
= pkg_spec_parse_pkg(space
, &err
);
533 ohshit(_("file triggers record mentions illegal "
534 "package name '%.250s' (for interest in file "
535 "'%.250s'): %.250s"), space
, linebuf
, err
.str
);
536 pkgbin
= &pkg
->installed
;
538 trk_file_interest_change(linebuf
, pkg
, pkgbin
, +2, trig_opts
);
540 pop_cleanup(ehflag_normaltidy
);
542 filetriggers_edited
= 0;
546 trig_file_activate_byname(const char *trig
, struct pkginfo
*aw
)
548 struct fsys_namenode
*fnn
= trigh
.namenode_find(trig
, 1);
551 trig_file_activate(fnn
, aw
);
555 trig_file_activate(struct fsys_namenode
*trig
, struct pkginfo
*aw
)
557 struct trigfileint
*tfi
;
559 for (tfi
= *trigh
.namenode_interested(trig
); tfi
;
560 tfi
= tfi
->samefile_next
)
561 trig_record_activation(tfi
->pkg
, (tfi
->options
== TRIG_NOAWAIT
) ?
562 NULL
: aw
, trigh
.namenode_name(trig
));
566 trig_file_activate_parents(const char *trig
, struct pkginfo
*aw
)
570 /* Traverse the whole pathname to activate all of its components. */
571 path
= m_strdup(trig
);
573 while ((slash
= strrchr(path
, '/'))) {
575 trig_file_activate_byname(path
, aw
);
582 trig_path_activate(struct fsys_namenode
*trig
, struct pkginfo
*aw
)
584 trig_file_activate(trig
, aw
);
585 trig_file_activate_parents(trigh
.namenode_name(trig
), aw
);
589 trig_path_activate_byname(const char *trig
, struct pkginfo
*aw
)
591 struct fsys_namenode
*fnn
= trigh
.namenode_find(trig
, 1);
594 trig_file_activate(fnn
, aw
);
596 trig_file_activate_parents(trig
, aw
);
599 static const char *trk_file_trig
;
602 trk_file_activate_start(void)
604 trk_file_trig
= trig_activating_name
;
608 trk_file_activate_awaiter(struct pkginfo
*aw
)
610 trig_path_activate_byname(trk_file_trig
, aw
);
614 trk_file_activate_done(void)
618 static const struct trigkindinfo tki_file
= {
619 .activate_start
= trk_file_activate_start
,
620 .activate_awaiter
= trk_file_activate_awaiter
,
621 .activate_done
= trk_file_activate_done
,
622 .interest_change
= trk_file_interest_change
,
625 /*---------- Trigger control info file. ----------*/
628 trig_cicb_interest_change(const char *trig
, struct pkginfo
*pkg
,
629 struct pkgbin
*pkgbin
, int signum
,
630 enum trig_options opts
)
632 const struct trigkindinfo
*tki
= trig_classify_byname(trig
);
634 if (filetriggers_edited
< 0)
635 internerr("trigger control file for package %s not read",
636 pkgbin_name(pkg
, pkgbin
, pnaw_always
));
638 tki
->interest_change(trig
, pkg
, pkgbin
, signum
, opts
);
642 trig_cicb_interest_delete(const char *trig
, struct pkginfo
*pkg
,
643 struct pkgbin
*pkgbin
, enum trig_options opts
)
645 trig_cicb_interest_change(trig
, pkg
, pkgbin
, -1, opts
);
649 trig_cicb_interest_add(const char *trig
, struct pkginfo
*pkg
,
650 struct pkgbin
*pkgbin
, enum trig_options opts
)
652 trig_cicb_interest_change(trig
, pkg
, pkgbin
, +1, opts
);
656 trig_cicb_statuschange_activate(const char *trig
, struct pkginfo
*pkg
,
657 struct pkgbin
*pkgbin
, enum trig_options opts
)
659 struct pkginfo
*aw
= pkg
;
661 trig_activate_start(trig
);
662 dtki
->activate_awaiter((opts
== TRIG_NOAWAIT
) ? NULL
: aw
);
663 dtki
->activate_done();
667 parse_ci_call(const char *file
, const char *cmd
, trig_parse_cicb
*cb
,
668 const char *trig
, struct pkginfo
*pkg
, struct pkgbin
*pkgbin
,
669 enum trig_options opts
)
673 emsg
= trig_name_is_illegal(trig
);
675 ohshit(_("triggers ci file '%.250s' contains illegal trigger "
676 "syntax in trigger name '%.250s': %.250s"),
679 cb(trig
, pkg
, pkgbin
, opts
);
683 trig_parse_ci(const char *file
, trig_parse_cicb
*interest
,
684 trig_parse_cicb
*activate
, struct pkginfo
*pkg
,
685 struct pkgbin
*pkgbin
)
688 char linebuf
[MAXTRIGDIRECTIVE
], *cmd
, *spc
, *eol
;
691 f
= fopen(file
, "r");
694 return; /* No file is just like an empty one. */
695 ohshite(_("unable to open triggers ci file '%.250s'"), file
);
697 push_cleanup(cu_closestream
, ~0, 1, f
);
699 while ((l
= fgets_checked(linebuf
, sizeof(linebuf
), f
, file
)) >= 0) {
700 for (cmd
= linebuf
; c_iswhite(*cmd
); cmd
++) ;
703 for (eol
= linebuf
+ l
; eol
> cmd
&& c_iswhite(eol
[-1]); eol
--) ;
708 for (spc
= cmd
; *spc
&& !c_iswhite(*spc
); spc
++) ;
710 ohshit(_("triggers ci file contains unknown directive syntax"));
712 while (c_iswhite(*spc
))
714 if (strcmp(cmd
, "interest") == 0 ||
715 strcmp(cmd
, "interest-await") == 0) {
716 parse_ci_call(file
, cmd
, interest
, spc
, pkg
, pkgbin
, TRIG_AWAIT
);
717 } else if (strcmp(cmd
, "interest-noawait") == 0) {
718 parse_ci_call(file
, cmd
, interest
, spc
, pkg
, pkgbin
, TRIG_NOAWAIT
);
719 } else if (strcmp(cmd
, "activate") == 0 ||
720 strcmp(cmd
, "activate-await") == 0) {
721 parse_ci_call(file
, cmd
, activate
, spc
, pkg
, pkgbin
, TRIG_AWAIT
);
722 } else if (strcmp(cmd
, "activate-noawait") == 0) {
723 parse_ci_call(file
, cmd
, activate
, spc
, pkg
, pkgbin
, TRIG_NOAWAIT
);
725 ohshit(_("triggers ci file contains unknown directive '%.250s'"),
729 pop_cleanup(ehflag_normaltidy
); /* fclose() */
732 /*---------- Unincorp file incorporation. ----------*/
735 tdm_incorp_trig_begin(const char *trig
)
737 trig_activate_start(trig
);
741 tdm_incorp_package(const char *awname
)
745 if (strcmp(awname
, "-") == 0)
748 aw
= pkg_spec_parse_pkg(awname
, NULL
);
750 dtki
->activate_awaiter(aw
);
754 tdm_incorp_trig_end(void)
756 dtki
->activate_done();
759 static const struct trigdefmeths tdm_incorp
= {
760 .trig_begin
= tdm_incorp_trig_begin
,
761 .package
= tdm_incorp_package
,
762 .trig_end
= tdm_incorp_trig_end
766 trig_incorporate(enum modstatdb_rw cstatus
)
768 enum trigdef_update_status ur
;
769 enum trigdef_update_flags tduf
;
772 triggersdir
= dpkg_db_get_path(TRIGGERSDIR
);
774 free(triggersfilefile
);
775 triggersfilefile
= trig_get_filename(triggersdir
, TRIGGERSFILEFILE
);
777 trigdef_set_methods(&tdm_incorp
);
778 trig_file_interests_ensure();
780 tduf
= TDUF_NO_LOCK_OK
;
781 if (cstatus
>= msdbrw_write
) {
783 if (trigh
.transitional_activate
)
784 tduf
|= TDUF_WRITE_IF_ENOENT
;
787 ur
= trigdef_update_start(tduf
);
788 if (ur
== TDUS_ERROR_NO_DIR
&& cstatus
>= msdbrw_write
) {
789 if (mkdir(triggersdir
, 0755)) {
791 ohshite(_("unable to create triggers state"
792 " directory '%.250s'"), triggersdir
);
794 ur
= trigdef_update_start(tduf
);
797 case TDUS_ERROR_EMPTY_DEFERRED
:
799 case TDUS_ERROR_NO_DIR
:
800 case TDUS_ERROR_NO_DEFERRED
:
801 if (!trigh
.transitional_activate
)
804 case TDUS_NO_DEFERRED
:
805 trigh
.transitional_activate(cstatus
);
808 /* Read and incorporate triggers. */
812 internerr("unknown trigdef_update_start return value '%d'", ur
);
815 /* Right, that's it. New (empty) Unincorp can be installed. */
816 trigdef_process_done();
819 /*---------- Default hooks. ----------*/
821 TRIGHOOKS_DEFINE_NAMENODE_ACCESSORS
823 static struct trig_hooks trigh
= {
824 .enqueue_deferred
= NULL
,
825 .transitional_activate
= NULL
,
826 .namenode_find
= th_nn_find
,
827 .namenode_interested
= th_nn_interested
,
828 .namenode_name
= th_nn_name
,
832 trig_override_hooks(const struct trig_hooks
*hooks
)