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