/ libpkg / triggers.c
triggers.c
  1  /*-
  2   * Copyright (c) 2020-2026 Baptiste Daroussin <bapt@FreeBSD.org>
  3   *
  4   * SPDX-License-Identifier: BSD-2-Clause
  5   */
  6  
  7  #include "pkg_config.h"
  8  
  9  #if __has_include(<sys/capsicum.h>)
 10  #include <sys/capsicum.h>
 11  #define HAVE_CAPSICUM 1
 12  #endif
 13  
 14  #include <sys/stat.h>
 15  #include <sys/wait.h>
 16  
 17  #include <dirent.h>
 18  #include <err.h>
 19  #include <errno.h>
 20  #include <fcntl.h>
 21  #include <paths.h>
 22  #include <spawn.h>
 23  #include <xstring.h>
 24  
 25  #include <pkg.h>
 26  #include <private/pkg.h>
 27  #include <private/event.h>
 28  #include <private/lua.h>
 29  
 30  extern char **environ;
 31  
 32  static const unsigned char litchar[] =
 33  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 34  
 35  static script_type_t
 36  get_script_type(const char *str)
 37  {
 38  	if (STRIEQ(str, "lua"))
 39  		return (SCRIPT_LUA);
 40  	return (SCRIPT_UNKNOWN);
 41  }
 42  
 43  static ucl_object_t *
 44  trigger_open_schema(void)
 45  {
 46  	struct ucl_parser *parser;
 47  	ucl_object_t *trigger_schema;
 48  	static const char trigger_schema_str[] = ""
 49  		"{"
 50  		"  type = object;"
 51  		"  properties {"
 52  		"    description: { type = string };"
 53  		"    path: { "
 54  		"      anyOf = [{"
 55  		"        type = array; "
 56  		"        item = { type = string };"
 57  		"      }, {"
 58  		"        type = string;"
 59  		"      }]"
 60  		"    };"
 61  		"    path_glob: { "
 62  		"      anyOf = [{"
 63  		"        type = array; "
 64  		"        item = { type = string };"
 65  		"      }, {"
 66  		"        type = string;"
 67  		"      }]"
 68  		"    };"
 69  		"    path_regexp: { "
 70  		"      anyOf = [{"
 71  		"        type = array; "
 72  		"        item = { type = string };"
 73  		"      }, {"
 74  		"        type = string;"
 75  		"      }]"
 76  		"    };"
 77  		"    cleanup = { "
 78  		"      type = object; "
 79  		"      properties = {"
 80  		"        type = { "
 81  		"          type = string,"
 82  		"          sandbox = boolean, "
 83  		"          enum: [lua];"
 84  		"        };"
 85  		"        script = { type = string };"
 86  		"      }; "
 87  		"      required = [ type, script ];"
 88  		"    };"
 89  		"    trigger = { "
 90  		"      type = object; "
 91  		"      properties = {"
 92  		"        type = { "
 93  		"          type = string,"
 94  		"          sandbox = boolean, "
 95  		"          enum: [lua];"
 96  		"        };"
 97  		"        script = { type = string };"
 98  		"      }; "
 99  		"      required = [ type, script ];"
100  		"    };"
101  		"  }\n"
102  		"  required = [ trigger ];"
103  		"}";
104  
105  	parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
106  	if (!ucl_parser_add_chunk(parser, trigger_schema_str,
107  	    sizeof(trigger_schema_str) -1)) {
108  		pkg_emit_error("Cannot parse schema for trigger: %s",
109  		    ucl_parser_get_error(parser));
110  		ucl_parser_free(parser);
111  		return (NULL);
112  	}
113  
114  	trigger_schema = ucl_parser_get_object(parser);
115  	ucl_parser_free(parser);
116  	return (trigger_schema);
117  }
118  
119  static bool
120  parse_trigger_script_block(const ucl_object_t *block, const char *block_name,
121      const char *trigger_name, char **out_script, int *out_type, bool *out_sandbox)
122  {
123  	const ucl_object_t *o;
124  
125  	o = ucl_object_find_key(block, "type");
126  	if (o == NULL) {
127  		pkg_emit_error("%s %s doesn't have a script type", block_name, trigger_name);
128  		return (false);
129  	}
130  	*out_type = get_script_type(ucl_object_tostring(o));
131  	if (*out_type == SCRIPT_UNKNOWN) {
132  		pkg_emit_error("Unknown script type for %s in %s", block_name, trigger_name);
133  		return (false);
134  	}
135  	o = ucl_object_find_key(block, "script");
136  	if (o == NULL) {
137  		pkg_emit_error("No script in %s %s", block_name, trigger_name);
138  		return (false);
139  	}
140  	*out_script = xstrdup(ucl_object_tostring(o));
141  	o = ucl_object_find_key(block, "sandbox");
142  	*out_sandbox = (o == NULL) ? true : ucl_object_toboolean(o);
143  	return (true);
144  }
145  
146  static struct trigger *
147  trigger_load(int dfd, const char *name, bool cleanup_only, ucl_object_t *schema)
148  {
149  	struct ucl_parser *p;
150  	ucl_object_t *obj = NULL;
151  	const ucl_object_t *block = NULL;
152  	int fd;
153  	struct ucl_schema_error err;
154  	struct trigger *t;
155  
156  	fd = openat(dfd, name, O_RDONLY);
157  	if (fd == -1) {
158  		pkg_emit_error("Unable to open the trigger: %s", name);
159  		return (NULL);
160  	}
161  
162  	p = ucl_parser_new(0);
163  	if (!ucl_parser_add_fd(p, fd)) {
164  		pkg_emit_error("Error parsing trigger '%s': %s", name,
165  		    ucl_parser_get_error(p));
166  		ucl_parser_free(p);
167  		close(fd);
168  		return (NULL);
169  	}
170  	close(fd);
171  
172  	obj = ucl_parser_get_object(p);
173  	ucl_parser_free(p);
174  	if (obj == NULL)
175  		return (NULL);
176  
177  	if (!ucl_object_validate(schema, obj, &err)) {
178  		pkg_emit_error("trigger definition %s cannot be validated: %s", name, err.msg);
179  		ucl_object_unref(obj);
180  		return (NULL);
181  	}
182  
183  	t = xcalloc(1, sizeof(*t));
184  	t->name = xstrdup(name);
185  
186  	if (cleanup_only) {
187  		block = ucl_object_find_key(obj, "cleanup");
188  		if (block == NULL)
189  			goto err;
190  		if (!parse_trigger_script_block(block, "cleanup", name,
191  		    &t->cleanup.script, &t->cleanup.type, &t->cleanup.sandbox))
192  			goto err;
193  		ucl_object_unref(obj);
194  		return (t);
195  	}
196  
197  	block = ucl_object_find_key(obj, "trigger");
198  	if (!parse_trigger_script_block(block, "trigger", name,
199  	    &t->script.script, &t->script.type, &t->script.sandbox))
200  		goto err;
201  
202  	/* Load path patterns (required for any non-cleanup block) */
203  	block = ucl_object_find_key(obj, "path");
204  	if (block != NULL)
205  		t->path = ucl_object_ref(block);
206  	block = ucl_object_find_key(obj, "path_glob");
207  	if (block != NULL)
208  		t->path_glob = ucl_object_ref(block);
209  	block = ucl_object_find_key(obj, "path_regexp");
210  	if (block != NULL)
211  		t->path_regexp = ucl_object_ref(block);
212  	if (t->path == NULL &&
213  	    t->path_glob == NULL &&
214  	    t->path_regexp == NULL) {
215  		pkg_emit_error("No path* in trigger %s, skipping", name);
216  		goto err;
217  	}
218  
219  	ucl_object_unref(obj);
220  	return (t);
221  
222  err:
223  	if (t) {
224  		if (t->path != NULL)
225  			ucl_object_unref(t->path);
226  		if (t->path_glob != NULL)
227  			ucl_object_unref(t->path_glob);
228  		if (t->path_regexp != NULL)
229  			ucl_object_unref(t->path_regexp);
230  		free(t->script.script);
231  		free(t->cleanup.script);
232  		free(t);
233  	}
234  	ucl_object_unref(obj);
235  	return (NULL);
236  }
237  
238  void
239  trigger_is_it_a_cleanup(struct triggers *t, const char *path)
240  {
241  	const char *trigger_name, *dir;
242  	const pkg_object *dirs, *cur;
243  	struct trigger *trig;
244  	pkg_iter it;
245  
246  	if (t->schema == NULL)
247  		t->schema = trigger_open_schema();
248  
249  	/* Check if the file was installed in a trigger directory. */
250  	it = NULL;
251  	trigger_name = NULL;
252  	dirs = pkg_config_get("PKG_TRIGGERS_DIR");
253  	while ((cur = pkg_object_iterate(dirs, &it))) {
254  		size_t len;
255  
256  		dir = pkg_object_string(cur);
257  		len = strlen(dir);
258  
259  		if (strncmp(path, dir, len) == 0) {
260  			trigger_name = path + strlen(dir);
261  			break;
262  		}
263  	}
264  
265  	if (trigger_name == NULL)
266  		return;
267  
268  	if (t->dfd == -1)
269  		t->dfd = openat(ctx.rootfd, RELATIVE_PATH(dir), O_DIRECTORY);
270  
271  	trig = trigger_load(t->dfd, RELATIVE_PATH(trigger_name), true, t->schema);
272  	if (trig != NULL) {
273  		if (t->cleanup == NULL)
274  			t->cleanup = xcalloc(1, sizeof(*t->cleanup));
275  
276  		vec_push(t->cleanup, trig);
277  	}
278  }
279  
280  /*
281   * Load triggers from a specific directory and add them to a vec.
282   */
283  static void
284  triggers_load_from(trigger_t *triggers, bool cleanup_only, const char *dir)
285  {
286  	int dfd;
287  	DIR *d;
288  	struct dirent *e;
289  	struct trigger *t;
290  	ucl_object_t *schema;
291  	struct stat st;
292  
293  	dfd = openat(ctx.rootfd, dir, O_DIRECTORY);
294  	if (dfd == -1) {
295  		if (errno != ENOENT)
296  			pkg_emit_error("Unable to open the trigger directory %s: %s",
297  			    dir, strerror(errno));
298  		return;
299  	}
300  
301  	d = fdopendir(dfd);
302  	if (d == NULL) {
303  		pkg_emit_error("Unable to open the trigger directory %s: %s",
304  		    dir, strerror(errno));
305  		close(dfd);
306  		return;
307  	}
308  
309  	schema = trigger_open_schema();
310  
311  	while ((e = readdir(d)) != NULL) {
312  		const char *ext;
313  		/* ignore all hidden files */
314  		if (e->d_name[0] ==  '.')
315  			continue;
316  		/* only consider files ending with .ucl */
317  		ext = strrchr(e->d_name, '.');
318  		if (ext == NULL)
319  			continue;
320  		if (!STREQ(ext, ".ucl"))
321  			continue;
322  		/* only regular files are considered */
323  		if (fstatat(dfd, e->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) {
324  			pkg_emit_errno("fstatat", e->d_name);
325  			continue;
326  		}
327  		if (!S_ISREG(st.st_mode))
328  			continue;
329  		t = trigger_load(dfd, e->d_name, cleanup_only, schema);
330  		if (t != NULL)
331  			vec_push(triggers, t);
332  	}
333  
334  	closedir(d);
335  	ucl_object_unref(schema);
336  }
337  
338  /*
339   * Load triggers from PKG_TRIGGERS_DIR.
340   */
341  trigger_t *
342  triggers_load(bool cleanup_only)
343  {
344  	trigger_t *ret;
345  	const pkg_object *dirs, *cur;
346  	pkg_iter it = NULL;
347  
348  	ret = xcalloc(1, sizeof(*ret));
349  
350  	dirs = pkg_config_get("PKG_TRIGGERS_DIR");
351  	while ((cur = pkg_object_iterate(dirs, &it))) {
352  		const char *dir;
353  
354  		dir = RELATIVE_PATH(pkg_object_string(cur));
355  		triggers_load_from(ret, cleanup_only, dir);
356  	}
357  
358  	return (ret);
359  }
360  
361  void
362  trigger_free(struct trigger *t)
363  {
364  	if (!t)
365  		return;
366  	free(t->name);
367  	if (t->path)
368  		ucl_object_unref(t->path);
369  	if (t->path_glob)
370  		ucl_object_unref(t->path_glob);
371  	if (t->path_regexp)
372  		ucl_object_unref(t->path_regexp);
373  	free(t->cleanup.script);
374  	free(t->script.script);
375  	free(t);
376  }
377  
378  static char *
379  get_random_name(char name[])
380  {
381  	char *pos;
382  	int r;
383  
384  	pos = name;
385  	while (*pos == 'X') {
386  #ifndef HAVE_ARC4RANDOM
387  		r = rand() % (sizeof(litchar) -1);
388  #else
389  		r = arc4random_uniform(sizeof(litchar) -1);
390  #endif
391  		*pos++ = litchar[r];
392  	}
393  
394  	return (name);
395  }
396  
397  static void
398  save_trigger(const char *script, bool sandbox, pkghash *args)
399  {
400  	int db = ctx.pkg_dbdirfd;
401  	pkghash_it it;
402  
403  	if (!mkdirat_p(db, "triggers"))
404  		return;
405  
406  	int trigfd = openat(db, "triggers", O_DIRECTORY);
407  	close(db);
408  	if (trigfd == -1) {
409  		pkg_errno("Failed to open '%s' as a directory", "triggers");
410  		return;
411  	}
412  
413  #ifndef HAVE_ARC4RANDOM
414  	srand(time(NULL));
415  #endif
416  
417  	int fd;
418  	for (;;) {
419  		char name[] = "XXXXXXXXXX";
420  		fd = openat(trigfd, get_random_name(name),
421  		    O_CREAT|O_RDWR|O_EXCL, 0644);
422  		if (fd != -1)
423  			break;
424  		if (errno == EEXIST)
425  			continue;
426  		pkg_errno("Can't create deferred triggers %s", name);
427  		return;
428  	}
429  	close(trigfd);
430  	FILE *f = fdopen(fd, "w");
431  	if (sandbox)
432  		fputs("--sandbox\n", f);
433  	fputs("--begin args\n", f);
434  	it = pkghash_iterator(args);
435  	while (pkghash_next(&it)) {
436  		fprintf(f, "-- %s\n", (char *)it.value);
437  	}
438  	fputs("--end args\n--\n", f);
439  	fprintf(f, "%s\n", script);
440  	fclose(f);
441  }
442  
443  static int
444  trigger_execute_lua_common(const char *script, bool sandbox, pkghash *args,
445      bool defer, const char *pkgname, const char *pkgversion, bool upgrade)
446  {
447  	lua_State *L;
448  	int pstat;
449  	pkghash_it it;
450  
451  	if (defer && !sandbox && ctx.defer_triggers) {
452  		save_trigger(script, sandbox, args);
453  		return (EPKG_OK);
454  	}
455  
456  	pid_t pid = fork();
457  	if (pid == 0) {
458  		L = luaL_newstate();
459  		luaL_openlibs(L);
460  		lua_override_ios(L, sandbox);
461  		static const luaL_Reg pkg_lib[] = {
462  			{ "print_msg", lua_print_msg },
463  			{ "filecmp", lua_pkg_filecmp },
464  			{ "copy", lua_pkg_copy },
465  			{ "stat", lua_stat },
466  			{ "readdir", lua_readdir },
467  			{ "exec", lua_exec },
468  			{ "symlink", lua_pkg_symlink },
469  			{ NULL, NULL },
470  		};
471  		luaL_newlib(L, pkg_lib);
472  		lua_setglobal(L, "pkg");
473  		lua_pushinteger(L, ctx.rootfd);
474  		lua_setglobal(L, "rootfd");
475  		if (pkgname != NULL) {
476  			lua_pushstring(L, pkgname);
477  			lua_setglobal(L, "pkg_name");
478  		}
479  		if (pkgversion != NULL) {
480  			lua_pushstring(L, pkgversion);
481  			lua_setglobal(L, "pkg_version");
482  		}
483  		lua_pushboolean(L, upgrade);
484  		lua_setglobal(L, "pkg_upgrade");
485  		char **arguments = NULL;
486  		int i = 0;
487  		if (args != NULL) {
488  			arguments = xcalloc(pkghash_count(args), sizeof(char*));
489  			it = pkghash_iterator(args);
490  			while (pkghash_next(&it)) {
491  				arguments[i++] = it.key;
492  			}
493  		}
494  		lua_args_table(L, arguments, i);
495  #ifdef HAVE_CAPSICUM
496  		if (sandbox) {
497  #ifndef COVERAGE
498  			if (cap_enter() < 0 && errno != ENOSYS) {
499  				err(1, "cap_enter failed");
500  			}
501  #endif
502  		}
503  #endif
504  		if (luaL_dostring(L, script)) {
505  			pkg_emit_error("Failed to execute lua trigger: "
506  					"%s", lua_tostring(L, -1));
507  			_exit(1);
508  		}
509  		if (lua_tonumber(L, -1) != 0) {
510  			lua_close(L);
511  			_exit(1);
512  		}
513  		lua_close(L);
514  		_exit(0);
515  	} else if (pid < 0) {
516  		pkg_emit_errno("Cannot fork", "lua_script");
517  		return (EPKG_FATAL);
518  	}
519  	while (waitpid(pid, &pstat, 0) == -1) {
520  		if (errno != EINTR) {
521  			pkg_emit_error("waitpid() failed: %s", strerror(errno));
522  			return (EPKG_FATAL );
523  		}
524  	}
525  	if (WEXITSTATUS(pstat) != 0) {
526  		pkg_emit_error("lua script failed");
527  		return (EPKG_FATAL);
528  	}
529  
530  	return (EPKG_OK);
531  }
532  
533  static int
534  trigger_execute_lua(const char *script, bool sandbox, pkghash *args)
535  {
536  	return (trigger_execute_lua_common(script, sandbox, args,
537  	    true, NULL, NULL, false));
538  }
539  
540  static void
541  trigger_check_match(struct trigger *t, char *dir)
542  {
543  	const ucl_object_t *cur;
544  	ucl_object_iter_t it;
545  
546  	if (t->path != NULL) {
547  		it = NULL;
548  		while ((cur = ucl_iterate_object(t->path, &it, true))) {
549  			if (STREQ(dir, ucl_object_tostring(cur))) {
550  				pkghash_safe_add(t->matched, dir, dir, NULL);
551  				return;
552  			}
553  		}
554  	}
555  
556  	if (match_ucl_lists(dir, t->path_glob, t->path_regexp)) {
557  		pkghash_safe_add(t->matched, dir, dir, NULL);
558  	}
559  }
560  
561  /*
562   * first execute cleanup scripts from the triggers that are not there anymore,
563   * then execute all per-transaction triggers that matched touched directories.
564   * Always reload triggers from disk: new trigger files may have been installed
565   * during the transaction.
566   */
567  int
568  triggers_execute(struct triggers *t)
569  {
570  	trigger_t *triggers;
571  	int ret = EPKG_OK;
572  
573  	triggers = triggers_load(false);
574  
575  	pkg_emit_triggers_begin();
576  	if (t != NULL && t->cleanup != NULL) {
577  		vec_foreach(*t->cleanup, i) {
578  			pkg_emit_trigger(t->cleanup->d[i]->name, true);
579  			if (t->cleanup->d[i]->cleanup.type == SCRIPT_LUA) {
580  				ret = trigger_execute_lua(t->cleanup->d[i]->cleanup.script,
581  				    t->cleanup->d[i]->cleanup.sandbox, NULL);
582  			}
583  			if (ret != EPKG_OK)
584  				goto cleanup;
585  		}
586  	}
587  
588  	if (ctx.touched_dir_hash) {
589  		pkghash_it it = pkghash_iterator(ctx.touched_dir_hash);
590  		while (pkghash_next(&it)) {
591  			vec_foreach(*triggers, i)
592  				trigger_check_match(triggers->d[i], it.key);
593  		}
594  	}
595  
596  	vec_foreach(*triggers, i) {
597  		if (triggers->d[i]->matched == NULL)
598  			continue;
599  		pkg_emit_trigger(triggers->d[i]->name, false);
600  		if (triggers->d[i]->script.type == SCRIPT_LUA) {
601  			ret = trigger_execute_lua(triggers->d[i]->script.script,
602  			    triggers->d[i]->script.sandbox, triggers->d[i]->matched);
603  		}
604  		if (ret != EPKG_OK)
605  			goto cleanup;
606  	}
607  	pkg_emit_triggers_finished();
608  
609  cleanup:
610  	vec_free_and_free(triggers, trigger_free);
611  	free(triggers);
612  
613  	return (EPKG_OK);
614  }
615  
616  /*
617   * Match a dir against a trigger's path patterns, adding to local_matched.
618   */
619  static bool
620  trigger_check_match_local(struct trigger *t, const char *dir, pkghash **matched)
621  {
622  	const ucl_object_t *cur;
623  	ucl_object_iter_t it;
624  
625  	if (t->path != NULL) {
626  		it = NULL;
627  		while ((cur = ucl_iterate_object(t->path, &it, true))) {
628  			if (STREQ(dir, ucl_object_tostring(cur))) {
629  				pkghash_safe_add(*matched, dir, NULL, NULL);
630  				return (true);
631  			}
632  		}
633  	}
634  
635  	if (match_ucl_lists(dir, t->path_glob, t->path_regexp)) {
636  		pkghash_safe_add(*matched, dir, NULL, NULL);
637  		return (true);
638  	}
639  	return (false);
640  }
641  
642  /*
643   * Per-package trigger subdirectory names, indexed by trigger_phase_t.
644   */
645  static const char *trigger_phase_dirs[] = {
646  	[TRIGGER_PHASE_PRE_INSTALL] = "pre_install",
647  	[TRIGGER_PHASE_POST_INSTALL] = "post_install",
648  	[TRIGGER_PHASE_PRE_DEINSTALL] = "pre_deinstall",
649  	[TRIGGER_PHASE_POST_DEINSTALL] = "post_deinstall",
650  };
651  
652  /*
653   * Load per-package triggers from the phase-specific subdirectory
654   * under each configured PKG_TRIGGERS_DIR.
655   */
656  static trigger_t *
657  triggers_load_perpackage(trigger_phase_t phase)
658  {
659  	trigger_t *ret;
660  	const pkg_object *dirs, *cur;
661  	pkg_iter it = NULL;
662  	char path[MAXPATHLEN];
663  
664  	ret = xcalloc(1, sizeof(*ret));
665  
666  	dirs = pkg_config_get("PKG_TRIGGERS_DIR");
667  	while ((cur = pkg_object_iterate(dirs, &it))) {
668  		const char *dir;
669  
670  		dir = RELATIVE_PATH(pkg_object_string(cur));
671  		snprintf(path, sizeof(path), "%s/%s",
672  		    dir, trigger_phase_dirs[phase]);
673  		triggers_load_from(ret, false, path);
674  	}
675  
676  	return (ret);
677  }
678  
679  /*
680   * Execute per-package triggers for a given phase on a specific package.
681   * Triggers are loaded from the phase-specific subdirectory (e.g.
682   * post_install/) so only relevant triggers are parsed.  They are
683   * reloaded from disk each time so that triggers installed or removed
684   * by earlier packages in the same transaction are picked up.
685   */
686  int
687  triggers_execute_perpackage(struct triggers *t, struct pkg *pkg,
688      trigger_phase_t phase, bool upgrade)
689  {
690  	struct pkg_file *f = NULL;
691  	struct pkg_dir *d = NULL;
692  	pkghash *pkg_dirs_hash = NULL;
693  	int ret = EPKG_OK;
694  	trigger_t *triggers;
695  
696  	if (t == NULL)
697  		return (EPKG_OK);
698  
699  	triggers = triggers_load_perpackage(phase);
700  
701  	if (triggers->len == 0) {
702  		vec_free_and_free(triggers, trigger_free);
703  		free(triggers);
704  		return (EPKG_OK);
705  	}
706  
707  	/* Build set of parent directories from the package's files */
708  	while (pkg_files(pkg, &f) == EPKG_OK) {
709  		char *dir, *slash;
710  		dir = xstrdup(f->path);
711  		slash = strrchr(dir, '/');
712  		if (slash != NULL) {
713  			*slash = '\0';
714  			pkghash_safe_add(pkg_dirs_hash, dir, NULL, NULL);
715  		}
716  		free(dir);
717  	}
718  	while (pkg_dirs(pkg, &d) == EPKG_OK) {
719  		pkghash_safe_add(pkg_dirs_hash, d->path, NULL, NULL);
720  	}
721  
722  	if (pkg_dirs_hash == NULL) {
723  		vec_free_and_free(triggers, trigger_free);
724  		free(triggers);
725  		return (EPKG_OK);
726  	}
727  
728  	/* Match and execute */
729  	vec_foreach(*triggers, i) {
730  		struct trigger *trig = triggers->d[i];
731  		pkghash *local_matched = NULL;
732  		pkghash_it it = pkghash_iterator(pkg_dirs_hash);
733  
734  		while (pkghash_next(&it))
735  			trigger_check_match_local(trig, it.key, &local_matched);
736  
737  		if (local_matched == NULL)
738  			continue;
739  
740  		pkg_emit_trigger(trig->name, false);
741  		if (trig->script.type == SCRIPT_LUA) {
742  			ret = trigger_execute_lua_common(trig->script.script,
743  			    trig->script.sandbox, local_matched, false,
744  			    pkg->name, pkg->version, upgrade);
745  		}
746  		pkghash_destroy(local_matched);
747  		if (ret != EPKG_OK) {
748  			pkg_emit_error("per-package trigger %s failed "
749  			    "for %s, continuing", trig->name, pkg->name);
750  			ret = EPKG_OK;
751  		}
752  	}
753  
754  	pkghash_destroy(pkg_dirs_hash);
755  	vec_free_and_free(triggers, trigger_free);
756  	free(triggers);
757  	return (ret);
758  }
759  
760  void
761  append_touched_dir(const char *path)
762  {
763  	pkghash_safe_add(ctx.touched_dir_hash, path, NULL, NULL);
764  }
765  
766  void
767  append_touched_file(const char *path)
768  {
769  	char *newpath, *walk;
770  
771  	newpath = xstrdup(path);
772  	walk = strrchr(newpath, '/');
773  	if (walk == NULL)
774  		return;
775  	*walk = '\0';
776  
777  	pkghash_safe_add(ctx.touched_dir_hash, newpath, NULL, NULL );
778  	free(newpath);
779  }
780  
781  static void
782  exec_deferred(int dfd, const char *name)
783  {
784  	bool sandbox = false;
785  	pkghash *args = NULL;
786  	xstring *script = NULL;
787  
788  	int fd = openat(dfd, name, O_RDONLY);
789  	if (fd == -1) {
790  		pkg_errno("Unable to open the trigger '%s'", name);
791  		return;
792  	}
793  	FILE *f = fdopen(fd, "r");
794  	if (f == NULL) {
795  		pkg_errno("Unable to open the trigger '%s'", name);
796  		return;
797  	}
798  
799  	char *line = NULL;
800  	size_t linecap = 0;
801  	ssize_t linelen;
802  	char *walk;
803  	bool inargs = false;
804  	while ((linelen = getline(&line, &linecap, f)) > 0) {
805  		walk = line;
806  		walk += 2; /* '--' aka lua comments */
807  		if (strncmp(walk, "sandbox", 7) == 0) {
808  			sandbox = true;
809  			continue;
810  		}
811  		if (strncmp(walk, "begin args", 10) == 0) {
812  			inargs = true;
813  			continue;
814  		}
815  		if (strncmp(walk, "end args", 8) == 0) {
816  			inargs = false;
817  			script = xstring_new();
818  			continue;
819  		}
820  		if (inargs) {
821  			walk++; /* skip the space */
822  			if (line[linelen -1] == '\n')
823  				line[linelen -1] = '\0';
824  			pkghash_safe_add(args, walk, NULL, NULL);
825  		}
826  		if (script != NULL)
827  			fputs(line, script->fp);
828  	}
829  	free(line);
830  	fclose(f);
831  	if (script == NULL) {
832  		pkghash_destroy(args);
833  		return;
834  	}
835  	char *s = xstring_get(script);
836  	if (trigger_execute_lua(s, sandbox, args) == EPKG_OK) {
837  		unlinkat(dfd, name, 0);
838  	}
839  	free(s);
840  	pkghash_destroy(args);
841  }
842  
843  int
844  pkg_execute_deferred_triggers(void)
845  {
846  	struct dirent *e;
847  	struct stat st;
848  	int dbdir = pkg_get_dbdirfd();
849  
850  	int trigfd = openat(dbdir, "triggers", O_DIRECTORY);
851  	if (trigfd == -1)
852  		return (EPKG_OK);
853  
854  	DIR *d = fdopendir(trigfd);
855  	if (d == NULL) {
856  		close(trigfd);
857  		pkg_emit_error("Unable to open the deferred trigger directory");
858  		return (EPKG_FATAL);
859  	}
860  
861  	while ((e = readdir(d)) != NULL) {
862  		/* ignore all hiddn files */
863  		if (e->d_name[0] == '.')
864  			continue;
865  		/* only regular files are considered */
866  		if (fstatat(trigfd, e->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) {
867  			pkg_emit_errno("fstatat", e->d_name);
868  			return (EPKG_FATAL);
869  		}
870  		exec_deferred(trigfd, e->d_name);
871  	}
872  	closedir(d);
873  	return (EPKG_OK);
874  }