diff options
Diffstat (limited to 'contrib')
| -rw-r--r-- | contrib/argv0.c | 13 | ||||
| l--------- | contrib/bootlog.c | 1 | ||||
| -rw-r--r-- | contrib/bootlog.h | 100 | ||||
| -rw-r--r-- | contrib/bootlog_mmap.c | 96 | ||||
| -rw-r--r-- | contrib/bootlog_sbrk.c | 73 | ||||
| -rw-r--r-- | contrib/conditional-init.c | 47 | ||||
| -rw-r--r-- | contrib/env.c | 68 | ||||
| -rw-r--r-- | contrib/put_env.h | 27 | ||||
| -rw-r--r-- | contrib/serdo.c | 236 | ||||
| -rw-r--r-- | contrib/sleeprun.c | 65 |
10 files changed, 726 insertions, 0 deletions
diff --git a/contrib/argv0.c b/contrib/argv0.c new file mode 100644 index 0000000..e2eeb81 --- /dev/null +++ b/contrib/argv0.c @@ -0,0 +1,13 @@ +#include "../ninitfeatures.h" +#include "../error_table.h" + +int main(int argc,char **argv,char **envp) { + errmsg_iam("argv0"); + if (argc < 3) { + carp("usage: argv0", " realname program [ arg ... ]"); + return 100; + } + pathexec_run(argv[1],argv + 2,envp); + carp("unable to run ",argv[1],": ",error_string(table,errno)); + return 111; +} diff --git a/contrib/bootlog.c b/contrib/bootlog.c new file mode 120000 index 0000000..f2f9083 --- /dev/null +++ b/contrib/bootlog.c @@ -0,0 +1 @@ +bootlog_sbrk.c
\ No newline at end of file diff --git a/contrib/bootlog.h b/contrib/bootlog.h new file mode 100644 index 0000000..967ed6d --- /dev/null +++ b/contrib/bootlog.h @@ -0,0 +1,100 @@ +/* return -1 on error */ +static int xx_write(int fd, void *buf, size_t len) { + char *x = buf; + ssize_t w; + while (len) { + w = write(fd, buf, len); + if (w <= 0) { + if (w < 0 && errno == EINTR) continue; + return -1; + } + x += w; + len -= w; + } + return 0; +} + +/* return 0 if closed or error, -1 temporary error */ +static int do_io(void *buf, int len) { + int r = read(0,buf,len); + if (r<0) + if (errno != EINTR) r = 0; + if (r>0) xx_write(1,buf,r); + return r; +} + +static int mk_backup() { + if (flag_rename) { + if (rename(name, flag_rename) && errno != ENOENT) return -1; + flag_rename = 0; + } + return 0; +} + +static void write2(char *s) { write(2,s,str_len(s)); } + +int main(int argc, char **argv) { + unsigned long len=0; + int pid, pi[2]; + + for (;;) { + char *p; + argc--; + argv++; + if ((p=argv[0]) == 0 || *p != '-') break; + while (*++p) + switch (*p) { + case 'a': m |= O_APPEND; break; + case 't': m |= O_TRUNC; break; + case 'c': m |= O_CREAT; break; + case 'r': ++flag_rename; break; + case '2': ++flagstderr; break; + case '1': ++flagstdout; break; + default: + goto usage; + } + } + + if (argc<3) { + usage: + write2("usage: bootlog [-12ctar] size logfile program args...\n"); + _exit(1); + } + if (scan_ulong(argv[0], &len) == 0) goto usage; + if ((flagstderr | flagstdout) == 0) { + ++flagstdout; + ++flagstderr; + } + name=argv[1]; + + for (pid=0; pid<3; pid++) + if (fcntl(pid,F_GETFL,0) == -1) goto do_it; + + if (pipe(pi)) goto do_it; + while ((pid=fork()) < 0); + + if (pid==0) { + close(pi[1]); + while ((pid=fork()) < 0); + if (pid==0) { + dup2(pi[0],0); + close(pi[0]); + loop(len); + } + _exit(0); + } else { + close(pi[0]); + waitpid(pid, 0, 0); + if (flagstdout) { dup2(pi[1],1); } + if (flagstderr) { dup2(pi[1],2); } + close(pi[1]); + } + + do_it: + argv += 2; + pathexec_run(argv[0], argv, environ); + write2("bootlog: "); + write2(argv[0]); + write2(": exec error\n"); + _exit(127); +} diff --git a/contrib/bootlog_mmap.c b/contrib/bootlog_mmap.c new file mode 100644 index 0000000..7bd9583 --- /dev/null +++ b/contrib/bootlog_mmap.c @@ -0,0 +1,96 @@ +/* bootlog.c */ +/* diet -Os gcc -o bootlog bootlog.c -Wall -W */ + +#include <unistd.h> +#include <alloca.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> /* rename */ +#include <sys/mman.h> +#include <sys/wait.h> +#include "../ninitfeatures.h" + +static int xx_write(int fd, void *buf, size_t len); +static int do_io(void *buf, int len); +static int mk_backup(); + +struct mem { + struct mem *x; + unsigned int p; +}; + +static struct mem *last, *root; +static char *flag_rename, *name; +static int flagstderr, flagstdout, m; +int fd = -1; + +#include "../pagesize_defs.h" +#define mem_size sizeof(struct mem) +#define alloc_size (page_size - mem_size) + +void *mmap_alloc() { + struct mem *m; + m=mmap(0,page_size,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0); + if (m==(struct mem*)-1) return 0; + /* kernel must zeroed m->p and m->x */ + + if (last) last->x = m; + else root = m; + last = m; + return ((void *)m) + mem_size; +} + +static void flush_root() { + if (mk_backup()) return; + if (fd < 0) fd = open(name, O_WRONLY | m, 0644); + if (fd < 0) return; + while (root) { + void *x = root->x; + xx_write(fd, ((void *)root) + mem_size, root->p); + root->p = 0; + if (root == last) break; + munmap(root, page_size); + root = x; + } +} + +static void loop(unsigned long len) { + char *buf = 0; + int r; + if (flag_rename) { + char *d, *s = name; + d = flag_rename = alloca(str_len(name) + 5); + while (*s) *d++ = *s++; + d[0] = '~'; + d[1] = 0; + } + while (len) { + if (buf == 0 && (buf=mmap_alloc()) == 0) break; + + if (last->p >= alloc_size) { + flush_root(); + if (last->p) { buf = 0; continue; } + } + + r = do_io(buf + last->p, alloc_size - last->p); + if (r==0) break; + if (r<0) continue; + + if ((unsigned long)r > len) r = len; + last->p += r; + len -= r; + } + + if (buf==0 || len==0) { + char tmp[1024]; + while (do_io(tmp,sizeof(tmp))); + } + + mk_backup(); + flag_rename = 0; + flush_root(); + fsync(fd); + close(fd); +} + +#include "bootlog.h" diff --git a/contrib/bootlog_sbrk.c b/contrib/bootlog_sbrk.c new file mode 100644 index 0000000..525fcdc --- /dev/null +++ b/contrib/bootlog_sbrk.c @@ -0,0 +1,73 @@ +/* bootlog.c */ +/* diet -Os gcc -o bootlog bootlog.c -Wall -W */ + +#include <unistd.h> +#include <alloca.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> /* rename */ +#include <sys/wait.h> +#include "../ninitfeatures.h" +#define BRKINCR 1024 + +static int xx_write(int fd, void *buf, size_t len); +static int do_io(void *buf, int len); +static int mk_backup(); + +static char *root, *last, *end; +static char *flag_rename, *name; +static int flagstderr, flagstdout, m; +int fd = -1; + +static void *setbrk(ssize_t incr) { + void *x = sbrk(incr); + if ((void *)-1 == x) return x; + if (root == 0) root = last = x; + end = x + incr; + return 0; +} + +static void flush_root() { + if (mk_backup()) return; + if (fd < 0) fd = open(name, O_WRONLY | m, 0644); + if (fd < 0 || root==0) return; + xx_write(fd, root, last-root); + last = root; + setbrk((ssize_t)BRKINCR - (end-root)); +} + +static void loop(unsigned long len) { + int r; + if (flag_rename) { + char *d, *s = name; + d = flag_rename = alloca(str_len(name) + 5); + while (*s) *d++ = *s++; + d[0] = '~'; + d[1] = 0; + } + while (len) { + if (last >= end) flush_root(); + if (last >= end && setbrk(BRKINCR)) break; + + r = do_io(last, end - last); + if (r==0) break; + if (r<0) continue; + + if ((unsigned long)r > len) r = len; + last += r; + len -= r; + } + + if (last >= end || len==0) { + char tmp[1024]; + while (do_io(tmp,sizeof(tmp))); + } + + mk_backup(); + flag_rename = 0; + flush_root(); + fsync(fd); + close(fd); +} + +#include "bootlog.h" diff --git a/contrib/conditional-init.c b/contrib/conditional-init.c new file mode 100644 index 0000000..10c69cc --- /dev/null +++ b/contrib/conditional-init.c @@ -0,0 +1,47 @@ +#include <unistd.h> +#include <time.h> +#include <unistd.h> +#include <sys/reboot.h> +#include "../ninitfeatures.h" +#include "../uid.h" + +#define TM_OUT 1200 + +int main(int argc, char **argv) { + unsigned long ul; + char *stable, *test; + + if (argc < 4) { + carp("usage: conditional-init now /stable/init /test/init [args...]\n" + "\tnow must be the output of: date +%s"); + return 1; + } + + errmsg_argv0 = "conditional-init"; + stable=argv[2]; + test=argv[3]; + + if (scan_ulong(argv[1], &ul)==0 || ul + TM_OUT < (unsigned long)time(0)) { + carp("booting (stable): ", stable); + argv += 3; + argv[0] = stable; + execve(stable, argv, environ); + return 0; + } + + if (fork()==0) { + unsigned long deadline = (unsigned long)time(0) + TM_OUT; + while ((unsigned long)time(0) < deadline ) nano_sleep(1,0); + sync(); + set_reboot(RB_AUTOBOOT); + return 2; + } + + argv += 3; + argv[0]=test; + carp("booting (test): ", test); + execve(test, argv, environ); + nano_sleep(TM_OUT,0); /* only if test fails */ + set_reboot(RB_AUTOBOOT); + return 1; +} diff --git a/contrib/env.c b/contrib/env.c new file mode 100644 index 0000000..5bc44bd --- /dev/null +++ b/contrib/env.c @@ -0,0 +1,68 @@ +#include <unistd.h> +#include <alloca.h> +#include "../ninitfeatures.h" +#include "../djb/buffer.h" +#include "../error_table.h" + +static unsigned long env_free; +#include "put_env.h" + +#define BUFFER_1_SIZE 1200 +buffer b = BUFFER_INIT(write, 2, 0, BUFFER_1_SIZE); + +#undef die +#define die(n,...) err_b(&b,__VA_ARGS__,0); buffer_flush(&b); _exit(n) + +int main(int argc,char *argv[]) { + int i; + char *nenv, **env; + + b.x=alloca(BUFFER_1_SIZE); /* XXX if it fails bummer */ + errmsg_iam("env"); + if (environ==0) environ = argv+argc; + for (env=environ; *env; ++env) env_free++; + + env=alloca((argc+env_free+3) * sizeof (char*)); + if (env==0) { die(1, "Out of memory"); } + + byte_copy(env, (env_free+1) * sizeof(char *), environ); + environ = env; + env_free = argc; + + for (i=1; i<argc; ++i) { + char *v=argv[i]; + if (v[0]=='-') { + if (v[1]==0) { + environ[0]=0; + } else { + for (++v; *v; ++v) + switch (*v) { + case 'i': environ[0]=0; break; + case 'u': + if (v[1]) { nenv = v+1; goto do_it; } + else if (argv[++i]) { nenv = argv[i]; goto do_it; } + default: + die(1, "usage: env [-] [-i] [-u] [NAME=VALUE...] " + "[program args...]"); + } + } + } else { + if (v[str_chr(v,'=')]) { nenv = v; goto do_it; } + else { + pathexec_run(v,argv+i,environ); + die(127, "unable ro run: ",v,": ",error_string(table,errno)); + } + } + continue; + + do_it: + put_env(nenv); + } + + for (b.fd = 1; *environ; ++environ) { + buffer_puts(&b, *environ); + buffer_puts(&b, "\n"); + } + buffer_flush(&b); + return 0; +} diff --git a/contrib/put_env.h b/contrib/put_env.h new file mode 100644 index 0000000..0d817b3 --- /dev/null +++ b/contrib/put_env.h @@ -0,0 +1,27 @@ +int put_env(const char *string) { + unsigned int len, envc, remove=0; + char **ep; + + len=str_chr(string,'='); + if (string[len]==0) remove=1; + for (envc=0, ep=environ; *ep; ++ep) { + if (!byte_diff(string, len, *ep) && (*ep)[len]=='=') { + if (remove) { + for (; ep[1]; ++ep) ep[0]=ep[1]; + ep[0]=0; + ++env_free; + return 0; + } + *ep=(char *)string; + return 0; + } + ++envc; + } + if (remove==0) { + if (env_free==0) return -1; + environ[envc++]=(char*)string; + environ[envc]=0; + --env_free; + } + return 0; +} diff --git a/contrib/serdo.c b/contrib/serdo.c new file mode 100644 index 0000000..e45fb9a --- /dev/null +++ b/contrib/serdo.c @@ -0,0 +1,236 @@ +/* serdo.c + modified by Nikola Vladov + unset VAR + exit n + exec file + # comment + ps -ax # comment ps + long line \ + continues here + echo something + . file + VAR=val ... command ... + killall5 -signumber + */ + +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <time.h> +#include "../ninitfeatures.h" +#include "../error_table.h" + +struct cmd { + char *pos; + char *x; + char last; + char eof; +}; + +static unsigned int env_free, last_cmd; +static char continueonerror; +static int batch(char *s); + +#include "put_env.h" + +static char *e() { return error_string(table, errno); } + +#define str_equal(A,B) !str_diff(A,B) +#define byte_equal(A,l,B) !byte_diff(A,l,B) +#define is_space(c) *c==' ' || (unsigned int)(char)(*c - 9)<5 +#define carpsys(...) err(2,__VA_ARGS__,": ",e(),(char*)0) +#define diesys(n,...) do { err(2,__VA_ARGS__,": ",e(),(char*)0); _exit(n); } while(0) + +#define DQUOTE '"' +#define SQUOTE '\'' + +static void pr_argv(int fd, char **argv) { + char *s; + while ((s=*argv++)) { + unsigned int len = str_len(s); + if (*argv) s[len++] = ' '; + errmsg_put(fd,s,len); + } + errmsg_puts(fd,"\n"); + errmsg_puts(fd,0); +} + +static int pr_fail(char **argv) { + carpsys(argv[0]); + if (argv[1]) pr_argv(2, argv); + return -1; +} + +static void put__env(char *s) { if (put_env(s)) die(1, "Out of memory"); } + +static int spawn(char **argv) { + int i; + char *s0=argv[0], *s1=argv[1], cfg_exec=0, ignore=0; + + if (str_equal(s0,"cd")) { + if (chdir(s1)) return pr_fail(argv); + return 0; + } else if (str_equal(s0,"export") || str_equal(s0,"unset")) { + while (*++argv) put__env(*argv); + return 0; +#ifdef SERDO_WANT_echo + } else if (str_equal(s0,"echo")) { + pr_argv(1, argv+1); + return 0; +#endif + } else if (s1) { + i = x_atoi(s1); + if (str_equal(s0,"exit")) { _exit(i); } + else if (str_equal(s0,"exec")) { cfg_exec++; ++argv; } + else if (s0[0]=='.' && s0[1]==0) { return batch(s1); } +#ifdef SERDO_WANT_killall5 + else if (str_equal(s0,"killall5")) { return kill(-1,-i); } +#endif + } + + if (argv[0][0] == '-') { argv[0] += 1; ignore = 1; } + + if (last_cmd && !cfg_exec) { + struct timespec ts = { 0, 500000000 }; + while ((i=fork()) < 0) nanosleep(&ts, 0); + } else i=-1; /* don't fork */ + + if (i <= 0) { +#ifdef SERDO_WANT_environ_in_command + for (; argv[1]; put__env(*argv++)) { + s0 = argv[0]; + if (!s0[str_chr(s0,'=')]) break; + } +#endif + pathexec_run(*argv,argv,environ); + pr_fail(argv); + if (!i) _exit(-1); /* child */ + return (ignore) ? 0 : -1; + } + + if (waitpid(i,&i,0)==-1) diesys(1,"waitpid failed"); + if (ignore) return 0; + if (!WIFEXITED(i)) return -1; + return WEXITSTATUS(i); +} + +static void get_word(struct cmd *c) { + char ch, *x, *s = c->pos; + + while (is_space(s) || (*s=='\\' && s[1]=='\n')) ++s; + if (!*s) { c->eof |= 1; return; } + c->last=0; + c->x=x=s; + if (*x == '#') c->last |= 2; + + while ((ch=*s)) { + if (ch==DQUOTE || ch==SQUOTE) { + while (*++s) { /* unterminated quoted string <==> *s == 0 */ + if (*s != ch) *x++ = *s; + else { + if (s[-1] == '\\') x[-1] = ch; + else { s++; break; } + } + } + if (!*s) die(2, "syntax error: unexpected EOF"); + } + else if (ch==' ' || ch=='\n' || ch=='\t') break; + else if (ch=='\\' && s[1]=='\n') { s += 2; continue; } + else if (ch=='#') { for (; *s && *s != '\n';) s++; break; } + else *x++ = *s++; + } + while (*s==' ' || *s=='\t') ++s; + if (*s=='\n') { ++s; c->last |= 1; } + + c->pos = s; + if (!*s) c->last |= 1; + *x = 0; +} + +static char *get_argv0(struct cmd *c) { + while (1) { + get_word(c); + if (c->eof) break; + if (c->last & 2) continue; + return c->x; + } + return 0; +} + +static int get_argv(struct cmd *c) { + unsigned int k=0, len=16; + char **argv, first=0; + + argv = alloca((len+2)*sizeof(char*)); + do { + if (first) get_word(c); + else first |= 1; + if (c->eof) break; + if (c->last < 2) { /* comment */ + if (k >= len) { + char **tmp = argv; + len *= 2; + argv = alloca((len+2) * sizeof(char*)); + byte_copy(argv, k*sizeof(char*), tmp); + } + argv[k++] = c->x; + } + } while (!c->last); + argv[k] = 0; + + if (!get_argv0(c)) --last_cmd; + return spawn(argv); +} + +static int execute(struct cmd *c) { + int r = 0; + if (get_argv0(c)) { + ++last_cmd; + + while (1) { + r = get_argv(c); + if (r!=0 && !continueonerror) break; + if (c->eof) break; + } + } + return r; +} + +static int batch(char *s) { + struct cmd c; + int len, fd=open(s,O_RDONLY); + if (fd==-1 || GLOBAL_READ(fd,c.pos, len,32768)) { + carpsys("could not open ",s); + return 1; + } + close(fd); + c.pos[len] = 0; + c.eof = 0; + return execute(&c); +} + +int main(int argc,char* argv[],char* env[]) { + if (argc<2) { +#ifdef SERDO_EXEC_script + if (!access("script",O_RDONLY)) *argv-- = "script"; else +#endif + { ops: die(1,"usage: serdo [-c] file"); } + } + + if (str_equal(argv[1],"-c")) { + ++continueonerror; + ++argv; + } + if (*++argv == 0) goto ops; + errmsg_iam("serdo"); + + for (env_free=0; env[env_free];) ++env_free; + ++env_free; + environ = alloca((env_free + SERDO_MAX_NEW_ENVIRON) * sizeof(char *)); + byte_copy(environ, env_free * sizeof(char *), env); + env_free = SERDO_MAX_NEW_ENVIRON; + + return batch(*argv); +} diff --git a/contrib/sleeprun.c b/contrib/sleeprun.c new file mode 100644 index 0000000..01ea5c9 --- /dev/null +++ b/contrib/sleeprun.c @@ -0,0 +1,65 @@ +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <signal.h> +#include "../ninitfeatures.h" +#include "../error_table.h" + +int main(int argc, char **argv) { + int fd; + unsigned long now, interval, last, ul[2] = { 0, 0 }; + char tmp[32],*p; + if (argc<3) + die(1, "usage: sleeprun SleepFile interval [program args...]\n" + "usage: sleeprun -aNumber program [args...]"); + errmsg_iam(argv[0]); + + p = argv[1]; + if (p[0] == '-' && p[1] == 'a') { + scan_ulong(p+2, &interval); + if (interval) alarm(interval); + argv += 2; + goto do_it; + } + + if (read_ulongs(argv[1], ul, 2) > 0) { + errno=0; + if (kill(ul[0],0)==0 || errno != ESRCH) { + tmp[fmt_ulong(tmp, ul[0])] = 0; + carp("WARNING: a program with PID ",tmp," is running now"); + } + } + + last=ul[1]; + scan_ulong(argv[2], &interval); + now = (unsigned long)time(0); + + last += interval; + if (last > now) { + nano_sleep(last-now, 0); + now = (unsigned long)time(0); + } + + if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644)) >=0) { + p = tmp; + p += fmt_ulong(tmp, getpid()); *p++ = ':'; + p += fmt_ulong(p, now); *p++ = 0; + write(fd,tmp,p-tmp); + close(fd); + } + + argv+=3; + do_it: + if (argv[0]) { + char *argv_0 = argv[0]; + argv[0] = argv_0 + str_rchr(argv_0,'/'); + if (argv[0][0]) argv[0]++; + else argv[0]=argv_0; + + pathexec_run(argv_0,argv,environ); + carp("unable to run: ",argv_0,": ",error_string(table, errno)); + return 127; + } + return 0; +} |
