1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
/*
Copy-on-write filesystem invocation.
GPL v2 or later
Copyright 2005-2009 Junichi Uekawa.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/wait.h>
#include "ilist.h"
#include "log.h"
const char *ilist_PRGNAME = "cow-shell";
static const char *ilistpath = "./.ilist";
/*
* remove ilist after use.
*/
static void ilist_deleter(const char *ilistfile) {
if (fork() == 0) {
/* I am the child process */
pid_t parent_pid = getppid();
if (daemon(0, 1) < 0) {
log_perror("cow-shell daemon");
exit(-1);
}
while (kill(parent_pid, 0) >= 0) {
sleep(1);
}
if (unlink(ilistfile) == -1) {
log_perror("cow-shell unlink .ilist");
exit(1);
}
exit(0);
}
}
/**
* Set environment variables.
*/
static void set_env_vars() {
char *buf;
// For sending down as environment variable, use a canonicalized version.
char *canonicalized_ilistpath = canonicalize_file_name(ilistpath);
setenv("COWDANCER_ILISTFILE", canonicalized_ilistpath, 1);
unsetenv("COWDANCER_IGNORE");
free(canonicalized_ilistpath);
asprintf(&buf,
"%s%s%s",
getenv("LD_PRELOAD") ?: "",
getenv("LD_PRELOAD") ? " " : "",
getenv("COWDANCER_SO") ?: COWDANCER_SO);
setenv("LD_PRELOAD", buf, 1);
free(buf);
}
/* give me a command-line to exec,
and I will cow-keep what's under this directory. */
int main(int ac, char **av) {
struct stat st;
int cowdancer_reuse;
cowdancer_reuse =
getenv("COWDANCER_REUSE") && !strcmp(getenv("COWDANCER_REUSE"), "yes");
if (cowdancer_reuse && !stat(ilistpath, &st)) {
/* if reuse flag is on and file already exists
do nothing */
} else {
if (unlink(ilistpath) == -1) {
if (errno == ENOENT) {
/* expected */
} else {
log_perror("cow-shell: unlink of .ilist failed");
return 1;
}
}
if (ilistcreate(ilistpath, NULL)) {
ilist_outofmemory(".ilist creation failed");
return 1;
}
}
set_env_vars();
if (!cowdancer_reuse) {
/* if reuse flag is not on, remove the file */
ilist_deleter(ilistpath);
}
if (ac > 1) {
execvp(av[1], av + 1);
} else {
const char *myshell = getenv("SHELL") ?: "/bin/sh";
log_printf(log_info, "Invoking %s", myshell);
execlp(myshell, myshell, NULL);
log_perror("cow-shell: exec");
log_printf(log_warn, "Falling back to /bin/sh");
execlp("/bin/sh", "/bin/sh", NULL);
}
log_perror("cow-shell: exec");
return 1;
}
|