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