From 220534453eecc2c07ad710d72268aafd20b83138 Mon Sep 17 00:00:00 2001 From: joe Date: Fri, 8 May 2015 23:07:47 -0400 Subject: initial commit --- alloc.c | 33 ++++ alloc.h | 10 ++ alloc_re.c | 19 +++ buffer.h | 61 ++++++++ buffer_2.c | 7 + buffer_put.c | 90 +++++++++++ buffer_write.c | 9 ++ build.sh | 1 + byte.h | 15 ++ byte_chr.c | 22 +++ byte_copy.c | 16 ++ byte_diff.c | 18 +++ chpst.c | 475 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ direntry.h | 12 ++ env.c | 17 ++ env.h | 10 ++ error.c | 132 ++++++++++++++++ error.h | 33 ++++ error_str.c | 267 +++++++++++++++++++++++++++++++ fmt.h | 27 ++++ fmt_ulong.c | 15 ++ gen_alloc.h | 9 ++ gen_allocdefs.h | 36 +++++ hasflock.h | 4 + hasshsgr.h | 4 + lock.h | 10 ++ lock_ex.c | 13 ++ lock_exnb.c | 13 ++ open.h | 12 ++ open_append.c | 8 + open_read.c | 8 + openreadclose.c | 18 +++ openreadclose.h | 10 ++ pathexec.h | 11 ++ pathexec_env.c | 74 +++++++++ pathexec_run.c | 48 ++++++ prot.c | 21 +++ prot.h | 9 ++ readclose.c | 23 +++ readclose.h | 11 ++ scan.h | 30 ++++ scan_ulong.c | 16 ++ sgetopt.c | 53 +++++++ sgetopt.h | 23 +++ str.h | 16 ++ str_chr.c | 19 +++ str_diff.c | 17 ++ str_len.c | 16 ++ str_start.c | 15 ++ stralloc.h | 31 ++++ stralloc_cat.c | 9 ++ stralloc_catb.c | 14 ++ stralloc_cats.c | 10 ++ stralloc_eady.c | 8 + stralloc_opyb.c | 13 ++ stralloc_opys.c | 10 ++ stralloc_pend.c | 7 + strerr.h | 80 ++++++++++ strerr_die.c | 33 ++++ strerr_sys.c | 14 ++ subgetopt.c | 67 ++++++++ subgetopt.h | 26 ++++ uidgid.c | 74 +++++++++ uidgid.h | 18 +++ 64 files changed, 2250 insertions(+) create mode 100644 alloc.c create mode 100644 alloc.h create mode 100644 alloc_re.c create mode 100644 buffer.h create mode 100644 buffer_2.c create mode 100644 buffer_put.c create mode 100644 buffer_write.c create mode 100644 build.sh create mode 100644 byte.h create mode 100644 byte_chr.c create mode 100644 byte_copy.c create mode 100644 byte_diff.c create mode 100644 chpst.c create mode 100644 direntry.h create mode 100644 env.c create mode 100644 env.h create mode 100644 error.c create mode 100644 error.h create mode 100644 error_str.c create mode 100644 fmt.h create mode 100644 fmt_ulong.c create mode 100644 gen_alloc.h create mode 100644 gen_allocdefs.h create mode 100644 hasflock.h create mode 100644 hasshsgr.h create mode 100644 lock.h create mode 100644 lock_ex.c create mode 100644 lock_exnb.c create mode 100644 open.h create mode 100644 open_append.c create mode 100644 open_read.c create mode 100644 openreadclose.c create mode 100644 openreadclose.h create mode 100644 pathexec.h create mode 100644 pathexec_env.c create mode 100644 pathexec_run.c create mode 100644 prot.c create mode 100644 prot.h create mode 100644 readclose.c create mode 100644 readclose.h create mode 100644 scan.h create mode 100644 scan_ulong.c create mode 100644 sgetopt.c create mode 100644 sgetopt.h create mode 100644 str.h create mode 100644 str_chr.c create mode 100644 str_diff.c create mode 100644 str_len.c create mode 100644 str_start.c create mode 100644 stralloc.h create mode 100644 stralloc_cat.c create mode 100644 stralloc_catb.c create mode 100644 stralloc_cats.c create mode 100644 stralloc_eady.c create mode 100644 stralloc_opyb.c create mode 100644 stralloc_opys.c create mode 100644 stralloc_pend.c create mode 100644 strerr.h create mode 100644 strerr_die.c create mode 100644 strerr_sys.c create mode 100644 subgetopt.c create mode 100644 subgetopt.h create mode 100644 uidgid.c create mode 100644 uidgid.h diff --git a/alloc.c b/alloc.c new file mode 100644 index 0000000..c741aa4 --- /dev/null +++ b/alloc.c @@ -0,0 +1,33 @@ +/* Public domain. */ + +#include +#include "alloc.h" +#include "error.h" + +#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */ +#define SPACE 2048 /* must be multiple of ALIGNMENT */ + +typedef union { char irrelevant[ALIGNMENT]; double d; } aligned; +static aligned realspace[SPACE / ALIGNMENT]; +#define space ((char *) realspace) +static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */ + +/*@null@*//*@out@*/char *alloc(n) +unsigned int n; +{ + char *x; + n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */ + if (n <= avail) { avail -= n; return space + avail; } + x = malloc(n); + if (!x) errno = error_nomem; + return x; +} + +void alloc_free(x) +char *x; +{ + if (x >= space) + if (x < space + SPACE) + return; /* XXX: assuming that pointers are flat */ + free(x); +} diff --git a/alloc.h b/alloc.h new file mode 100644 index 0000000..21122fc --- /dev/null +++ b/alloc.h @@ -0,0 +1,10 @@ +/* Public domain. */ + +#ifndef ALLOC_H +#define ALLOC_H + +extern /*@null@*//*@out@*/char *alloc(); +extern void alloc_free(); +extern int alloc_re(); + +#endif diff --git a/alloc_re.c b/alloc_re.c new file mode 100644 index 0000000..1074609 --- /dev/null +++ b/alloc_re.c @@ -0,0 +1,19 @@ +/* Public domain. */ + +#include "alloc.h" +#include "byte.h" + +int alloc_re(x,m,n) +char **x; +unsigned int m; +unsigned int n; +{ + char *y; + + y = alloc(n); + if (!y) return 0; + byte_copy(y,m,*x); + alloc_free(*x); + *x = y; + return 1; +} diff --git a/buffer.h b/buffer.h new file mode 100644 index 0000000..8f2e572 --- /dev/null +++ b/buffer.h @@ -0,0 +1,61 @@ +/* Public domain. */ + +#ifndef BUFFER_H +#define BUFFER_H + +typedef struct buffer { + char *x; + unsigned int p; + unsigned int n; + int fd; + int (*op)(); +} buffer; + +#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } +#define BUFFER_INSIZE 8192 +#define BUFFER_OUTSIZE 8192 + +extern void buffer_init(buffer *,int (*)(),int,char *,unsigned int); + +extern int buffer_flush(buffer *); +extern int buffer_put(buffer *,const char *,unsigned int); +extern int buffer_putalign(buffer *,const char *,unsigned int); +extern int buffer_putflush(buffer *,const char *,unsigned int); +extern int buffer_puts(buffer *,const char *); +extern int buffer_putsalign(buffer *,const char *); +extern int buffer_putsflush(buffer *,const char *); + +#define buffer_PUTC(s,c) \ + ( ((s)->n != (s)->p) \ + ? ( (s)->x[(s)->p++] = (c), 0 ) \ + : buffer_put((s),&(c),1) \ + ) + +extern int buffer_get(buffer *,char *,unsigned int); +extern int buffer_bget(buffer *,char *,unsigned int); +extern int buffer_feed(buffer *); + +extern char *buffer_peek(buffer *); +extern void buffer_seek(buffer *,unsigned int); + +#define buffer_PEEK(s) ( (s)->x + (s)->n ) +#define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) + +#define buffer_GETC(s,c) \ + ( ((s)->p > 0) \ + ? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \ + : buffer_get((s),(c),1) \ + ) + +extern int buffer_copy(buffer *,buffer *); + +extern int buffer_unixread(int,char *,unsigned int); +extern int buffer_unixwrite(int,const char *,unsigned int); + +extern buffer *buffer_0; +extern buffer *buffer_0small; +extern buffer *buffer_1; +extern buffer *buffer_1small; +extern buffer *buffer_2; + +#endif diff --git a/buffer_2.c b/buffer_2.c new file mode 100644 index 0000000..f255a92 --- /dev/null +++ b/buffer_2.c @@ -0,0 +1,7 @@ +/* Public domain. */ + +#include "buffer.h" + +char buffer_2_space[256]; +static buffer it = BUFFER_INIT(buffer_unixwrite,2,buffer_2_space,sizeof buffer_2_space); +buffer *buffer_2 = ⁢ diff --git a/buffer_put.c b/buffer_put.c new file mode 100644 index 0000000..23164b3 --- /dev/null +++ b/buffer_put.c @@ -0,0 +1,90 @@ +/* Public domain. */ + +#include "buffer.h" +#include "str.h" +#include "byte.h" +#include "error.h" + +static int allwrite(int (*op)(),int fd,const char *buf,unsigned int len) +{ + int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +int buffer_flush(buffer *s) +{ + int p; + + p = s->p; + if (!p) return 0; + s->p = 0; + return allwrite(s->op,s->fd,s->x,p); +} + +int buffer_putalign(buffer *s,const char *buf,unsigned int len) +{ + unsigned int n; + + while (len > (n = s->n - s->p)) { + byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n; + if (buffer_flush(s) == -1) return -1; + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int buffer_put(buffer *s,const char *buf,unsigned int len) +{ + unsigned int n; + + n = s->n; + if (len > n - s->p) { + if (buffer_flush(s) == -1) return -1; + /* now s->p == 0 */ + if (n < BUFFER_OUTSIZE) n = BUFFER_OUTSIZE; + while (len > s->n) { + if (n > len) n = len; + if (allwrite(s->op,s->fd,buf,n) == -1) return -1; + buf += n; + len -= n; + } + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int buffer_putflush(buffer *s,const char *buf,unsigned int len) +{ + if (buffer_flush(s) == -1) return -1; + return allwrite(s->op,s->fd,buf,len); +} + +int buffer_putsalign(buffer *s,const char *buf) +{ + return buffer_putalign(s,buf,str_len(buf)); +} + +int buffer_puts(buffer *s,const char *buf) +{ + return buffer_put(s,buf,str_len(buf)); +} + +int buffer_putsflush(buffer *s,const char *buf) +{ + return buffer_putflush(s,buf,str_len(buf)); +} diff --git a/buffer_write.c b/buffer_write.c new file mode 100644 index 0000000..4ba13ef --- /dev/null +++ b/buffer_write.c @@ -0,0 +1,9 @@ +/* Public domain. */ + +#include +#include "buffer.h" + +int buffer_unixwrite(int fd,const char *buf,unsigned int len) +{ + return write(fd,buf,len); +} diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..0c8562d --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +gcc -I./runit-2.1.2/src/ -I. ./runit-2.1.2/src/chpst.c runit-2.1.2/src/pathexec_env.c runit-2.1.2/src/str_chr.c runit-2.1.2/src/sgetopt.c runit-2.1.2/src/subgetopt.c runit-2.1.2/src/pathexec_run.c runit-2.1.2/src/stralloc_catb.c runit-2.1.2/src/stralloc_cat.c runit-2.1.2/src/stralloc_cats.c runit-2.1.2/src/stralloc_eady.c runit-2.1.2/src/stralloc_opyb.c runit-2.1.2/src/stralloc_opys.c runit-2.1.2/src/stralloc_pend.c runit-2.1.2/src/byte_copy.c runit-2.1.2/src/error.c runit-2.1.2/src/error_str.c runit-2.1.2/src/strerr_sys.c runit-2.1.2/src/buffer_put.c runit-2.1.2/src/str_len.c runit-2.1.2/src/alloc_re.c runit-2.1.2/src/str_diff.c runit-2.1.2/src/strerr_die.c runit-2.1.2/src/buffer_2.c runit-2.1.2/src/scan_ulong.c runit-2.1.2/src/alloc.c runit-2.1.2/src/uidgid.c runit-2.1.2/src/buffer_write.c runit-2.1.2/src/open_append.c runit-2.1.2/src/open_read.c runit-2.1.2/src/prot.c runit-2.1.2/src/fmt_ulong.c runit-2.1.2/src/openreadclose.c runit-2.1.2/src/readclose.c runit-2.1.2/src/byte_diff.c runit-2.1.2/src/byte_chr.c runit-2.1.2/src/lock_exnb.c runit-2.1.2/src/lock_ex.c runit-2.1.2/src/env.c runit-2.1.2/src/str_start.c -ochpst -lnsl diff --git a/byte.h b/byte.h new file mode 100644 index 0000000..09aab61 --- /dev/null +++ b/byte.h @@ -0,0 +1,15 @@ +/* Public domain. */ + +#ifndef BYTE_H +#define BYTE_H + +extern unsigned int byte_chr(); +extern unsigned int byte_rchr(); +extern void byte_copy(); +extern void byte_copyr(); +extern int byte_diff(); +extern void byte_zero(); + +#define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) + +#endif diff --git a/byte_chr.c b/byte_chr.c new file mode 100644 index 0000000..fd56056 --- /dev/null +++ b/byte_chr.c @@ -0,0 +1,22 @@ +/* Public domain. */ + +#include "byte.h" + +unsigned int byte_chr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + + ch = c; + t = s; + for (;;) { + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + } + return t - s; +} diff --git a/byte_copy.c b/byte_copy.c new file mode 100644 index 0000000..74c9e4a --- /dev/null +++ b/byte_copy.c @@ -0,0 +1,16 @@ +/* Public domain. */ + +#include "byte.h" + +void byte_copy(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + for (;;) { + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + } +} diff --git a/byte_diff.c b/byte_diff.c new file mode 100644 index 0000000..0c4d17b --- /dev/null +++ b/byte_diff.c @@ -0,0 +1,18 @@ +/* Public domain. */ + +#include "byte.h" + +int byte_diff(s,n,t) +register char *s; +register unsigned int n; +register char *t; +{ + for (;;) { + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + } + return ((int)(unsigned int)(unsigned char) *s) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/chpst.c b/chpst.c new file mode 100644 index 0000000..f1b8ed9 --- /dev/null +++ b/chpst.c @@ -0,0 +1,475 @@ +#include +#include +#include +#include +#include +#include "sgetopt.h" +#include "error.h" +#include "strerr.h" +#include "str.h" +#include "uidgid.h" +#include "prot.h" +#include "strerr.h" +#include "scan.h" +#include "fmt.h" +#include "lock.h" +#include "pathexec.h" +#include "stralloc.h" +#include "byte.h" +#include "open.h" +#include "openreadclose.h" +#include "direntry.h" + +#define USAGE_MAIN " [-vP012] [-u user[:group]] [-U user[:group]] [-b argv0] [-e dir] [-/ root] [-n nice] [-l|-L lock] [-m n] [-d n] [-o n] [-p n] [-f n] [-c n] prog" +#define FATAL "chpst: fatal: " +#define WARNING "chpst: warning: " + +const char *progname; +static stralloc sa; + +void fatal(const char *m) { strerr_die3sys(111, FATAL, m, ": "); } +void fatal2(const char *m0, const char *m1) { + strerr_die5sys(111, FATAL, m0, ": ", m1, ": "); +} +void fatalx(const char *m0, const char *m1) { + strerr_die4x(111, FATAL, m0, ": ", m1); +} +void warn(const char *m) { strerr_warn2(WARNING, m, 0); } +void die_nomem() { strerr_die2x(111, FATAL, "out of memory."); } +void usage() { strerr_die4x(100, "usage: ", progname, USAGE_MAIN, "\n"); } + +char *set_user =0; +char *env_user =0; +const char *argv0 =0; +const char *env_dir =0; +unsigned int verbose =0; +unsigned int pgrp =0; +unsigned int nostdin =0; +unsigned int nostdout =0; +unsigned int nostderr =0; +long limitd =-2; +long limits =-2; +long limitl =-2; +long limita =-2; +long limito =-2; +long limitp =-2; +long limitf =-2; +long limitc =-2; +long limitr =-2; +long limitt =-2; +long nicelvl =0; +const char *lock =0; +const char *root =0; +unsigned int lockdelay; + +void suidgid(char *user, unsigned int ext) { + struct uidgid ugid; + + if (ext) { + if (! uidgids_get(&ugid, user)) { + if (*user == ':') fatalx("invalid uid/gids", user +1); + if (errno) fatal("unable to get password/group file entry"); + fatalx("unknown user/group", user); + } + } + else + if (! uidgid_get(&ugid, user)) { + if (errno) fatal("unable to get password file entry"); + fatalx("unknown account", user); + } + if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to setgroups"); + if (setgid(*ugid.gid) == -1) fatal("unable to setgid"); + if (prot_uid(ugid.uid) == -1) fatal("unable to setuid"); +} + +void euidgid(char *user, unsigned int ext) { + struct uidgid ugid; + char bufnum[FMT_ULONG]; + + if (ext) { + if (! uidgids_get(&ugid, user)) { + if (*user == ':') fatalx("invalid uid/gids", user +1); + if (errno) fatal("unable to get password/group file entry"); + fatalx("unknown user/group", user); + } + } + else + if (! uidgid_get(&ugid, user)) { + if (errno) fatal("unable to get password file entry"); + fatalx("unknown account", user); + } + bufnum[fmt_ulong(bufnum, *ugid.gid)] =0; + if (! pathexec_env("GID", bufnum)) die_nomem(); + bufnum[fmt_ulong(bufnum, ugid.uid)] =0; + if (! pathexec_env("UID", bufnum)) die_nomem(); +} + +void edir(const char *dirname) { + int wdir; + DIR *dir; + direntry *d; + int i; + + if ((wdir =open_read(".")) == -1) + fatal("unable to open current working directory"); + if (chdir(dirname)) fatal2("unable to switch to directory", dirname); + if (! (dir =opendir("."))) fatal2("unable to open directory", dirname); + for (;;) { + errno =0; + d =readdir(dir); + if (! d) { + if (errno) fatal2("unable to read directory", dirname); + break; + } + if (d->d_name[0] == '.') continue; + if (openreadclose(d->d_name, &sa, 256) == -1) { + if ((errno == error_isdir) && env_dir) { + if (verbose) + strerr_warn6(WARNING, "unable to read ", dirname, "/", + d->d_name, ": ", &strerr_sys); + continue; + } + else + strerr_die6sys(111, FATAL, "unable to read ", dirname, "/", + d->d_name, ": "); + } + if (sa.len) { + sa.len =byte_chr(sa.s, sa.len, '\n'); + while (sa.len && (sa.s[sa.len -1] == ' ' || sa.s[sa.len -1] == '\t')) + --sa.len; + for (i =0; i < sa.len; ++i) if (! sa.s[i]) sa.s[i] ='\n'; + if (! stralloc_0(&sa)) die_nomem(); + if (! pathexec_env(d->d_name, sa.s)) die_nomem(); + } + else + if (! pathexec_env(d->d_name, 0)) die_nomem(); + } + closedir(dir); + if (fchdir(wdir) == -1) fatal("unable to switch to starting directory"); + close(wdir); +} + +void slock_die(const char *m, const char *f, unsigned int x) { + if (! x) fatal2(m, f); + _exit(0); +} +void slock(const char *f, unsigned int d, unsigned int x) { + int fd; + + if ((fd =open_append(f)) == -1) slock_die("unable to open lock", f, x); + if (d) { + if (lock_ex(fd) == -1) slock_die("unable to lock", f, x); + return; + } + if (lock_exnb(fd) == -1) slock_die("unable to lock", f, x); +} + +void limit(int what, long l) { + struct rlimit r; + + if (getrlimit(what, &r) == -1) fatal("unable to getrlimit()"); + if ((l < 0) || (l > r.rlim_max)) + r.rlim_cur =r.rlim_max; + else + r.rlim_cur =l; + if (setrlimit(what, &r) == -1) fatal("unable to setrlimit()"); +} +void slimit() { + if (limitd >= -1) { +#ifdef RLIMIT_DATA + limit(RLIMIT_DATA, limitd); +#else + if (verbose) warn("system does not support RLIMIT_DATA"); +#endif + } + if (limits >= -1) { +#ifdef RLIMIT_STACK + limit(RLIMIT_STACK, limits); +#else + if (verbose) warn("system does not support RLIMIT_STACK"); +#endif + } + if (limitl >= -1) { +#ifdef RLIMIT_MEMLOCK + limit(RLIMIT_MEMLOCK, limitl); +#else + if (verbose) warn("system does not support RLIMIT_MEMLOCK"); +#endif + } + if (limita >= -1) { +#ifdef RLIMIT_VMEM + limit(RLIMIT_VMEM, limita); +#else +#ifdef RLIMIT_AS + limit(RLIMIT_AS, limita); +#else + if (verbose) + warn("system does neither support RLIMIT_VMEM nor RLIMIT_AS"); +#endif +#endif + } + if (limito >= -1) { +#ifdef RLIMIT_NOFILE + limit(RLIMIT_NOFILE, limito); +#else +#ifdef RLIMIT_OFILE + limit(RLIMIT_OFILE, limito); +#else + if (verbose) + warn("system does neither support RLIMIT_NOFILE nor RLIMIT_OFILE"); +#endif +#endif + } + if (limitp >= -1) { +#ifdef RLIMIT_NPROC + limit(RLIMIT_NPROC, limitp); +#else + if (verbose) warn("system does not support RLIMIT_NPROC"); +#endif + } + if (limitf >= -1) { +#ifdef RLIMIT_FSIZE + limit(RLIMIT_FSIZE, limitf); +#else + if (verbose) warn("system does not support RLIMIT_FSIZE"); +#endif + } + if (limitc >= -1) { +#ifdef RLIMIT_CORE + limit(RLIMIT_CORE, limitc); +#else + if (verbose) warn("system does not support RLIMIT_CORE"); +#endif + } + if (limitr >= -1) { +#ifdef RLIMIT_RSS + limit(RLIMIT_RSS, limitr); +#else + if (verbose) warn("system does not support RLIMIT_RSS"); +#endif + } + if (limitt >= -1) { +#ifdef RLIMIT_CPU + limit(RLIMIT_CPU, limitt); +#else + if (verbose) warn("system does not support RLIMIT_CPU"); +#endif + } +} + +/* argv[0] */ +void setuidgid(int, const char *const *); +void envuidgid(int, const char *const *); +void envdir(int, const char *const *); +void pgrphack(int, const char *const *); +void setlock(int, const char *const *); +void softlimit(int, const char *const *); + +int main(int argc, const char **argv) { + int opt; + int i; + unsigned long ul; + + progname =argv[0]; + for (i =str_len(progname); i; --i) + if (progname[i -1] == '/') { + progname +=i; + break; + } + if (progname[0] == 'd') ++progname; + + /* argv[0] */ + if (str_equal(progname, "setuidgid")) setuidgid(argc, argv); + if (str_equal(progname, "envuidgid")) envuidgid(argc, argv); + if (str_equal(progname, "envdir")) envdir(argc, argv); + if (str_equal(progname, "pgrphack")) pgrphack(argc, argv); + if (str_equal(progname, "setlock")) setlock(argc, argv); + if (str_equal(progname, "softlimit")) softlimit(argc, argv); + + while ((opt =getopt(argc, argv, "u:U:b:e:m:d:o:p:f:c:r:t:/:n:l:L:vP012V")) + != opteof) + switch(opt) { + case 'u': set_user =(char*)optarg; break; + case 'U': env_user =(char*)optarg; break; + case 'b': argv0 =(char*)optarg; break; + case 'e': env_dir =optarg; break; + case 'm': + if (optarg[scan_ulong(optarg, &ul)]) usage(); + limits =limitl =limita =limitd =ul; + break; + case 'd': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitd =ul; break; + case 'o': if (optarg[scan_ulong(optarg, &ul)]) usage(); limito =ul; break; + case 'p': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitp =ul; break; + case 'f': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitf =ul; break; + case 'c': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitc =ul; break; + case 'r': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitr =ul; break; + case 't': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitt =ul; break; + case '/': root =optarg; break; + case 'n': + switch (*optarg) { + case '-': + if (optarg[scan_ulong(++optarg, &ul)]) usage(); nicelvl =ul; + nicelvl *=-1; + break; + case '+': ++optarg; + default: + if (optarg[scan_ulong(optarg, &ul)]) usage(); nicelvl =ul; + break; + } + break; + case 'l': if (lock) usage(); lock =optarg; lockdelay =1; break; + case 'L': if (lock) usage(); lock =optarg; lockdelay =0; break; + case 'v': verbose =1; break; + case 'P': pgrp =1; break; + case '0': nostdin =1; break; + case '1': nostdout =1; break; + case '2': nostderr =1; break; + case 'V': strerr_warn1("$Id: f279d44141c981dd7535a12260efcf1ef7beed26 $", 0); + case '?': usage(); + } + argv +=optind; + if (! argv || ! *argv) usage(); + + if (pgrp) setsid(); + if (env_dir) edir(env_dir); + if (root) { + if (chdir(root) == -1) fatal2("unable to change directory", root); + if (chroot(".") == -1) fatal("unable to change root directory"); + } + if (nicelvl) { + errno =0; + if (nice(nicelvl) == -1) if (errno) fatal("unable to set nice level"); + } + if (env_user) euidgid(env_user, 1); + if (set_user) suidgid(set_user, 1); + if (lock) slock(lock, lockdelay, 0); + if (nostdin) if (close(0) == -1) fatal("unable to close stdin"); + if (nostdout) if (close(1) == -1) fatal("unable to close stdout"); + if (nostderr) if (close(2) == -1) fatal("unable to close stderr"); + slimit(); + + progname =*argv; + if (argv0) *argv =argv0; + pathexec_env_run(progname, argv); + fatal2("unable to run", *argv); + return(0); +} + +/* argv[0] */ +#define USAGE_SETUIDGID " account child" +#define USAGE_ENVUIDGID " account child" +#define USAGE_ENVDIR " dir child" +#define USAGE_PGRPHACK " child" +#define USAGE_SETLOCK " [ -nNxX ] file program [ arg ... ]" +#define USAGE_SOFTLIMIT " [-a allbytes] [-c corebytes] [-d databytes] [-f filebytes] [-l lockbytes] [-m membytes] [-o openfiles] [-p processes] [-r residentbytes] [-s stackbytes] [-t cpusecs] child" + +void setuidgid_usage() { + strerr_die4x(100, "usage: ", progname, USAGE_SETUIDGID, "\n"); +} +void setuidgid(int argc, const char *const *argv) { + const char *account; + + if (! (account =*++argv)) setuidgid_usage(); + if (! *++argv) setuidgid_usage(); + suidgid((char*)account, 0); + pathexec(argv); + fatal2("unable to run", *argv); +} + +void envuidgid_usage() { + strerr_die4x(100, "usage: ", progname, USAGE_ENVUIDGID, "\n"); +} +void envuidgid(int argc, const char *const *argv) { + const char *account; + + if (! (account =*++argv)) envuidgid_usage(); + if (! *++argv) envuidgid_usage(); + euidgid((char*)account, 0); + pathexec(argv); + fatal2("unable to run", *argv); +} + +void envdir_usage() { + strerr_die4x(100, "usage: ", progname, USAGE_ENVDIR, "\n"); +} +void envdir(int argc, const char *const *argv) { + const char *dir; + + if (! (dir =*++argv)) envdir_usage(); + if (! *++argv) envdir_usage(); + edir(dir); + pathexec(argv); + fatal2("unable to run", *argv); +} + +void pgrphack_usage() { + strerr_die4x(100, "usage: ", progname, USAGE_PGRPHACK, "\n"); +} +void pgrphack(int argc, const char *const *argv) { + if (! *++argv) pgrphack_usage(); + setsid(); + pathexec(argv); + fatal2("unable to run", *argv); +} + +void setlock_usage() { + strerr_die4x(100, "usage: ", progname, USAGE_SETLOCK, "\n"); +} +void setlock(int argc, const char *const *argv) { + int opt; + unsigned int delay =0; + unsigned int x =0; + const char *fn; + + while ((opt =getopt(argc, argv, "nNxX")) != opteof) + switch(opt) { + case 'n': delay =1; break; + case 'N': delay =0; break; + case 'x': x =1; break; + case 'X': x =0; break; + default: setlock_usage(); + } + argv +=optind; + if (! (fn =*argv)) setlock_usage(); + if (! *++argv) setlock_usage(); + + slock(fn, delay, x); + pathexec(argv); + if (! x) fatal2("unable to run", *argv); + _exit(0); +} + +void softlimit_usage() { + strerr_die4x(100, "usage: ", progname, USAGE_SOFTLIMIT, "\n"); +} +void getlarg(long *l) { + unsigned long ul; + + if (str_equal(optarg, "=")) { *l =-1; return; } + if (optarg[scan_ulong(optarg, &ul)]) usage(); + *l =ul; +} +void softlimit(int argc, const char *const *argv) { + int opt; + + while ((opt =getopt(argc,argv,"a:c:d:f:l:m:o:p:r:s:t:")) != opteof) + switch(opt) { + case '?': softlimit_usage(); + case 'a': getlarg(&limita); break; + case 'c': getlarg(&limitc); break; + case 'd': getlarg(&limitd); break; + case 'f': getlarg(&limitf); break; + case 'l': getlarg(&limitl); break; + case 'm': getlarg(&limitd); limits =limitl =limita =limitd; break; + case 'o': getlarg(&limito); break; + case 'p': getlarg(&limitp); break; + case 'r': getlarg(&limitr); break; + case 's': getlarg(&limits); break; + case 't': getlarg(&limitt); break; + } + argv +=optind; + if (!*argv) softlimit_usage(); + slimit(); + pathexec(argv); + fatal2("unable to run", *argv); +} diff --git a/direntry.h b/direntry.h new file mode 100644 index 0000000..bfd4d19 --- /dev/null +++ b/direntry.h @@ -0,0 +1,12 @@ +/* Public domain. */ + +#ifndef DIRENTRY_H +#define DIRENTRY_H + +/* sysdep: +dirent */ + +#include +#include +#define direntry struct dirent + +#endif diff --git a/env.c b/env.c new file mode 100644 index 0000000..1b3ef62 --- /dev/null +++ b/env.c @@ -0,0 +1,17 @@ +/* Public domain. */ + +#include "str.h" +#include "env.h" + +extern /*@null@*/char *env_get(const char *s) +{ + int i; + unsigned int len; + + if (!s) return 0; + len = str_len(s); + for (i = 0;environ[i];++i) + if (str_start(environ[i],s) && (environ[i][len] == '=')) + return environ[i] + len + 1; + return 0; +} diff --git a/env.h b/env.h new file mode 100644 index 0000000..834d331 --- /dev/null +++ b/env.h @@ -0,0 +1,10 @@ +/* Public domain. */ + +#ifndef ENV_H +#define ENV_H + +extern char **environ; + +extern /*@null@*/char *env_get(const char *); + +#endif diff --git a/error.c b/error.c new file mode 100644 index 0000000..ea5f9c2 --- /dev/null +++ b/error.c @@ -0,0 +1,132 @@ +/* Public domain. */ + +#include +#include "error.h" + +/* warning: as coverage improves here, should update error_{str,temp} */ + +int error_intr = +#ifdef EINTR +EINTR; +#else +-1; +#endif + +int error_nomem = +#ifdef ENOMEM +ENOMEM; +#else +-2; +#endif + +int error_noent = +#ifdef ENOENT +ENOENT; +#else +-3; +#endif + +int error_txtbsy = +#ifdef ETXTBSY +ETXTBSY; +#else +-4; +#endif + +int error_io = +#ifdef EIO +EIO; +#else +-5; +#endif + +int error_exist = +#ifdef EEXIST +EEXIST; +#else +-6; +#endif + +int error_timeout = +#ifdef ETIMEDOUT +ETIMEDOUT; +#else +-7; +#endif + +int error_inprogress = +#ifdef EINPROGRESS +EINPROGRESS; +#else +-8; +#endif + +int error_wouldblock = +#ifdef EWOULDBLOCK +EWOULDBLOCK; +#else +-9; +#endif + +int error_again = +#ifdef EAGAIN +EAGAIN; +#else +-10; +#endif + +int error_pipe = +#ifdef EPIPE +EPIPE; +#else +-11; +#endif + +int error_perm = +#ifdef EPERM +EPERM; +#else +-12; +#endif + +int error_acces = +#ifdef EACCES +EACCES; +#else +-13; +#endif + +int error_nodevice = +#ifdef ENXIO +ENXIO; +#else +-14; +#endif + +int error_proto = +#ifdef EPROTO +EPROTO; +#else +-15; +#endif + +int error_isdir = +#ifdef EISDIR +EISDIR; +#else +-16; +#endif + +int error_connrefused = +#ifdef ECONNREFUSED +ECONNREFUSED; +#else +-17; +#endif + +int error_notdir = +#ifdef ENOTDIR +ENOTDIR; +#else +-18; +#endif diff --git a/error.h b/error.h new file mode 100644 index 0000000..8ecb400 --- /dev/null +++ b/error.h @@ -0,0 +1,33 @@ +/* Public domain. */ + +#ifndef ERROR_H +#define ERROR_H + +/* 20030124: include -upcoming glibc changes */ +#include + +/* extern int errno; */ + +extern int error_intr; +extern int error_nomem; +extern int error_noent; +extern int error_txtbsy; +extern int error_io; +extern int error_exist; +extern int error_timeout; +extern int error_inprogress; +extern int error_wouldblock; +extern int error_again; +extern int error_pipe; +extern int error_perm; +extern int error_acces; +extern int error_nodevice; +extern int error_proto; +extern int error_isdir; +extern int error_connrefused; +extern int error_notdir; + +extern const char *error_str(int); +extern int error_temp(int); + +#endif diff --git a/error_str.c b/error_str.c new file mode 100644 index 0000000..e002efe --- /dev/null +++ b/error_str.c @@ -0,0 +1,267 @@ +/* Public domain. */ + +#include +#include "error.h" + +#define X(e,s) if (i == e) return s; + +const char *error_str(int i) +{ + X(0,"no error") + X(error_intr,"interrupted system call") + X(error_nomem,"out of memory") + X(error_noent,"file does not exist") + X(error_txtbsy,"text busy") + X(error_io,"input/output error") + X(error_exist,"file already exists") + X(error_timeout,"timed out") + X(error_inprogress,"operation in progress") + X(error_again,"temporary failure") + X(error_wouldblock,"input/output would block") + X(error_pipe,"broken pipe") + X(error_perm,"permission denied") + X(error_acces,"access denied") + X(error_nodevice,"device not configured") + X(error_proto,"protocol error") + X(error_isdir,"is a directory") + X(error_connrefused,"connection refused") + X(error_notdir,"not a directory") +#ifdef ESRCH + X(ESRCH,"no such process") +#endif +#ifdef E2BIG + X(E2BIG,"argument list too long") +#endif +#ifdef ENOEXEC + X(ENOEXEC,"exec format error") +#endif +#ifdef EBADF + X(EBADF,"file descriptor not open") +#endif +#ifdef ECHILD + X(ECHILD,"no child processes") +#endif +#ifdef EDEADLK + X(EDEADLK,"operation would cause deadlock") +#endif +#ifdef EFAULT + X(EFAULT,"bad address") +#endif +#ifdef ENOTBLK + X(ENOTBLK,"not a block device") +#endif +#ifdef EBUSY + X(EBUSY,"device busy") +#endif +#ifdef EXDEV + X(EXDEV,"cross-device link") +#endif +#ifdef ENODEV + X(ENODEV,"device does not support operation") +#endif +#ifdef EINVAL + X(EINVAL,"invalid argument") +#endif +#ifdef ENFILE + X(ENFILE,"system cannot open more files") +#endif +#ifdef EMFILE + X(EMFILE,"process cannot open more files") +#endif +#ifdef ENOTTY + X(ENOTTY,"not a tty") +#endif +#ifdef EFBIG + X(EFBIG,"file too big") +#endif +#ifdef ENOSPC + X(ENOSPC,"out of disk space") +#endif +#ifdef ESPIPE + X(ESPIPE,"unseekable descriptor") +#endif +#ifdef EROFS + X(EROFS,"read-only file system") +#endif +#ifdef EMLINK + X(EMLINK,"too many links") +#endif +#ifdef EDOM + X(EDOM,"input out of range") +#endif +#ifdef ERANGE + X(ERANGE,"output out of range") +#endif +#ifdef EALREADY + X(EALREADY,"operation already in progress") +#endif +#ifdef ENOTSOCK + X(ENOTSOCK,"not a socket") +#endif +#ifdef EDESTADDRREQ + X(EDESTADDRREQ,"destination address required") +#endif +#ifdef EMSGSIZE + X(EMSGSIZE,"message too long") +#endif +#ifdef EPROTOTYPE + X(EPROTOTYPE,"incorrect protocol type") +#endif +#ifdef ENOPROTOOPT + X(ENOPROTOOPT,"protocol not available") +#endif +#ifdef EPROTONOSUPPORT + X(EPROTONOSUPPORT,"protocol not supported") +#endif +#ifdef ESOCKTNOSUPPORT + X(ESOCKTNOSUPPORT,"socket type not supported") +#endif +#ifdef EOPNOTSUPP + X(EOPNOTSUPP,"operation not supported") +#endif +#ifdef EPFNOSUPPORT + X(EPFNOSUPPORT,"protocol family not supported") +#endif +#ifdef EAFNOSUPPORT + X(EAFNOSUPPORT,"address family not supported") +#endif +#ifdef EADDRINUSE + X(EADDRINUSE,"address already used") +#endif +#ifdef EADDRNOTAVAIL + X(EADDRNOTAVAIL,"address not available") +#endif +#ifdef ENETDOWN + X(ENETDOWN,"network down") +#endif +#ifdef ENETUNREACH + X(ENETUNREACH,"network unreachable") +#endif +#ifdef ENETRESET + X(ENETRESET,"network reset") +#endif +#ifdef ECONNABORTED + X(ECONNABORTED,"connection aborted") +#endif +#ifdef ECONNRESET + X(ECONNRESET,"connection reset") +#endif +#ifdef ENOBUFS + X(ENOBUFS,"out of buffer space") +#endif +#ifdef EISCONN + X(EISCONN,"already connected") +#endif +#ifdef ENOTCONN + X(ENOTCONN,"not connected") +#endif +#ifdef ESHUTDOWN + X(ESHUTDOWN,"socket shut down") +#endif +#ifdef ETOOMANYREFS + X(ETOOMANYREFS,"too many references") +#endif +#ifdef ELOOP + X(ELOOP,"symbolic link loop") +#endif +#ifdef ENAMETOOLONG + X(ENAMETOOLONG,"file name too long") +#endif +#ifdef EHOSTDOWN + X(EHOSTDOWN,"host down") +#endif +#ifdef EHOSTUNREACH + X(EHOSTUNREACH,"host unreachable") +#endif +#ifdef ENOTEMPTY + X(ENOTEMPTY,"directory not empty") +#endif +#ifdef EPROCLIM + X(EPROCLIM,"too many processes") +#endif +#ifdef EUSERS + X(EUSERS,"too many users") +#endif +#ifdef EDQUOT + X(EDQUOT,"disk quota exceeded") +#endif +#ifdef ESTALE + X(ESTALE,"stale NFS file handle") +#endif +#ifdef EREMOTE + X(EREMOTE,"too many levels of remote in path") +#endif +#ifdef EBADRPC + X(EBADRPC,"RPC structure is bad") +#endif +#ifdef ERPCMISMATCH + X(ERPCMISMATCH,"RPC version mismatch") +#endif +#ifdef EPROGUNAVAIL + X(EPROGUNAVAIL,"RPC program unavailable") +#endif +#ifdef EPROGMISMATCH + X(EPROGMISMATCH,"program version mismatch") +#endif +#ifdef EPROCUNAVAIL + X(EPROCUNAVAIL,"bad procedure for program") +#endif +#ifdef ENOLCK + X(ENOLCK,"no locks available") +#endif +#ifdef ENOSYS + X(ENOSYS,"system call not available") +#endif +#ifdef EFTYPE + X(EFTYPE,"bad file type") +#endif +#ifdef EAUTH + X(EAUTH,"authentication error") +#endif +#ifdef ENEEDAUTH + X(ENEEDAUTH,"not authenticated") +#endif +#ifdef ENOSTR + X(ENOSTR,"not a stream device") +#endif +#ifdef ETIME + X(ETIME,"timer expired") +#endif +#ifdef ENOSR + X(ENOSR,"out of stream resources") +#endif +#ifdef ENOMSG + X(ENOMSG,"no message of desired type") +#endif +#ifdef EBADMSG + X(EBADMSG,"bad message type") +#endif +#ifdef EIDRM + X(EIDRM,"identifier removed") +#endif +#ifdef ENONET + X(ENONET,"machine not on network") +#endif +#ifdef ERREMOTE + X(ERREMOTE,"object not local") +#endif +#ifdef ENOLINK + X(ENOLINK,"link severed") +#endif +#ifdef EADV + X(EADV,"advertise error") +#endif +#ifdef ESRMNT + X(ESRMNT,"srmount error") +#endif +#ifdef ECOMM + X(ECOMM,"communication error") +#endif +#ifdef EMULTIHOP + X(EMULTIHOP,"multihop attempted") +#endif +#ifdef EREMCHG + X(EREMCHG,"remote address changed") +#endif + return "unknown error"; +} diff --git a/fmt.h b/fmt.h new file mode 100644 index 0000000..8847fa6 --- /dev/null +++ b/fmt.h @@ -0,0 +1,27 @@ +/* Public domain. */ + +#ifndef FMT_H +#define FMT_H + +#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ +#define FMT_LEN ((char *) 0) /* convenient abbreviation */ + +extern unsigned int fmt_uint(char *,unsigned int); +extern unsigned int fmt_uint0(char *,unsigned int,unsigned int); +extern unsigned int fmt_xint(char *,unsigned int); +extern unsigned int fmt_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int); +extern unsigned int fmt_ushort(char *,unsigned short); +extern unsigned int fmt_xshort(char *,unsigned short); +extern unsigned int fmt_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short); +extern unsigned int fmt_ulong(char *,unsigned long); +extern unsigned int fmt_xlong(char *,unsigned long); +extern unsigned int fmt_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long); + +extern unsigned int fmt_plusminus(char *,int); +extern unsigned int fmt_minus(char *,int); +extern unsigned int fmt_0x(char *,int); + +extern unsigned int fmt_str(char *,const char *); +extern unsigned int fmt_strn(char *,const char *,unsigned int); + +#endif diff --git a/fmt_ulong.c b/fmt_ulong.c new file mode 100644 index 0000000..168572f --- /dev/null +++ b/fmt_ulong.c @@ -0,0 +1,15 @@ +/* Public domain. */ + +#include "fmt.h" + +unsigned int fmt_ulong(register char *s,register unsigned long u) +{ + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 9) { ++len; q /= 10; } + if (s) { + s += len; + do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ + } + return len; +} diff --git a/gen_alloc.h b/gen_alloc.h new file mode 100644 index 0000000..bd55e5b --- /dev/null +++ b/gen_alloc.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef GEN_ALLOC_H +#define GEN_ALLOC_H + +#define GEN_ALLOC_typedef(ta,type,field,len,a) \ + typedef struct ta { type *field; unsigned int len; unsigned int a; } ta; + +#endif diff --git a/gen_allocdefs.h b/gen_allocdefs.h new file mode 100644 index 0000000..3afd92b --- /dev/null +++ b/gen_allocdefs.h @@ -0,0 +1,36 @@ +/* Public domain. */ + +#ifndef GEN_ALLOC_DEFS_H +#define GEN_ALLOC_DEFS_H + +#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \ +int ta_ready(register ta *x,register unsigned int n) \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \ +int ta_rplus(register ta *x,register unsigned int n) \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; n += x->len; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \ +int ta_append(register ta *x,register const type *i) \ +{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; } + +#endif diff --git a/hasflock.h b/hasflock.h new file mode 100644 index 0000000..1878f64 --- /dev/null +++ b/hasflock.h @@ -0,0 +1,4 @@ +/* Public domain. */ + +/* sysdep: +flock */ +#define HASFLOCK 1 diff --git a/hasshsgr.h b/hasshsgr.h new file mode 100644 index 0000000..5624ed0 --- /dev/null +++ b/hasshsgr.h @@ -0,0 +1,4 @@ +/* Public domain. */ + +/* sysdep: +shortsetgroups */ +#define HASSHORTSETGROUPS 1 diff --git a/lock.h b/lock.h new file mode 100644 index 0000000..4a96cdc --- /dev/null +++ b/lock.h @@ -0,0 +1,10 @@ +/* Public domain. */ + +#ifndef LOCK_H +#define LOCK_H + +extern int lock_ex(int); +extern int lock_un(int); +extern int lock_exnb(int); + +#endif diff --git a/lock_ex.c b/lock_ex.c new file mode 100644 index 0000000..b75a764 --- /dev/null +++ b/lock_ex.c @@ -0,0 +1,13 @@ +/* Public domain. */ + +#include +#include +#include +#include "hasflock.h" +#include "lock.h" + +#ifdef HASFLOCK +int lock_ex(int fd) { return flock(fd,LOCK_EX); } +#else +int lock_ex(int fd) { return lockf(fd,1,0); } +#endif diff --git a/lock_exnb.c b/lock_exnb.c new file mode 100644 index 0000000..9ec2b9c --- /dev/null +++ b/lock_exnb.c @@ -0,0 +1,13 @@ +/* Public domain. */ + +#include +#include +#include +#include "hasflock.h" +#include "lock.h" + +#ifdef HASFLOCK +int lock_exnb(int fd) { return flock(fd,LOCK_EX | LOCK_NB); } +#else +int lock_exnb(int fd) { return lockf(fd,2,0); } +#endif diff --git a/open.h b/open.h new file mode 100644 index 0000000..9939663 --- /dev/null +++ b/open.h @@ -0,0 +1,12 @@ +/* Public domain. */ + +#ifndef OPEN_H +#define OPEN_H + +extern int open_read(const char *); +extern int open_excl(const char *); +extern int open_append(const char *); +extern int open_trunc(const char *); +extern int open_write(const char *); + +#endif diff --git a/open_append.c b/open_append.c new file mode 100644 index 0000000..d1b241b --- /dev/null +++ b/open_append.c @@ -0,0 +1,8 @@ +/* Public domain. */ + +#include +#include +#include "open.h" + +int open_append(const char *fn) +{ return open(fn,O_WRONLY | O_NDELAY | O_APPEND | O_CREAT,0600); } diff --git a/open_read.c b/open_read.c new file mode 100644 index 0000000..99b3cd1 --- /dev/null +++ b/open_read.c @@ -0,0 +1,8 @@ +/* Public domain. */ + +#include +#include +#include "open.h" + +int open_read(const char *fn) +{ return open(fn,O_RDONLY | O_NDELAY); } diff --git a/openreadclose.c b/openreadclose.c new file mode 100644 index 0000000..635933b --- /dev/null +++ b/openreadclose.c @@ -0,0 +1,18 @@ +/* Public domain. */ + +#include "error.h" +#include "open.h" +#include "readclose.h" +#include "openreadclose.h" + +int openreadclose(const char *fn,stralloc *sa,unsigned int bufsize) +{ + int fd; + fd = open_read(fn); + if (fd == -1) { + if (errno == error_noent) return 0; + return -1; + } + if (readclose(fd,sa,bufsize) == -1) return -1; + return 1; +} diff --git a/openreadclose.h b/openreadclose.h new file mode 100644 index 0000000..728899c --- /dev/null +++ b/openreadclose.h @@ -0,0 +1,10 @@ +/* Public domain. */ + +#ifndef OPENREADCLOSE_H +#define OPENREADCLOSE_H + +#include "stralloc.h" + +extern int openreadclose(const char *,stralloc *,unsigned int); + +#endif diff --git a/pathexec.h b/pathexec.h new file mode 100644 index 0000000..d46ab17 --- /dev/null +++ b/pathexec.h @@ -0,0 +1,11 @@ +/* Public domain. */ + +#ifndef PATHEXEC_H +#define PATHEXEC_H + +extern void pathexec_run(const char *,const char * const *,const char * const *); +extern int pathexec_env(const char *,const char *); +extern void pathexec_env_run(const char *, const char * const *); +extern void pathexec(const char * const *); + +#endif diff --git a/pathexec_env.c b/pathexec_env.c new file mode 100644 index 0000000..1305469 --- /dev/null +++ b/pathexec_env.c @@ -0,0 +1,74 @@ +/* Public domain. */ + +#include "stralloc.h" +#include "alloc.h" +#include "str.h" +#include "byte.h" +#include "env.h" +#include "pathexec.h" + +static stralloc plus; +static stralloc tmp; + +int pathexec_env(const char *s,const char *t) +{ + if (!s) return 1; + if (!stralloc_copys(&tmp,s)) return 0; + if (t) { + if (!stralloc_cats(&tmp,"=")) return 0; + if (!stralloc_cats(&tmp,t)) return 0; + } + if (!stralloc_0(&tmp)) return 0; + return stralloc_cat(&plus,&tmp); +} + +void pathexec_env_run(const char *file, const char *const *argv) +{ + const char **e; + unsigned int elen; + unsigned int i; + unsigned int j; + unsigned int split; + unsigned int t; + + if (!stralloc_cats(&plus,"")) return; + + elen = 0; + for (i = 0;environ[i];++i) + ++elen; + for (i = 0;i < plus.len;++i) + if (!plus.s[i]) + ++elen; + + e = (const char **) alloc((elen + 1) * sizeof(char *)); + if (!e) return; + + elen = 0; + for (i = 0;environ[i];++i) + e[elen++] = environ[i]; + + j = 0; + for (i = 0;i < plus.len;++i) + if (!plus.s[i]) { + split = str_chr(plus.s + j,'='); + for (t = 0;t < elen;++t) + if (byte_equal(plus.s + j,split,e[t])) + if (e[t][split] == '=') { + --elen; + e[t] = e[elen]; + break; + } + if (plus.s[j + split]) + e[elen++] = plus.s + j; + j = i + 1; + } + e[elen] = 0; + + pathexec_run(file,argv,e); + alloc_free(e); +} + +void pathexec(const char *const *argv) +{ + return pathexec_env_run(*argv, argv); +} diff --git a/pathexec_run.c b/pathexec_run.c new file mode 100644 index 0000000..1770ac7 --- /dev/null +++ b/pathexec_run.c @@ -0,0 +1,48 @@ +/* Public domain. */ + +#include "error.h" +#include "stralloc.h" +#include "str.h" +#include "env.h" +#include "pathexec.h" + +static stralloc tmp; + +void pathexec_run(const char *file,const char * const *argv,const char * const *envp) +{ + const char *path; + unsigned int split; + int savederrno; + + if (file[str_chr(file,'/')]) { + execve(file,argv,envp); + return; + } + + path = env_get("PATH"); + if (!path) path = "/bin:/usr/bin"; + + savederrno = 0; + for (;;) { + split = str_chr(path,':'); + if (!stralloc_copyb(&tmp,path,split)) return; + if (!split) + if (!stralloc_cats(&tmp,".")) return; + if (!stralloc_cats(&tmp,"/")) return; + if (!stralloc_cats(&tmp,file)) return; + if (!stralloc_0(&tmp)) return; + + execve(tmp.s,argv,envp); + if (errno != error_noent) { + savederrno = errno; + if ((errno != error_acces) && (errno != error_perm) && (errno != error_isdir)) return; + } + + if (!path[split]) { + if (savederrno) errno = savederrno; + return; + } + path += split; + path += 1; + } +} diff --git a/prot.c b/prot.c new file mode 100644 index 0000000..79a88c5 --- /dev/null +++ b/prot.c @@ -0,0 +1,21 @@ +/* Public domain. */ + +#include "hasshsgr.h" +#include "prot.h" + +int prot_gid(int gid) +{ +#ifdef HASSHORTSETGROUPS + short x[2]; + x[0] = gid; x[1] = 73; /* catch errors */ + if (setgroups(1,x) == -1) return -1; +#else + if (setgroups(1,&gid) == -1) return -1; +#endif + return setgid(gid); /* _should_ be redundant, but on some systems it isn't */ +} + +int prot_uid(int uid) +{ + return setuid(uid); +} diff --git a/prot.h b/prot.h new file mode 100644 index 0000000..2e5cb81 --- /dev/null +++ b/prot.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef PROT_H +#define PROT_H + +extern int prot_gid(int); +extern int prot_uid(int); + +#endif diff --git a/readclose.c b/readclose.c new file mode 100644 index 0000000..9d83007 --- /dev/null +++ b/readclose.c @@ -0,0 +1,23 @@ +/* Public domain. */ + +#include +#include "error.h" +#include "readclose.h" + +int readclose_append(int fd,stralloc *sa,unsigned int bufsize) +{ + int r; + for (;;) { + if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; } + r = read(fd,sa->s + sa->len,bufsize); + if (r == -1) if (errno == error_intr) continue; + if (r <= 0) { close(fd); return r; } + sa->len += r; + } +} + +int readclose(int fd,stralloc *sa,unsigned int bufsize) +{ + if (!stralloc_copys(sa,"")) { close(fd); return -1; } + return readclose_append(fd,sa,bufsize); +} diff --git a/readclose.h b/readclose.h new file mode 100644 index 0000000..bde9889 --- /dev/null +++ b/readclose.h @@ -0,0 +1,11 @@ +/* Public domain. */ + +#ifndef READCLOSE_H +#define READCLOSE_H + +#include "stralloc.h" + +extern int readclose_append(int,stralloc *,unsigned int); +extern int readclose(int,stralloc *,unsigned int); + +#endif diff --git a/scan.h b/scan.h new file mode 100644 index 0000000..3db49d3 --- /dev/null +++ b/scan.h @@ -0,0 +1,30 @@ +/* Public domain. */ + +#ifndef SCAN_H +#define SCAN_H + +extern unsigned int scan_uint(const char *,unsigned int *); +extern unsigned int scan_xint(const char *,unsigned int *); +extern unsigned int scan_nbbint(const char *,unsigned int,unsigned int,unsigned int,unsigned int *); +extern unsigned int scan_ushort(const char *,unsigned short *); +extern unsigned int scan_xshort(const char *,unsigned short *); +extern unsigned int scan_nbbshort(const char *,unsigned int,unsigned int,unsigned int,unsigned short *); +extern unsigned int scan_ulong(const char *,unsigned long *); +extern unsigned int scan_xlong(const char *,unsigned long *); +extern unsigned int scan_nbblong(const char *,unsigned int,unsigned int,unsigned int,unsigned long *); + +extern unsigned int scan_plusminus(const char *,int *); +extern unsigned int scan_0x(const char *,unsigned int *); + +extern unsigned int scan_whitenskip(const char *,unsigned int); +extern unsigned int scan_nonwhitenskip(const char *,unsigned int); +extern unsigned int scan_charsetnskip(const char *,const char *,unsigned int); +extern unsigned int scan_noncharsetnskip(const char *,const char *,unsigned int); + +extern unsigned int scan_strncmp(const char *,const char *,unsigned int); +extern unsigned int scan_memcmp(const char *,const char *,unsigned int); + +extern unsigned int scan_long(const char *,long *); +extern unsigned int scan_8long(const char *,unsigned long *); + +#endif diff --git a/scan_ulong.c b/scan_ulong.c new file mode 100644 index 0000000..af19701 --- /dev/null +++ b/scan_ulong.c @@ -0,0 +1,16 @@ +/* Public domain. */ + +#include "scan.h" + +unsigned int scan_ulong(register const char *s,register unsigned long *u) +{ + register unsigned int pos = 0; + register unsigned long result = 0; + register unsigned long c; + while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) { + result = result * 10 + c; + ++pos; + } + *u = result; + return pos; +} diff --git a/sgetopt.c b/sgetopt.c new file mode 100644 index 0000000..8bb608f --- /dev/null +++ b/sgetopt.c @@ -0,0 +1,53 @@ +/* Public domain. */ + +/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer +D. J. Bernstein, djb@pobox.com. +Depends on subgetopt.h, buffer.h. +No system requirements. +19991219: Switched to buffer.h. +19970208: Cleanups. +931201: Baseline. +No known patent problems. + +Documentation in sgetopt.3. +*/ + +#include "buffer.h" +#define SGETOPTNOSHORT +#include "sgetopt.h" +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define getopt sgetoptmine +#define optind subgetoptind +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname + +int opterr = 1; +const char *optprogname = 0; + +int getopt(int argc,const char *const *argv,const char *opts) +{ + int c; + const char *s; + + if (!optprogname) { + optprogname = *argv; + if (!optprogname) optprogname = ""; + for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1; + } + c = subgetopt(argc,argv,opts); + if (opterr) + if (c == '?') { + char chp[2]; chp[0] = optproblem; chp[1] = '\n'; + buffer_puts(buffer_2,optprogname); + if (argv[optind] && (optind < argc)) + buffer_puts(buffer_2,": illegal option -- "); + else + buffer_puts(buffer_2,": option requires an argument -- "); + buffer_put(buffer_2,chp,2); + buffer_flush(buffer_2); + } + return c; +} diff --git a/sgetopt.h b/sgetopt.h new file mode 100644 index 0000000..bf8bce6 --- /dev/null +++ b/sgetopt.h @@ -0,0 +1,23 @@ +/* Public domain. */ + +#ifndef SGETOPT_H +#define SGETOPT_H + +#ifndef SGETOPTNOSHORT +#define getopt sgetoptmine +#define optarg subgetoptarg +#define optind subgetoptind +#define optpos subgetoptpos +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname +#define opteof subgetoptdone +#endif + +#include "subgetopt.h" + +extern int sgetoptmine(int,const char *const *,const char *); +extern int sgetopterr; +extern const char *sgetoptprogname; + +#endif diff --git a/str.h b/str.h new file mode 100644 index 0000000..f65b8f6 --- /dev/null +++ b/str.h @@ -0,0 +1,16 @@ +/* Public domain. */ + +#ifndef STR_H +#define STR_H + +extern unsigned int str_copy(char *,const char *); +extern int str_diff(const char *,const char *); +extern int str_diffn(const char *,const char *,unsigned int); +extern unsigned int str_len(const char *); +extern unsigned int str_chr(const char *,int); +extern unsigned int str_rchr(const char *,int); +extern int str_start(const char *,const char *); + +#define str_equal(s,t) (!str_diff((s),(t))) + +#endif diff --git a/str_chr.c b/str_chr.c new file mode 100644 index 0000000..9b467eb --- /dev/null +++ b/str_chr.c @@ -0,0 +1,19 @@ +/* Public domain. */ + +#include "str.h" + +unsigned int str_chr(register const char *s,int c) +{ + register char ch; + register const char *t; + + ch = c; + t = s; + for (;;) { + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + } + return t - s; +} diff --git a/str_diff.c b/str_diff.c new file mode 100644 index 0000000..47dff22 --- /dev/null +++ b/str_diff.c @@ -0,0 +1,17 @@ +/* Public domain. */ + +#include "str.h" + +int str_diff(register const char *s,register const char *t) +{ + register char x; + + for (;;) { + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + } + return ((int)(unsigned int)(unsigned char) x) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/str_len.c b/str_len.c new file mode 100644 index 0000000..dedd005 --- /dev/null +++ b/str_len.c @@ -0,0 +1,16 @@ +/* Public domain. */ + +#include "str.h" + +unsigned int str_len(const char *s) +{ + register const char *t; + + t = s; + for (;;) { + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + } +} diff --git a/str_start.c b/str_start.c new file mode 100644 index 0000000..017efc7 --- /dev/null +++ b/str_start.c @@ -0,0 +1,15 @@ +/* Public domain. */ + +#include "str.h" + +int str_start(register const char *s,register const char *t) +{ + register char x; + + for (;;) { + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + } +} diff --git a/stralloc.h b/stralloc.h new file mode 100644 index 0000000..51d61bd --- /dev/null +++ b/stralloc.h @@ -0,0 +1,31 @@ +/* Public domain. */ + +#ifndef STRALLOC_H +#define STRALLOC_H + +#include "gen_alloc.h" + +GEN_ALLOC_typedef(stralloc,char,s,len,a) + +extern int stralloc_ready(stralloc *,unsigned int); +extern int stralloc_readyplus(stralloc *,unsigned int); +extern int stralloc_copy(stralloc *,const stralloc *); +extern int stralloc_cat(stralloc *,const stralloc *); +extern int stralloc_copys(stralloc *,const char *); +extern int stralloc_cats(stralloc *,const char *); +extern int stralloc_copyb(stralloc *,const char *,unsigned int); +extern int stralloc_catb(stralloc *,const char *,unsigned int); +extern int stralloc_append(stralloc *,const char *); /* beware: this takes a pointer to 1 char */ +extern int stralloc_starts(stralloc *,const char *); + +#define stralloc_0(sa) stralloc_append(sa,"") + +extern int stralloc_catulong0(stralloc *,unsigned long,unsigned int); +extern int stralloc_catlong0(stralloc *,long,unsigned int); + +#define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0)) +#define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n))) +#define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n))) +#define stralloc_catint(sa,i) (stralloc_catlong0((sa),(i),0)) + +#endif diff --git a/stralloc_cat.c b/stralloc_cat.c new file mode 100644 index 0000000..2c6ad58 --- /dev/null +++ b/stralloc_cat.c @@ -0,0 +1,9 @@ +/* Public domain. */ + +#include "byte.h" +#include "stralloc.h" + +int stralloc_cat(stralloc *sato,const stralloc *safrom) +{ + return stralloc_catb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_catb.c b/stralloc_catb.c new file mode 100644 index 0000000..8ee0af4 --- /dev/null +++ b/stralloc_catb.c @@ -0,0 +1,14 @@ +/* Public domain. */ + +#include "stralloc.h" +#include "byte.h" + +int stralloc_catb(stralloc *sa,const char *s,unsigned int n) +{ + if (!sa->s) return stralloc_copyb(sa,s,n); + if (!stralloc_readyplus(sa,n + 1)) return 0; + byte_copy(sa->s + sa->len,n,s); + sa->len += n; + sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_cats.c b/stralloc_cats.c new file mode 100644 index 0000000..ea1e290 --- /dev/null +++ b/stralloc_cats.c @@ -0,0 +1,10 @@ +/* Public domain. */ + +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_cats(stralloc *sa,const char *s) +{ + return stralloc_catb(sa,s,str_len(s)); +} diff --git a/stralloc_eady.c b/stralloc_eady.c new file mode 100644 index 0000000..81dbb85 --- /dev/null +++ b/stralloc_eady.c @@ -0,0 +1,8 @@ +/* Public domain. */ + +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready) +GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus) diff --git a/stralloc_opyb.c b/stralloc_opyb.c new file mode 100644 index 0000000..bbcff48 --- /dev/null +++ b/stralloc_opyb.c @@ -0,0 +1,13 @@ +/* Public domain. */ + +#include "stralloc.h" +#include "byte.h" + +int stralloc_copyb(stralloc *sa,const char *s,unsigned int n) +{ + if (!stralloc_ready(sa,n + 1)) return 0; + byte_copy(sa->s,n,s); + sa->len = n; + sa->s[n] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_opys.c b/stralloc_opys.c new file mode 100644 index 0000000..075b6f8 --- /dev/null +++ b/stralloc_opys.c @@ -0,0 +1,10 @@ +/* Public domain. */ + +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_copys(stralloc *sa,const char *s) +{ + return stralloc_copyb(sa,s,str_len(s)); +} diff --git a/stralloc_pend.c b/stralloc_pend.c new file mode 100644 index 0000000..70cb55c --- /dev/null +++ b/stralloc_pend.c @@ -0,0 +1,7 @@ +/* Public domain. */ + +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) diff --git a/strerr.h b/strerr.h new file mode 100644 index 0000000..21d812d --- /dev/null +++ b/strerr.h @@ -0,0 +1,80 @@ +/* Public domain. */ + +#ifndef STRERR_H +#define STRERR_H + +struct strerr { + struct strerr *who; + const char *x; + const char *y; + const char *z; +} ; + +extern struct strerr strerr_sys; +extern void strerr_sysinit(void); + +extern const char *strerr(const struct strerr *); +extern void strerr_warn(const char *,const char *,const char *,const char *,const char *,const char *,const struct strerr *); +extern void strerr_die(int,const char *,const char *,const char *,const char *,const char *,const char *,const struct strerr *); + +#define STRERR(r,se,a) \ +{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; } + +#define STRERR_SYS(r,se,a) \ +{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; } +#define STRERR_SYS3(r,se,a,b,c) \ +{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; } + +#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(se)) +#define strerr_warn5(x1,x2,x3,x4,x5,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),0,(se)) +#define strerr_warn4(x1,x2,x3,x4,se) \ +strerr_warn((x1),(x2),(x3),(x4),0,0,(se)) +#define strerr_warn3(x1,x2,x3,se) \ +strerr_warn((x1),(x2),(x3),0,0,0,(se)) +#define strerr_warn2(x1,x2,se) \ +strerr_warn((x1),(x2),0,0,0,0,(se)) +#define strerr_warn1(x1,se) \ +strerr_warn((x1),0,0,0,0,0,(se)) + +#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(se)) +#define strerr_die5(e,x1,x2,x3,x4,x5,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,(se)) +#define strerr_die4(e,x1,x2,x3,x4,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,(se)) +#define strerr_die3(e,x1,x2,x3,se) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,(se)) +#define strerr_die2(e,x1,x2,se) \ +strerr_die((e),(x1),(x2),0,0,0,0,(se)) +#define strerr_die1(e,x1,se) \ +strerr_die((e),(x1),0,0,0,0,0,(se)) + +#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys) +#define strerr_die5sys(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,&strerr_sys) +#define strerr_die4sys(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,&strerr_sys) +#define strerr_die3sys(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,&strerr_sys) +#define strerr_die2sys(e,x1,x2) \ +strerr_die((e),(x1),(x2),0,0,0,0,&strerr_sys) +#define strerr_die1sys(e,x1) \ +strerr_die((e),(x1),0,0,0,0,0,&strerr_sys) + +#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),0) +#define strerr_die5x(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,0) +#define strerr_die4x(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,0) +#define strerr_die3x(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,0) +#define strerr_die2x(e,x1,x2) \ +strerr_die((e),(x1),(x2),0,0,0,0,0) +#define strerr_die1x(e,x1) \ +strerr_die((e),(x1),0,0,0,0,0,0) + +#endif diff --git a/strerr_die.c b/strerr_die.c new file mode 100644 index 0000000..f226b80 --- /dev/null +++ b/strerr_die.c @@ -0,0 +1,33 @@ +/* Public domain. */ + +#include +#include "buffer.h" +#include "strerr.h" + +void strerr_warn(const char *x1,const char *x2,const char *x3,const char *x4,const char *x5,const char *x6,const struct strerr *se) +{ + strerr_sysinit(); + + if (x1) buffer_puts(buffer_2,x1); + if (x2) buffer_puts(buffer_2,x2); + if (x3) buffer_puts(buffer_2,x3); + if (x4) buffer_puts(buffer_2,x4); + if (x5) buffer_puts(buffer_2,x5); + if (x6) buffer_puts(buffer_2,x6); + + while(se) { + if (se->x) buffer_puts(buffer_2,se->x); + if (se->y) buffer_puts(buffer_2,se->y); + if (se->z) buffer_puts(buffer_2,se->z); + se = se->who; + } + + buffer_puts(buffer_2,"\n"); + buffer_flush(buffer_2); +} + +void strerr_die(int e,const char *x1,const char *x2,const char *x3,const char *x4,const char *x5,const char *x6,const struct strerr *se) +{ + strerr_warn(x1,x2,x3,x4,x5,x6,se); + _exit(e); +} diff --git a/strerr_sys.c b/strerr_sys.c new file mode 100644 index 0000000..84b302f --- /dev/null +++ b/strerr_sys.c @@ -0,0 +1,14 @@ +/* Public domain. */ + +#include "error.h" +#include "strerr.h" + +struct strerr strerr_sys; + +void strerr_sysinit(void) +{ + strerr_sys.who = 0; + strerr_sys.x = error_str(errno); + strerr_sys.y = ""; + strerr_sys.z = ""; +} diff --git a/subgetopt.c b/subgetopt.c new file mode 100644 index 0000000..85ace96 --- /dev/null +++ b/subgetopt.c @@ -0,0 +1,67 @@ +/* Public domain. */ + +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define sgopt subgetopt +#define optind subgetoptind +#define optpos subgetoptpos +#define optarg subgetoptarg +#define optproblem subgetoptproblem +#define optdone subgetoptdone + +int optind = 1; +int optpos = 0; +const char *optarg = 0; +int optproblem = 0; +int optdone = SUBGETOPTDONE; + +int sgopt(int argc,const char *const *argv,const char *opts) +{ + int c; + const char *s; + + optarg = 0; + if (!argv || (optind >= argc) || !argv[optind]) return optdone; + if (optpos && !argv[optind][optpos]) { + ++optind; + optpos = 0; + if ((optind >= argc) || !argv[optind]) return optdone; + } + if (!optpos) { + if (argv[optind][0] != '-') return optdone; + ++optpos; + c = argv[optind][1]; + if ((c == '-') || (c == 0)) { + if (c) ++optind; + optpos = 0; + return optdone; + } + /* otherwise c is reassigned below */ + } + c = argv[optind][optpos]; + ++optpos; + s = opts; + while (*s) { + if (c == *s) { + if (s[1] == ':') { + optarg = argv[optind] + optpos; + ++optind; + optpos = 0; + if (!*optarg) { + optarg = argv[optind]; + if ((optind >= argc) || !optarg) { /* argument past end */ + optproblem = c; + return '?'; + } + ++optind; + } + } + return c; + } + ++s; + if (*s == ':') ++s; + } + optproblem = c; + return '?'; +} diff --git a/subgetopt.h b/subgetopt.h new file mode 100644 index 0000000..41ad26a --- /dev/null +++ b/subgetopt.h @@ -0,0 +1,26 @@ +/* Public domain. */ + +#ifndef SUBGETOPT_H +#define SUBGETOPT_H + +#ifndef SUBGETOPTNOSHORT +#define sgopt subgetopt +#define sgoptarg subgetoptarg +#define sgoptind subgetoptind +#define sgoptpos subgetoptpos +#define sgoptproblem subgetoptproblem +#define sgoptprogname subgetoptprogname +#define sgoptdone subgetoptdone +#endif + +#define SUBGETOPTDONE -1 + +extern int subgetopt(int,const char *const *,const char *); +extern const char *subgetoptarg; +extern int subgetoptind; +extern int subgetoptpos; +extern int subgetoptproblem; +extern const char *subgetoptprogname; +extern int subgetoptdone; + +#endif diff --git a/uidgid.c b/uidgid.c new file mode 100644 index 0000000..befa754 --- /dev/null +++ b/uidgid.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include "uidgid.h" +#include "str.h" +#include "scan.h" + +/* user */ +unsigned int uidgid_get(struct uidgid *u, char *ug) { + struct passwd *pwd =0; + + if (! (pwd =getpwnam(ug))) return(0); + u->gid[0] =pwd->pw_gid; u->gids =1; + u->uid =pwd->pw_uid; + return(1); +} + +/* uid:gid[:gid[:gid]...] */ +unsigned int uidgids_set(struct uidgid *u, char *ug) { + unsigned long id; + int i; + + if (*(ug +=scan_ulong(ug, &id)) != ':') return(0); + u->uid =(uid_t)id; + ++ug; + for (i =0; i < 60; ++i, ++ug) { + ug +=scan_ulong(ug, &id); + u->gid[i] =(gid_t)id; + if (*ug != ':') { ++i; break; } + } + u->gid[i] =0; + u->gids =i; + if (*ug) return(0); + return(1); +} + +/* [:]user[:group[:group]...] */ +unsigned int uidgids_get(struct uidgid *u, char *ug) { + char *g =0; + struct passwd *pwd =0; + struct group *gr =0; + int i, d =0; + + if (*ug == ':') return(uidgids_set(u, ug +1)); + if (ug[(d =str_chr(ug, ':'))] == ':') { + ug[d] =0; + g =ug +d +1; + } + if (! (pwd =getpwnam(ug))) { if (g) ug[d] =':'; return(0); } + u->uid =pwd->pw_uid; + if (! g) { + u->gid[0] =pwd->pw_gid; + u->gids =1; + return(1); + } + ug[d] =':'; + for (i =0; i < 60; ++i) { + if (g[(d =str_chr(g, ':'))] == ':') { + g[d] =0; + if (! (gr =getgrnam(g))) { g[d] =':'; return(0); } + g[d] =':'; + u->gid[i] =gr->gr_gid; + g +=d +1; + } + else { + if (! (gr =getgrnam(g))) return(0); + u->gid[i++] =gr->gr_gid; + break; + } + } + u->gid[i] =0; + u->gids =i; + return(1); +} diff --git a/uidgid.h b/uidgid.h new file mode 100644 index 0000000..13cacbc --- /dev/null +++ b/uidgid.h @@ -0,0 +1,18 @@ +#ifndef UIDGID_H +#define UIDGID_H + +#include + +struct uidgid { + uid_t uid; + gid_t gid[61]; + int gids; +}; + +/* user */ +extern unsigned int uidgid_get(struct uidgid *, char *); + +/* [:]user[:group[:group]...] */ +extern unsigned int uidgids_get(struct uidgid *, char *); + +#endif -- cgit v1.2.3