Commit 9c5236e9 authored by Baptiste Daroussin's avatar Baptiste Daroussin
Browse files

Triggers: in case rootdir is provided, defer the triggers

Save the triggers for later execution

pkg triggers will run them
parent abf8dd8f
......@@ -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
}
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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);
}
......@@ -29,6 +29,7 @@ SRCS= add.c \
shlib.c \
ssh.c \
stats.c \
triggers.c \
update.c \
updating.c \
upgrade.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},
......
......@@ -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);
......
/*-
* 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);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment