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 *
trig_get_filename(const char * dir,const char * filename)49 trig_get_filename(const char *dir, const char *filename)
50 {
51 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
trig_record_activation(struct pkginfo * pend,struct pkginfo * aw,const char * trig)81 trig_record_activation(struct pkginfo *pend, struct pkginfo *aw, const char *trig)
82 {
83 if (pend->status < PKG_STAT_TRIGGERSAWAITED)
84 return; /* Not interested then. */
85
86 if (trig_note_pend(pend, trig))
87 modstatdb_note_ifwrite(pend);
88
89 if (trigh.enqueue_deferred)
90 trigh.enqueue_deferred(pend);
91
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);
97 }
98 }
99
100 void
trig_clear_awaiters(struct pkginfo * notpend)101 trig_clear_awaiters(struct pkginfo *notpend)
102 {
103 struct trigaw *ta;
104 struct pkginfo *aw;
105
106 if (notpend->trigpend_head)
107 internerr("package %s has pending triggers",
108 pkg_name(notpend, pnaw_always));
109
110 ta = notpend->othertrigaw_head;
111 notpend->othertrigaw_head = NULL;
112 for (; ta; ta = ta->samepend_next) {
113 aw = ta->aw;
114 if (!aw)
115 continue;
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);
120 else
121 pkg_set_status(aw, PKG_STAT_INSTALLED);
122 modstatdb_note(aw);
123 }
124 }
125 }
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
trig_fixup_awaiters(enum modstatdb_rw cstatus)137 trig_fixup_awaiters(enum modstatdb_rw cstatus)
138 {
139 if (cstatus < msdbrw_write)
140 return;
141
142 trig_awaited_pend_foreach(trig_clear_awaiters);
143 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 *
trig_classify_byname(const char * name)167 trig_classify_byname(const char *name)
168 {
169 if (name[0] == '/') {
170 const char *slash;
171
172 slash = name;
173 while (slash) {
174 if (slash[1] == '\0' || slash[1] == '/')
175 goto invalid;
176
177 slash = strchr(slash + 2, '/');
178 }
179 return &tki_file;
180 }
181
182 if (!pkg_name_is_illegal(name) && !strchr(name, '_'))
183 return &tki_explicit;
184
185 invalid:
186 return &tki_unknown;
187 }
188
189 /*
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();
195 */
196 static void
trig_activate_start(const char * name)197 trig_activate_start(const char *name)
198 {
199 dtki = trig_classify_byname(name);
200 trig_activating_name = nfstrsave(name);
201 dtki->activate_start();
202 }
203
204 /*---------- Unknown trigger kinds. ----------*/
205
206 static void
trk_unknown_activate_start(void)207 trk_unknown_activate_start(void)
208 {
209 }
210
211 static void
trk_unknown_activate_awaiter(struct pkginfo * aw)212 trk_unknown_activate_awaiter(struct pkginfo *aw)
213 {
214 }
215
216 static void
trk_unknown_activate_done(void)217 trk_unknown_activate_done(void)
218 {
219 }
220
221 static void DPKG_ATTR_NORET
trk_unknown_interest_change(const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,int signum,enum trig_options opts)222 trk_unknown_interest_change(const char *trig, struct pkginfo *pkg,
223 struct pkgbin *pkgbin, int signum,
224 enum trig_options opts)
225 {
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));
229 }
230
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,
236 };
237
238 /*---------- Explicit triggers. ----------*/
239
240 static FILE *trk_explicit_f;
241 static struct varbuf trk_explicit_fn;
242 static char *trk_explicit_trig;
243
244 static void
trk_explicit_activate_done(void)245 trk_explicit_activate_done(void)
246 {
247 if (trk_explicit_f) {
248 fclose(trk_explicit_f);
249 trk_explicit_f = NULL;
250 }
251 }
252
253 static void
trk_explicit_start(const char * trig)254 trk_explicit_start(const char *trig)
255 {
256 trk_explicit_activate_done();
257
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);
263
264 trk_explicit_f = fopen(trk_explicit_fn.buf, "r");
265 if (!trk_explicit_f) {
266 if (errno != ENOENT)
267 ohshite(_("failed to open trigger interest list file '%.250s'"),
268 trk_explicit_fn.buf);
269 }
270 }
271
272 static int
trk_explicit_fgets(char * buf,size_t sz)273 trk_explicit_fgets(char *buf, size_t sz)
274 {
275 return fgets_checked(buf, sz, trk_explicit_f, trk_explicit_fn.buf);
276 }
277
278 static void
trk_explicit_activate_start(void)279 trk_explicit_activate_start(void)
280 {
281 trk_explicit_start(trig_activating_name);
282 trk_explicit_trig = trig_activating_name;
283 }
284
285 static void
trk_explicit_activate_awaiter(struct pkginfo * aw)286 trk_explicit_activate_awaiter(struct pkginfo *aw)
287 {
288 char buf[1024];
289 struct pkginfo *pend;
290
291 if (!trk_explicit_f)
292 return;
293
294 if (fseek(trk_explicit_f, 0, SEEK_SET))
295 ohshite(_("failed to rewind trigger interest file '%.250s'"),
296 trk_explicit_fn.buf);
297
298 while (trk_explicit_fgets(buf, sizeof(buf)) >= 0) {
299 struct dpkg_error err;
300 char *slash;
301 bool noawait = false;
302 slash = strchr(buf, '/');
303 if (slash && strcmp("/noawait", slash) == 0) {
304 noawait = true;
305 *slash = '\0';
306 }
307 if (slash && strcmp("/await", slash) == 0) {
308 noawait = false;
309 *slash = '\0';
310 }
311
312 pend = pkg_spec_parse_pkg(buf, &err);
313 if (pend == NULL)
314 ohshit(_("trigger interest file '%.250s' syntax error; "
315 "illegal package name '%.250s': %.250s"),
316 trk_explicit_fn.buf, buf, err.str);
317
318 trig_record_activation(pend, noawait ? NULL : aw,
319 trk_explicit_trig);
320 }
321 }
322
323 static void
trk_explicit_interest_change(const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,int signum,enum trig_options opts)324 trk_explicit_interest_change(const char *trig, struct pkginfo *pkg,
325 struct pkgbin *pkgbin, int signum,
326 enum trig_options opts)
327 {
328 char buf[1024];
329 struct atomic_file *file;
330 bool empty = true;
331
332 trk_explicit_start(trig);
333 file = atomic_file_new(trk_explicit_fn.buf, 0);
334 atomic_file_open(file);
335
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);
339
340 if (strncmp(buf, pkgname, len) == 0 && len < sizeof(buf) &&
341 (buf[len] == '\0' || buf[len] == '/'))
342 continue;
343 fprintf(file->fp, "%s\n", buf);
344 empty = false;
345 }
346 if (signum > 0) {
347 fprintf(file->fp, "%s%s\n",
348 pkgbin_name(pkg, pkgbin, pnaw_nonambig),
349 (opts == TRIG_NOAWAIT) ? "/noawait" : "");
350 empty = false;
351 }
352
353 if (!empty)
354 atomic_file_sync(file);
355
356 atomic_file_close(file);
357
358 if (empty)
359 atomic_file_remove(file);
360 else
361 atomic_file_commit(file);
362
363 atomic_file_free(file);
364
365 dir_sync_path(triggersdir);
366 }
367
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,
373 };
374
375 /*---------- File triggers. ----------*/
376
377 static struct {
378 struct trigfileint *head, *tail;
379 } filetriggers;
380
381 /*
382 * Values:
383 * -1: Not read.
384 * 0: Not edited.
385 * 1: Edited
386 */
387 static int filetriggers_edited = -1;
388
389 /*
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.
393 */
394 static void
trk_file_interest_change(const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,int signum,enum trig_options opts)395 trk_file_interest_change(const char *trig, struct pkginfo *pkg,
396 struct pkgbin *pkgbin, int signum,
397 enum trig_options opts)
398 {
399 struct fsys_namenode *fnn;
400 struct trigfileint **search, *tfi;
401
402 fnn = trigh.namenode_find(trig, signum <= 0);
403 if (!fnn) {
404 if (signum >= 0)
405 internerr("lost filename node '%s' for package %s "
406 "triggered to add", trig,
407 pkgbin_name(pkg, pkgbin, pnaw_always));
408 return;
409 }
410
411 for (search = trigh.namenode_interested(fnn);
412 (tfi = *search);
413 search = &tfi->samefile_next)
414 if (tfi->pkg == pkg)
415 goto found;
416
417 /* Not found. */
418 if (signum < 0)
419 return;
420
421 tfi = nfmalloc(sizeof(*tfi));
422 tfi->pkg = pkg;
423 tfi->pkgbin = pkgbin;
424 tfi->fnn = fnn;
425 tfi->options = opts;
426 tfi->samefile_next = *trigh.namenode_interested(fnn);
427 *trigh.namenode_interested(fnn) = tfi;
428
429 LIST_LINK_TAIL_PART(filetriggers, tfi, inoverall);
430 goto edited;
431
432 found:
433 tfi->options = opts;
434 if (signum > 1)
435 ohshit(_("duplicate file trigger interest for filename '%.250s' "
436 "and package '%.250s'"), trig,
437 pkgbin_name(pkg, pkgbin, pnaw_nonambig));
438 if (signum > 0)
439 return;
440
441 /* Remove it: */
442 *search = tfi->samefile_next;
443 LIST_UNLINK_PART(filetriggers, tfi, inoverall);
444 edited:
445 filetriggers_edited = 1;
446 }
447
448 static void
trig_file_interests_remove(void)449 trig_file_interests_remove(void)
450 {
451 if (unlink(triggersfilefile) && errno != ENOENT)
452 ohshite(_("cannot remove '%.250s'"), triggersfilefile);
453 }
454
455 static void
trig_file_interests_update(void)456 trig_file_interests_update(void)
457 {
458 struct trigfileint *tfi;
459 struct atomic_file *file;
460
461 file = atomic_file_new(triggersfilefile, 0);
462 atomic_file_open(file);
463
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" : "");
468
469 atomic_file_sync(file);
470 atomic_file_close(file);
471 atomic_file_commit(file);
472 atomic_file_free(file);
473 }
474
475 void
trig_file_interests_save(void)476 trig_file_interests_save(void)
477 {
478 if (filetriggers_edited <= 0)
479 return;
480
481 if (!filetriggers.head)
482 trig_file_interests_remove();
483 else
484 trig_file_interests_update();
485
486 dir_sync_path(triggersdir);
487
488 filetriggers_edited = 0;
489 }
490
491 void
trig_file_interests_ensure(void)492 trig_file_interests_ensure(void)
493 {
494 FILE *f;
495 char linebuf[1024], *space;
496 struct pkginfo *pkg;
497 struct pkgbin *pkgbin;
498
499 if (filetriggers_edited >= 0)
500 return;
501
502 f = fopen(triggersfilefile, "r");
503 if (!f) {
504 if (errno == ENOENT)
505 goto ok;
506 ohshite(_("unable to read file triggers file '%.250s'"),
507 triggersfilefile);
508 }
509
510 push_cleanup(cu_closestream, ~0, 1, f);
511 while (fgets_checked(linebuf, sizeof(linebuf), f, triggersfilefile) >= 0) {
512 struct dpkg_error err;
513 char *slash;
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'"),
518 triggersfilefile);
519 *space++ = '\0';
520
521 slash = strchr(space, '/');
522 if (slash && strcmp("/noawait", slash) == 0) {
523 trig_opts = TRIG_NOAWAIT;
524 *slash = '\0';
525 }
526 if (slash && strcmp("/await", slash) == 0) {
527 trig_opts = TRIG_AWAIT;
528 *slash = '\0';
529 }
530
531 pkg = pkg_spec_parse_pkg(space, &err);
532 if (pkg == NULL)
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;
537
538 trk_file_interest_change(linebuf, pkg, pkgbin, +2, trig_opts);
539 }
540 pop_cleanup(ehflag_normaltidy);
541 ok:
542 filetriggers_edited = 0;
543 }
544
545 void
trig_file_activate_byname(const char * trig,struct pkginfo * aw)546 trig_file_activate_byname(const char *trig, struct pkginfo *aw)
547 {
548 struct fsys_namenode *fnn = trigh.namenode_find(trig, 1);
549
550 if (fnn)
551 trig_file_activate(fnn, aw);
552 }
553
554 void
trig_file_activate(struct fsys_namenode * trig,struct pkginfo * aw)555 trig_file_activate(struct fsys_namenode *trig, struct pkginfo *aw)
556 {
557 struct trigfileint *tfi;
558
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));
563 }
564
565 static void
trig_file_activate_parents(const char * trig,struct pkginfo * aw)566 trig_file_activate_parents(const char *trig, struct pkginfo *aw)
567 {
568 char *path, *slash;
569
570 /* Traverse the whole pathname to activate all of its components. */
571 path = m_strdup(trig);
572
573 while ((slash = strrchr(path, '/'))) {
574 *slash = '\0';
575 trig_file_activate_byname(path, aw);
576 }
577
578 free(path);
579 }
580
581 void
trig_path_activate(struct fsys_namenode * trig,struct pkginfo * aw)582 trig_path_activate(struct fsys_namenode *trig, struct pkginfo *aw)
583 {
584 trig_file_activate(trig, aw);
585 trig_file_activate_parents(trigh.namenode_name(trig), aw);
586 }
587
588 static void
trig_path_activate_byname(const char * trig,struct pkginfo * aw)589 trig_path_activate_byname(const char *trig, struct pkginfo *aw)
590 {
591 struct fsys_namenode *fnn = trigh.namenode_find(trig, 1);
592
593 if (fnn)
594 trig_file_activate(fnn, aw);
595
596 trig_file_activate_parents(trig, aw);
597 }
598
599 static const char *trk_file_trig;
600
601 static void
trk_file_activate_start(void)602 trk_file_activate_start(void)
603 {
604 trk_file_trig = trig_activating_name;
605 }
606
607 static void
trk_file_activate_awaiter(struct pkginfo * aw)608 trk_file_activate_awaiter(struct pkginfo *aw)
609 {
610 trig_path_activate_byname(trk_file_trig, aw);
611 }
612
613 static void
trk_file_activate_done(void)614 trk_file_activate_done(void)
615 {
616 }
617
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,
623 };
624
625 /*---------- Trigger control info file. ----------*/
626
627 static void
trig_cicb_interest_change(const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,int signum,enum trig_options opts)628 trig_cicb_interest_change(const char *trig, struct pkginfo *pkg,
629 struct pkgbin *pkgbin, int signum,
630 enum trig_options opts)
631 {
632 const struct trigkindinfo *tki = trig_classify_byname(trig);
633
634 if (filetriggers_edited < 0)
635 internerr("trigger control file for package %s not read",
636 pkgbin_name(pkg, pkgbin, pnaw_always));
637
638 tki->interest_change(trig, pkg, pkgbin, signum, opts);
639 }
640
641 void
trig_cicb_interest_delete(const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,enum trig_options opts)642 trig_cicb_interest_delete(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
648 void
trig_cicb_interest_add(const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,enum trig_options opts)649 trig_cicb_interest_add(const char *trig, struct pkginfo *pkg,
650 struct pkgbin *pkgbin, enum trig_options opts)
651 {
652 trig_cicb_interest_change(trig, pkg, pkgbin, +1, opts);
653 }
654
655 void
trig_cicb_statuschange_activate(const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,enum trig_options opts)656 trig_cicb_statuschange_activate(const char *trig, struct pkginfo *pkg,
657 struct pkgbin *pkgbin, enum trig_options opts)
658 {
659 struct pkginfo *aw = pkg;
660
661 trig_activate_start(trig);
662 dtki->activate_awaiter((opts == TRIG_NOAWAIT) ? NULL : aw);
663 dtki->activate_done();
664 }
665
666 static void
parse_ci_call(const char * file,const char * cmd,trig_parse_cicb * cb,const char * trig,struct pkginfo * pkg,struct pkgbin * pkgbin,enum trig_options opts)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)
670 {
671 const char *emsg;
672
673 emsg = trig_name_is_illegal(trig);
674 if (emsg)
675 ohshit(_("triggers ci file '%.250s' contains illegal trigger "
676 "syntax in trigger name '%.250s': %.250s"),
677 file, trig, emsg);
678 if (cb)
679 cb(trig, pkg, pkgbin, opts);
680 }
681
682 void
trig_parse_ci(const char * file,trig_parse_cicb * interest,trig_parse_cicb * activate,struct pkginfo * pkg,struct pkgbin * pkgbin)683 trig_parse_ci(const char *file, trig_parse_cicb *interest,
684 trig_parse_cicb *activate, struct pkginfo *pkg,
685 struct pkgbin *pkgbin)
686 {
687 FILE *f;
688 char linebuf[MAXTRIGDIRECTIVE], *cmd, *spc, *eol;
689 int l;
690
691 f = fopen(file, "r");
692 if (!f) {
693 if (errno == ENOENT)
694 return; /* No file is just like an empty one. */
695 ohshite(_("unable to open triggers ci file '%.250s'"), file);
696 }
697 push_cleanup(cu_closestream, ~0, 1, f);
698
699 while ((l = fgets_checked(linebuf, sizeof(linebuf), f, file)) >= 0) {
700 for (cmd = linebuf; c_iswhite(*cmd); cmd++) ;
701 if (*cmd == '#')
702 continue;
703 for (eol = linebuf + l; eol > cmd && c_iswhite(eol[-1]); eol--) ;
704 if (eol == cmd)
705 continue;
706 *eol = '\0';
707
708 for (spc = cmd; *spc && !c_iswhite(*spc); spc++) ;
709 if (!*spc)
710 ohshit(_("triggers ci file contains unknown directive syntax"));
711 *spc++ = '\0';
712 while (c_iswhite(*spc))
713 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);
724 } else {
725 ohshit(_("triggers ci file contains unknown directive '%.250s'"),
726 cmd);
727 }
728 }
729 pop_cleanup(ehflag_normaltidy); /* fclose() */
730 }
731
732 /*---------- Unincorp file incorporation. ----------*/
733
734 static void
tdm_incorp_trig_begin(const char * trig)735 tdm_incorp_trig_begin(const char *trig)
736 {
737 trig_activate_start(trig);
738 }
739
740 static void
tdm_incorp_package(const char * awname)741 tdm_incorp_package(const char *awname)
742 {
743 struct pkginfo *aw;
744
745 if (strcmp(awname, "-") == 0)
746 aw = NULL;
747 else
748 aw = pkg_spec_parse_pkg(awname, NULL);
749
750 dtki->activate_awaiter(aw);
751 }
752
753 static void
tdm_incorp_trig_end(void)754 tdm_incorp_trig_end(void)
755 {
756 dtki->activate_done();
757 }
758
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
763 };
764
765 void
trig_incorporate(enum modstatdb_rw cstatus)766 trig_incorporate(enum modstatdb_rw cstatus)
767 {
768 enum trigdef_update_status ur;
769 enum trigdef_update_flags tduf;
770
771 free(triggersdir);
772 triggersdir = dpkg_db_get_path(TRIGGERSDIR);
773
774 free(triggersfilefile);
775 triggersfilefile = trig_get_filename(triggersdir, TRIGGERSFILEFILE);
776
777 trigdef_set_methods(&tdm_incorp);
778 trig_file_interests_ensure();
779
780 tduf = TDUF_NO_LOCK_OK;
781 if (cstatus >= msdbrw_write) {
782 tduf |= TDUF_WRITE;
783 if (trigh.transitional_activate)
784 tduf |= TDUF_WRITE_IF_ENOENT;
785 }
786
787 ur = trigdef_update_start(tduf);
788 if (ur == TDUS_ERROR_NO_DIR && cstatus >= msdbrw_write) {
789 if (mkdir(triggersdir, 0755)) {
790 if (errno != EEXIST)
791 ohshite(_("unable to create triggers state"
792 " directory '%.250s'"), triggersdir);
793 } else if (chown(triggersdir, 0, 0)) {
794 ohshite(_("unable to set ownership of triggers state"
795 " directory '%.250s'"), triggersdir);
796 }
797 ur = trigdef_update_start(tduf);
798 }
799 switch (ur) {
800 case TDUS_ERROR_EMPTY_DEFERRED:
801 return;
802 case TDUS_ERROR_NO_DIR:
803 case TDUS_ERROR_NO_DEFERRED:
804 if (!trigh.transitional_activate)
805 return;
806 /* Fall through. */
807 case TDUS_NO_DEFERRED:
808 trigh.transitional_activate(cstatus);
809 break;
810 case TDUS_OK:
811 /* Read and incorporate triggers. */
812 trigdef_parse();
813 break;
814 default:
815 internerr("unknown trigdef_update_start return value '%d'", ur);
816 }
817
818 /* Right, that's it. New (empty) Unincorp can be installed. */
819 trigdef_process_done();
820 }
821
822 /*---------- Default hooks. ----------*/
823
824 TRIGHOOKS_DEFINE_NAMENODE_ACCESSORS
825
826 static struct trig_hooks trigh = {
827 .enqueue_deferred = NULL,
828 .transitional_activate = NULL,
829 .namenode_find = th_nn_find,
830 .namenode_interested = th_nn_interested,
831 .namenode_name = th_nn_name,
832 };
833
834 void
trig_override_hooks(const struct trig_hooks * hooks)835 trig_override_hooks(const struct trig_hooks *hooks)
836 {
837 trigh = *hooks;
838 }
839