Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Triggers: in case rootdir is provided, defer the triggers
Baptiste Daroussin committed 5 years ago
commit 9c5236e921afacc00f27a0c7ef31df1078bd219e
parent abf8dd8
8 files changed +270 -3
modified libpkg/pkg.h.in
@@ -1660,6 +1660,7 @@ int pkg_create_from_manifest(const char *, pkg_formats, const char *,
int pkg_create_staged(const char *, pkg_formats, const char *, const char *, char *, bool) __attribute__((deprecated));
int pkg_create_installed(const char *, pkg_formats, struct pkg *) __attribute__((deprecated));
int pkgdb_register_ports(struct pkgdb *db, struct pkg *pkg) __attribute__((deprecated));;
+
int pkg_execute_deferred_triggers(void);

#ifdef __cplusplus
}
modified libpkg/pkg_config.c
@@ -76,6 +76,7 @@ struct pkg_ctx ctx = {
	.backup_libraries = false,
	.triggers = true,
	.compression_level = -1,
+
	.defer_triggers = false,
};

struct config_entry {
@@ -1612,6 +1613,8 @@ pkg_set_rootdir(const char *rootdir) {
		return (EPKG_FATAL);
	}
	ctx.pkg_rootdir = rootdir;
+
	ctx.defer_triggers = true;
+
	printf("ici\n");

	return (EPKG_OK);
}
modified libpkg/private/pkg.h
@@ -266,6 +266,7 @@ struct pkg_ctx {
	bool triggers;
	const char *triggers_path;
	kh_strings_t *touched_dir_hash;
+
	bool defer_triggers;
};

extern struct pkg_ctx ctx;
modified libpkg/triggers.c
@@ -39,6 +39,7 @@
#include <fcntl.h>
#include <paths.h>
#include <spawn.h>
+
#include <xstring.h>

#include <private/pkg.h>
#include <private/event.h>
@@ -46,6 +47,9 @@

extern char **environ;

+
static const unsigned char litchar[] =
+
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+

static script_type_t
get_script_type(const char *str)
{
@@ -319,8 +323,76 @@ trigger_free(struct trigger *t)
	free(t->script.script);
}

+
static char *
+
get_random_name(char name[])
+
{
+
	char *pos;
+
	int r;
+

+
	pos = name;
+
	while (*pos == 'X') {
+
#ifndef HAVE_ARC4RANDOM
+
		r = rand() % (sizeof(litchar) -1);
+
#else
+
		r = arc4random_uniform(sizeof(litchar) -1);
+
#endif
+
		*pos++ = litchar[r];
+
	}
+

+
	return (name);
+
}
+

+
static void
+
save_trigger(const char *script, bool sandbox, kh_strings_t *args, bool lua)
+
{
+
	int db = ctx.pkg_dbdirfd;
+
	const char *dir;
+
	const char *comment = "-- ";
+

+
	if (!lua)
+
		comment = "# ";
+

+
	if (!mkdirat_p(db, "triggers"))
+
		return;
+

+
	int trigfd = openat(db, "triggers", O_DIRECTORY);
+
	close(db);
+
	if (trigfd == -1) {
+
		pkg_errno("Failed to open '%s' as a directory", "triggers");
+
		return;
+
	}
+

+
#ifndef HAVE_ARC4RANDOM
+
	srand(time(NULL));
+
#endif
+

+
	int fd;
+
	for (;;) {
+
		char name[] = "XXXXXXXXXX";
+
		fd = openat(trigfd, get_random_name(name),
+
		    O_CREAT|O_RDWR|O_EXCL, 0644);
+
		if (fd != -1)
+
			break;
+
		if (errno == EEXIST)
+
			continue;
+
		pkg_errno("meh %s", name);
+
		return;
+
	}
+
	close(trigfd);
+
	FILE *f = fdopen(fd, "w");
+
	if (sandbox)
+
		fprintf(f, "%ssandbox\n", comment);
+
	fprintf(f, "%sbegin args\n", comment);
+
	kh_foreach_value(args, dir, {
+
		fprintf(f, "-- %s\n", dir);
+
	});
+
	fprintf(f, "%send args\n--\n", comment);
+
	fprintf(f, "%s\n", script);
+
	fclose(f);
+
}
+

static int
-
trigger_execute_shell(const char *script, kh_strings_t *args __unused)
+
trigger_execute_shell(const char *script, bool sandboxed __unused, kh_strings_t *args __unused)
{
	posix_spawn_file_actions_t action;
	int stdin_pipe[2] = {-1, -1};
@@ -332,6 +404,11 @@ trigger_execute_shell(const char *script, kh_strings_t *args __unused)
	int ret = EPKG_OK;
	pid_t pid;

+
	if (ctx.defer_triggers) {
+
		save_trigger(script, false, args, false);
+
		return (EPKG_OK);
+
	}
+

	if (pipe(stdin_pipe) < 0)
		return (EPKG_FATAL);

@@ -393,6 +470,11 @@ trigger_execute_lua(const char *script, bool sandbox, kh_strings_t *args)
	lua_State *L;
	int pstat;

+
	if (ctx.defer_triggers) {
+
		save_trigger(script, sandbox, args, true);
+
		return (EPKG_OK);
+
	}
+

	pid_t pid = fork();
	if (pid == 0) {
		L = luaL_newstate();
@@ -519,7 +601,7 @@ triggers_execute(struct trigger *cleanup_triggers)
			ret = trigger_execute_lua(t->cleanup.script,
			    t->cleanup.sandbox, NULL);
		} else if (t->cleanup.type == SCRIPT_SHELL) {
-
			ret = trigger_execute_shell(t->cleanup.script, NULL);
+
			ret = trigger_execute_shell(t->cleanup.script, false, NULL);
		}
		if (ret != EPKG_OK)
			goto cleanup;
@@ -542,7 +624,7 @@ triggers_execute(struct trigger *cleanup_triggers)
			ret = trigger_execute_lua(t->script.script,
			    t->script.sandbox, t->matched);
		} else if (t->script.type == SCRIPT_SHELL) {
-
			ret = trigger_execute_shell(t->script.script, t->matched);
+
			ret = trigger_execute_shell(t->script.script, false, t->matched);
		}
		if (ret != EPKG_OK)
			goto cleanup;
@@ -575,3 +657,109 @@ append_touched_file(const char *path)

	kh_add(strings, ctx.touched_dir_hash, newpath, newpath, free);
}
+

+
void
+
exec_deferred(int dfd, const char *name)
+
{
+
	int (*trigger_exec)(const char *, bool , kh_strings_t *);
+
	const char *comment = NULL;
+
	bool sandbox = false;
+
	kh_strings_t *args = NULL;
+
	xstring *script = NULL;
+

+
	int fd = openat(dfd, name, O_RDONLY);
+
	if (fd == -1) {
+
		pkg_errno("Unable to open the trigger '%s'", name);
+
		return;
+
	}
+
	FILE *f = fdopen(fd, "r");
+
	if (f == NULL) {
+
		pkg_errno("Unable to open the trigger '%s'", name);
+
		return;
+
	}
+
	
+
	char *line = NULL;
+
	size_t linecap = 0;
+
	ssize_t linelen;
+
	char *walk;
+
	bool inargs = false;
+
	while ((linelen = getline(&line, &linecap, f)) > 0) {
+
		if (comment == NULL) {
+
			if (*line == '#') {
+
				trigger_exec = &trigger_execute_shell;
+
				comment = "#";
+
			} else {
+
				trigger_exec = &trigger_execute_lua;
+
				comment = "--";
+
			}
+
		}
+
		walk = line;
+
		walk += strlen(comment);
+
		if (strncmp(walk, "sandbox", 7) == 0) {
+
			sandbox = true;
+
			continue;
+
		}
+
		if (strncmp(walk, "begin args", 10) == 0) {
+
			inargs = true;
+
			continue;
+
		}
+
		if (strncmp(walk, "end args", 8) == 0) {
+
			inargs = false;
+
			script = xstring_new();
+
			continue;
+
		}
+
		if (inargs) {
+
			walk++; /* skip the space */
+
			if (line[linelen -1] == '\n')
+
				line[linelen -1] = '\0';
+
			char *s = strdup(walk);
+
			kh_add(strings, args, s, s, free);
+
		}
+
		if (script != NULL)
+
			fputs(line, script->fp);
+
	}
+
	free(line);
+
	fclose(f);
+
	if (script == NULL) {
+
		kh_destroy_strings(args);
+
		return;
+
	}
+
	char *s = xstring_get(script);
+
	if (trigger_exec(s, sandbox, args) == EPKG_OK) {
+
		unlinkat(dfd, name, 0);
+
	}
+
	free(s);
+
	kh_destroy_strings(args);
+
}
+

+
int
+
pkg_execute_deferred_triggers(void)
+
{
+
	struct dirent *e;
+
	struct stat st;
+
	int dbdir = pkg_get_dbdirfd();
+

+
	int trigfd = openat(dbdir, "triggers", O_DIRECTORY);
+
	if (trigfd == -1)
+
		return (EPKG_OK);
+

+
	DIR *d = fdopendir(trigfd);
+
	if (d == NULL) {
+
		close(trigfd);
+
		pkg_emit_error("Unable to open the deferred trigger directory");
+
		return (EPKG_FATAL);
+
	}
+

+
	while ((e = readdir(d)) != NULL) {
+
		/* ignore all hiddn files */
+
		if (e->d_name[0] == '.')
+
			continue;
+
		/* only regular files are considered */
+
		if (fstatat(trigfd, e->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) {
+
			pkg_emit_errno("fstatat", e->d_name);
+
			return (EPKG_FATAL);
+
		}
+
		exec_deferred(trigfd, e->d_name);
+
	}
+
	return (EPKG_OK);
+
}
modified src/Makefile.autosetup
@@ -29,6 +29,7 @@ SRCS= add.c \
	shlib.c \
	ssh.c \
	stats.c \
+
	triggers.c \
	update.c \
	updating.c \
	upgrade.c \
modified src/main.c
@@ -112,6 +112,7 @@ static struct commands {
	{ "shell", "Opens a debug shell", exec_shell, usage_shell},
	{ "shlib", "Displays which packages link against a specific shared library", exec_shlib, usage_shlib},
	{ "stats", "Displays package database statistics", exec_stats, usage_stats},
+
	{ "triggers", "Execute deferred triggers", exec_triggers, usage_triggers},
	{ "unlock", "Unlocks a package, allowing modification or deletion", exec_unlock, usage_lock},
	{ "update", "Updates package repository catalogues", exec_update, usage_update},
	{ "updating", "Displays UPDATING information for a package", exec_updating, usage_updating},
modified src/pkgcli.h
@@ -29,6 +29,7 @@
#define _PKGCLI_H

#include <search.h>
+
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <xstring.h>
@@ -136,6 +137,10 @@ char *sanitize(char *, const char *, size_t);
int exec_stats(int, char **);
void usage_stats(void);

+
/* pkg triggers */
+
int exec_triggers(int, char **);
+
void usage_triggers(void);
+

/* pkg update */
int exec_update(int, char **);
void usage_update(void);
added src/triggers.c
@@ -0,0 +1,67 @@
+
/*-
+
 * Copyright (c) 2021 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * 
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions
+
 * are met:
+
 * 1. Redistributions of source code must retain the above copyright
+
 *    notice, this list of conditions and the following disclaimer
+
 *    in this position and unchanged.
+
 * 2. Redistributions in binary form must reproduce the above copyright
+
 *    notice, this list of conditions and the following disclaimer in the
+
 *    documentation and/or other materials provided with the distribution.
+
 * 
+
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#ifdef HAVE_CONFIG_H
+
#include "pkg_config.h"
+
#endif
+

+
#include <getopt.h>
+
#include <pkg.h>
+

+
#include "pkgcli.h"
+

+
void
+
usage_triggers(void)
+
{
+
	fprintf(stderr, "Usage: pkg truffers [-q]\n\n");
+
	fprintf(stderr, "For more information see 'pkg help triggers'.\n");
+
}
+

+
int
+
exec_triggers(int argc, char **argv)
+
{
+
	int ch;
+

+
	struct option longopts[] = {
+
		{ "quiet",	no_argument,	NULL,	'q' },
+
		{ NULL,		0,		NULL,	0   },
+
	};
+
	
+
	while ((ch = getopt_long(argc, argv, "+q", longopts, NULL)) != -1) {
+
                switch (ch) {
+
		case 'q':
+
			quiet = true;
+
			break;
+
		default:
+
			usage_triggers();
+
			return (EXIT_FAILURE);
+
		}
+
	}
+
	argv += optind;
+

+
	pkg_execute_deferred_triggers();
+

+
	return (EXIT_SUCCESS);
+
}