summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alloc.c33
-rw-r--r--alloc.h10
-rw-r--r--alloc_re.c19
-rw-r--r--buffer.h61
-rw-r--r--buffer_2.c7
-rw-r--r--buffer_put.c90
-rw-r--r--buffer_write.c9
-rw-r--r--build.sh1
-rw-r--r--byte.h15
-rw-r--r--byte_chr.c22
-rw-r--r--byte_copy.c16
-rw-r--r--byte_diff.c18
-rw-r--r--chpst.c475
-rw-r--r--direntry.h12
-rw-r--r--env.c17
-rw-r--r--env.h10
-rw-r--r--error.c132
-rw-r--r--error.h33
-rw-r--r--error_str.c267
-rw-r--r--fmt.h27
-rw-r--r--fmt_ulong.c15
-rw-r--r--gen_alloc.h9
-rw-r--r--gen_allocdefs.h36
-rw-r--r--hasflock.h4
-rw-r--r--hasshsgr.h4
-rw-r--r--lock.h10
-rw-r--r--lock_ex.c13
-rw-r--r--lock_exnb.c13
-rw-r--r--open.h12
-rw-r--r--open_append.c8
-rw-r--r--open_read.c8
-rw-r--r--openreadclose.c18
-rw-r--r--openreadclose.h10
-rw-r--r--pathexec.h11
-rw-r--r--pathexec_env.c74
-rw-r--r--pathexec_run.c48
-rw-r--r--prot.c21
-rw-r--r--prot.h9
-rw-r--r--readclose.c23
-rw-r--r--readclose.h11
-rw-r--r--scan.h30
-rw-r--r--scan_ulong.c16
-rw-r--r--sgetopt.c53
-rw-r--r--sgetopt.h23
-rw-r--r--str.h16
-rw-r--r--str_chr.c19
-rw-r--r--str_diff.c17
-rw-r--r--str_len.c16
-rw-r--r--str_start.c15
-rw-r--r--stralloc.h31
-rw-r--r--stralloc_cat.c9
-rw-r--r--stralloc_catb.c14
-rw-r--r--stralloc_cats.c10
-rw-r--r--stralloc_eady.c8
-rw-r--r--stralloc_opyb.c13
-rw-r--r--stralloc_opys.c10
-rw-r--r--stralloc_pend.c7
-rw-r--r--strerr.h80
-rw-r--r--strerr_die.c33
-rw-r--r--strerr_sys.c14
-rw-r--r--subgetopt.c67
-rw-r--r--subgetopt.h26
-rw-r--r--uidgid.c74
-rw-r--r--uidgid.h18
64 files changed, 2250 insertions, 0 deletions
diff --git a/alloc.c b/alloc.c
new file mode 100644
index 0000000..c741aa4
--- /dev/null
+++ b/alloc.c
@@ -0,0 +1,33 @@
1/* Public domain. */
2
3#include <stdlib.h>
4#include "alloc.h"
5#include "error.h"
6
7#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */
8#define SPACE 2048 /* must be multiple of ALIGNMENT */
9
10typedef union { char irrelevant[ALIGNMENT]; double d; } aligned;
11static aligned realspace[SPACE / ALIGNMENT];
12#define space ((char *) realspace)
13static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */
14
15/*@null@*//*@out@*/char *alloc(n)
16unsigned int n;
17{
18 char *x;
19 n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */
20 if (n <= avail) { avail -= n; return space + avail; }
21 x = malloc(n);
22 if (!x) errno = error_nomem;
23 return x;
24}
25
26void alloc_free(x)
27char *x;
28{
29 if (x >= space)
30 if (x < space + SPACE)
31 return; /* XXX: assuming that pointers are flat */
32 free(x);
33}
diff --git a/alloc.h b/alloc.h
new file mode 100644
index 0000000..21122fc
--- /dev/null
+++ b/alloc.h
@@ -0,0 +1,10 @@
1/* Public domain. */
2
3#ifndef ALLOC_H
4#define ALLOC_H
5
6extern /*@null@*//*@out@*/char *alloc();
7extern void alloc_free();
8extern int alloc_re();
9
10#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 @@
1/* Public domain. */
2
3#include "alloc.h"
4#include "byte.h"
5
6int alloc_re(x,m,n)
7char **x;
8unsigned int m;
9unsigned int n;
10{
11 char *y;
12
13 y = alloc(n);
14 if (!y) return 0;
15 byte_copy(y,m,*x);
16 alloc_free(*x);
17 *x = y;
18 return 1;
19}
diff --git a/buffer.h b/buffer.h
new file mode 100644
index 0000000..8f2e572
--- /dev/null
+++ b/buffer.h
@@ -0,0 +1,61 @@
1/* Public domain. */
2
3#ifndef BUFFER_H
4#define BUFFER_H
5
6typedef struct buffer {
7 char *x;
8 unsigned int p;
9 unsigned int n;
10 int fd;
11 int (*op)();
12} buffer;
13
14#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) }
15#define BUFFER_INSIZE 8192
16#define BUFFER_OUTSIZE 8192
17
18extern void buffer_init(buffer *,int (*)(),int,char *,unsigned int);
19
20extern int buffer_flush(buffer *);
21extern int buffer_put(buffer *,const char *,unsigned int);
22extern int buffer_putalign(buffer *,const char *,unsigned int);
23extern int buffer_putflush(buffer *,const char *,unsigned int);
24extern int buffer_puts(buffer *,const char *);
25extern int buffer_putsalign(buffer *,const char *);
26extern int buffer_putsflush(buffer *,const char *);
27
28#define buffer_PUTC(s,c) \
29 ( ((s)->n != (s)->p) \
30 ? ( (s)->x[(s)->p++] = (c), 0 ) \
31 : buffer_put((s),&(c),1) \
32 )
33
34extern int buffer_get(buffer *,char *,unsigned int);
35extern int buffer_bget(buffer *,char *,unsigned int);
36extern int buffer_feed(buffer *);
37
38extern char *buffer_peek(buffer *);
39extern void buffer_seek(buffer *,unsigned int);
40
41#define buffer_PEEK(s) ( (s)->x + (s)->n )
42#define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) )
43
44#define buffer_GETC(s,c) \
45 ( ((s)->p > 0) \
46 ? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \
47 : buffer_get((s),(c),1) \
48 )
49
50extern int buffer_copy(buffer *,buffer *);
51
52extern int buffer_unixread(int,char *,unsigned int);
53extern int buffer_unixwrite(int,const char *,unsigned int);
54
55extern buffer *buffer_0;
56extern buffer *buffer_0small;
57extern buffer *buffer_1;
58extern buffer *buffer_1small;
59extern buffer *buffer_2;
60
61#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 @@
1/* Public domain. */
2
3#include "buffer.h"
4
5char buffer_2_space[256];
6static buffer it = BUFFER_INIT(buffer_unixwrite,2,buffer_2_space,sizeof buffer_2_space);
7buffer *buffer_2 = &it;
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 @@
1/* Public domain. */
2
3#include "buffer.h"
4#include "str.h"
5#include "byte.h"
6#include "error.h"
7
8static int allwrite(int (*op)(),int fd,const char *buf,unsigned int len)
9{
10 int w;
11
12 while (len) {
13 w = op(fd,buf,len);
14 if (w == -1) {
15 if (errno == error_intr) continue;
16 return -1; /* note that some data may have been written */
17 }
18 if (w == 0) ; /* luser's fault */
19 buf += w;
20 len -= w;
21 }
22 return 0;
23}
24
25int buffer_flush(buffer *s)
26{
27 int p;
28
29 p = s->p;
30 if (!p) return 0;
31 s->p = 0;
32 return allwrite(s->op,s->fd,s->x,p);
33}
34
35int buffer_putalign(buffer *s,const char *buf,unsigned int len)
36{
37 unsigned int n;
38
39 while (len > (n = s->n - s->p)) {
40 byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n;
41 if (buffer_flush(s) == -1) return -1;
42 }
43 /* now len <= s->n - s->p */
44 byte_copy(s->x + s->p,len,buf);
45 s->p += len;
46 return 0;
47}
48
49int buffer_put(buffer *s,const char *buf,unsigned int len)
50{
51 unsigned int n;
52
53 n = s->n;
54 if (len > n - s->p) {
55 if (buffer_flush(s) == -1) return -1;
56 /* now s->p == 0 */
57 if (n < BUFFER_OUTSIZE) n = BUFFER_OUTSIZE;
58 while (len > s->n) {
59 if (n > len) n = len;
60 if (allwrite(s->op,s->fd,buf,n) == -1) return -1;
61 buf += n;
62 len -= n;
63 }
64 }
65 /* now len <= s->n - s->p */
66 byte_copy(s->x + s->p,len,buf);
67 s->p += len;
68 return 0;
69}
70
71int buffer_putflush(buffer *s,const char *buf,unsigned int len)
72{
73 if (buffer_flush(s) == -1) return -1;
74 return allwrite(s->op,s->fd,buf,len);
75}
76
77int buffer_putsalign(buffer *s,const char *buf)
78{
79 return buffer_putalign(s,buf,str_len(buf));
80}
81
82int buffer_puts(buffer *s,const char *buf)
83{
84 return buffer_put(s,buf,str_len(buf));
85}
86
87int buffer_putsflush(buffer *s,const char *buf)
88{
89 return buffer_putflush(s,buf,str_len(buf));
90}
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 @@
1/* Public domain. */
2
3#include <unistd.h>
4#include "buffer.h"
5
6int buffer_unixwrite(int fd,const char *buf,unsigned int len)
7{
8 return write(fd,buf,len);
9}
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 @@
1/* Public domain. */
2
3#ifndef BYTE_H
4#define BYTE_H
5
6extern unsigned int byte_chr();
7extern unsigned int byte_rchr();
8extern void byte_copy();
9extern void byte_copyr();
10extern int byte_diff();
11extern void byte_zero();
12
13#define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
14
15#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 @@
1/* Public domain. */
2
3#include "byte.h"
4
5unsigned int byte_chr(s,n,c)
6char *s;
7register unsigned int n;
8int c;
9{
10 register char ch;
11 register char *t;
12
13 ch = c;
14 t = s;
15 for (;;) {
16 if (!n) break; if (*t == ch) break; ++t; --n;
17 if (!n) break; if (*t == ch) break; ++t; --n;
18 if (!n) break; if (*t == ch) break; ++t; --n;
19 if (!n) break; if (*t == ch) break; ++t; --n;
20 }
21 return t - s;
22}
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 @@
1/* Public domain. */
2
3#include "byte.h"
4
5void byte_copy(to,n,from)
6register char *to;
7register unsigned int n;
8register char *from;
9{
10 for (;;) {
11 if (!n) return; *to++ = *from++; --n;
12 if (!n) return; *to++ = *from++; --n;
13 if (!n) return; *to++ = *from++; --n;
14 if (!n) return; *to++ = *from++; --n;
15 }
16}
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 @@
1/* Public domain. */
2
3#include "byte.h"
4
5int byte_diff(s,n,t)
6register char *s;
7register unsigned int n;
8register char *t;
9{
10 for (;;) {
11 if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
12 if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
13 if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
14 if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
15 }
16 return ((int)(unsigned int)(unsigned char) *s)
17 - ((int)(unsigned int)(unsigned char) *t);
18}
diff --git a/chpst.c b/chpst.c
new file mode 100644
index 0000000..f1b8ed9
--- /dev/null
+++ b/chpst.c
@@ -0,0 +1,475 @@
1#include <sys/types.h>
2#include <time.h>
3#include <sys/time.h>
4#include <sys/resource.h>
5#include <unistd.h>
6#include "sgetopt.h"
7#include "error.h"
8#include "strerr.h"
9#include "str.h"
10#include "uidgid.h"
11#include "prot.h"
12#include "strerr.h"
13#include "scan.h"
14#include "fmt.h"
15#include "lock.h"
16#include "pathexec.h"
17#include "stralloc.h"
18#include "byte.h"
19#include "open.h"
20#include "openreadclose.h"
21#include "direntry.h"
22
23#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"
24#define FATAL "chpst: fatal: "
25#define WARNING "chpst: warning: "
26
27const char *progname;
28static stralloc sa;
29
30void fatal(const char *m) { strerr_die3sys(111, FATAL, m, ": "); }
31void fatal2(const char *m0, const char *m1) {
32 strerr_die5sys(111, FATAL, m0, ": ", m1, ": ");
33}
34void fatalx(const char *m0, const char *m1) {
35 strerr_die4x(111, FATAL, m0, ": ", m1);
36}
37void warn(const char *m) { strerr_warn2(WARNING, m, 0); }
38void die_nomem() { strerr_die2x(111, FATAL, "out of memory."); }
39void usage() { strerr_die4x(100, "usage: ", progname, USAGE_MAIN, "\n"); }
40
41char *set_user =0;
42char *env_user =0;
43const char *argv0 =0;
44const char *env_dir =0;
45unsigned int verbose =0;
46unsigned int pgrp =0;
47unsigned int nostdin =0;
48unsigned int nostdout =0;
49unsigned int nostderr =0;
50long limitd =-2;
51long limits =-2;
52long limitl =-2;
53long limita =-2;
54long limito =-2;
55long limitp =-2;
56long limitf =-2;
57long limitc =-2;
58long limitr =-2;
59long limitt =-2;
60long nicelvl =0;
61const char *lock =0;
62const char *root =0;
63unsigned int lockdelay;
64
65void suidgid(char *user, unsigned int ext) {
66 struct uidgid ugid;
67
68 if (ext) {
69 if (! uidgids_get(&ugid, user)) {
70 if (*user == ':') fatalx("invalid uid/gids", user +1);
71 if (errno) fatal("unable to get password/group file entry");
72 fatalx("unknown user/group", user);
73 }
74 }
75 else
76 if (! uidgid_get(&ugid, user)) {
77 if (errno) fatal("unable to get password file entry");
78 fatalx("unknown account", user);
79 }
80 if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to setgroups");
81 if (setgid(*ugid.gid) == -1) fatal("unable to setgid");
82 if (prot_uid(ugid.uid) == -1) fatal("unable to setuid");
83}
84
85void euidgid(char *user, unsigned int ext) {
86 struct uidgid ugid;
87 char bufnum[FMT_ULONG];
88
89 if (ext) {
90 if (! uidgids_get(&ugid, user)) {
91 if (*user == ':') fatalx("invalid uid/gids", user +1);
92 if (errno) fatal("unable to get password/group file entry");
93 fatalx("unknown user/group", user);
94 }
95 }
96 else
97 if (! uidgid_get(&ugid, user)) {
98 if (errno) fatal("unable to get password file entry");
99 fatalx("unknown account", user);
100 }
101 bufnum[fmt_ulong(bufnum, *ugid.gid)] =0;
102 if (! pathexec_env("GID", bufnum)) die_nomem();
103 bufnum[fmt_ulong(bufnum, ugid.uid)] =0;
104 if (! pathexec_env("UID", bufnum)) die_nomem();
105}
106
107void edir(const char *dirname) {
108 int wdir;
109 DIR *dir;
110 direntry *d;
111 int i;
112
113 if ((wdir =open_read(".")) == -1)
114 fatal("unable to open current working directory");
115 if (chdir(dirname)) fatal2("unable to switch to directory", dirname);
116 if (! (dir =opendir("."))) fatal2("unable to open directory", dirname);
117 for (;;) {
118 errno =0;
119 d =readdir(dir);
120 if (! d) {
121 if (errno) fatal2("unable to read directory", dirname);
122 break;
123 }
124 if (d->d_name[0] == '.') continue;
125 if (openreadclose(d->d_name, &sa, 256) == -1) {
126 if ((errno == error_isdir) && env_dir) {
127 if (verbose)
128 strerr_warn6(WARNING, "unable to read ", dirname, "/",
129 d->d_name, ": ", &strerr_sys);
130 continue;
131 }
132 else
133 strerr_die6sys(111, FATAL, "unable to read ", dirname, "/",
134 d->d_name, ": ");
135 }
136 if (sa.len) {
137 sa.len =byte_chr(sa.s, sa.len, '\n');
138 while (sa.len && (sa.s[sa.len -1] == ' ' || sa.s[sa.len -1] == '\t'))
139 --sa.len;
140 for (i =0; i < sa.len; ++i) if (! sa.s[i]) sa.s[i] ='\n';
141 if (! stralloc_0(&sa)) die_nomem();
142 if (! pathexec_env(d->d_name, sa.s)) die_nomem();
143 }
144 else
145 if (! pathexec_env(d->d_name, 0)) die_nomem();
146 }
147 closedir(dir);
148 if (fchdir(wdir) == -1) fatal("unable to switch to starting directory");
149 close(wdir);
150}
151
152void slock_die(const char *m, const char *f, unsigned int x) {
153 if (! x) fatal2(m, f);
154 _exit(0);
155}
156void slock(const char *f, unsigned int d, unsigned int x) {
157 int fd;
158
159 if ((fd =open_append(f)) == -1) slock_die("unable to open lock", f, x);
160 if (d) {
161 if (lock_ex(fd) == -1) slock_die("unable to lock", f, x);
162 return;
163 }
164 if (lock_exnb(fd) == -1) slock_die("unable to lock", f, x);
165}
166
167void limit(int what, long l) {
168 struct rlimit r;
169
170 if (getrlimit(what, &r) == -1) fatal("unable to getrlimit()");
171 if ((l < 0) || (l > r.rlim_max))
172 r.rlim_cur =r.rlim_max;
173 else
174 r.rlim_cur =l;
175 if (setrlimit(what, &r) == -1) fatal("unable to setrlimit()");
176}
177void slimit() {
178 if (limitd >= -1) {
179#ifdef RLIMIT_DATA
180 limit(RLIMIT_DATA, limitd);
181#else
182 if (verbose) warn("system does not support RLIMIT_DATA");
183#endif
184 }
185 if (limits >= -1) {
186#ifdef RLIMIT_STACK
187 limit(RLIMIT_STACK, limits);
188#else
189 if (verbose) warn("system does not support RLIMIT_STACK");
190#endif
191 }
192 if (limitl >= -1) {
193#ifdef RLIMIT_MEMLOCK
194 limit(RLIMIT_MEMLOCK, limitl);
195#else
196 if (verbose) warn("system does not support RLIMIT_MEMLOCK");
197#endif
198 }
199 if (limita >= -1) {
200#ifdef RLIMIT_VMEM
201 limit(RLIMIT_VMEM, limita);
202#else
203#ifdef RLIMIT_AS
204 limit(RLIMIT_AS, limita);
205#else
206 if (verbose)
207 warn("system does neither support RLIMIT_VMEM nor RLIMIT_AS");
208#endif
209#endif
210 }
211 if (limito >= -1) {
212#ifdef RLIMIT_NOFILE
213 limit(RLIMIT_NOFILE, limito);
214#else
215#ifdef RLIMIT_OFILE
216 limit(RLIMIT_OFILE, limito);
217#else
218 if (verbose)
219 warn("system does neither support RLIMIT_NOFILE nor RLIMIT_OFILE");
220#endif
221#endif
222 }
223 if (limitp >= -1) {
224#ifdef RLIMIT_NPROC
225 limit(RLIMIT_NPROC, limitp);
226#else
227 if (verbose) warn("system does not support RLIMIT_NPROC");
228#endif
229 }
230 if (limitf >= -1) {
231#ifdef RLIMIT_FSIZE
232 limit(RLIMIT_FSIZE, limitf);
233#else
234 if (verbose) warn("system does not support RLIMIT_FSIZE");
235#endif
236 }
237 if (limitc >= -1) {
238#ifdef RLIMIT_CORE
239 limit(RLIMIT_CORE, limitc);
240#else
241 if (verbose) warn("system does not support RLIMIT_CORE");
242#endif
243 }
244 if (limitr >= -1) {
245#ifdef RLIMIT_RSS
246 limit(RLIMIT_RSS, limitr);
247#else
248 if (verbose) warn("system does not support RLIMIT_RSS");
249#endif
250 }
251 if (limitt >= -1) {
252#ifdef RLIMIT_CPU
253 limit(RLIMIT_CPU, limitt);
254#else
255 if (verbose) warn("system does not support RLIMIT_CPU");
256#endif
257 }
258}
259
260/* argv[0] */
261void setuidgid(int, const char *const *);
262void envuidgid(int, const char *const *);
263void envdir(int, const char *const *);
264void pgrphack(int, const char *const *);
265void setlock(int, const char *const *);
266void softlimit(int, const char *const *);
267
268int main(int argc, const char **argv) {
269 int opt;
270 int i;
271 unsigned long ul;
272
273 progname =argv[0];
274 for (i =str_len(progname); i; --i)
275 if (progname[i -1] == '/') {
276 progname +=i;
277 break;
278 }
279 if (progname[0] == 'd') ++progname;
280
281 /* argv[0] */
282 if (str_equal(progname, "setuidgid")) setuidgid(argc, argv);
283 if (str_equal(progname, "envuidgid")) envuidgid(argc, argv);
284 if (str_equal(progname, "envdir")) envdir(argc, argv);
285 if (str_equal(progname, "pgrphack")) pgrphack(argc, argv);
286 if (str_equal(progname, "setlock")) setlock(argc, argv);
287 if (str_equal(progname, "softlimit")) softlimit(argc, argv);
288
289 while ((opt =getopt(argc, argv, "u:U:b:e:m:d:o:p:f:c:r:t:/:n:l:L:vP012V"))
290 != opteof)
291 switch(opt) {
292 case 'u': set_user =(char*)optarg; break;
293 case 'U': env_user =(char*)optarg; break;
294 case 'b': argv0 =(char*)optarg; break;
295 case 'e': env_dir =optarg; break;
296 case 'm':
297 if (optarg[scan_ulong(optarg, &ul)]) usage();
298 limits =limitl =limita =limitd =ul;
299 break;
300 case 'd': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitd =ul; break;
301 case 'o': if (optarg[scan_ulong(optarg, &ul)]) usage(); limito =ul; break;
302 case 'p': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitp =ul; break;
303 case 'f': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitf =ul; break;
304 case 'c': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitc =ul; break;
305 case 'r': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitr =ul; break;
306 case 't': if (optarg[scan_ulong(optarg, &ul)]) usage(); limitt =ul; break;
307 case '/': root =optarg; break;
308 case 'n':
309 switch (*optarg) {
310 case '-':
311 if (optarg[scan_ulong(++optarg, &ul)]) usage(); nicelvl =ul;
312 nicelvl *=-1;
313 break;
314 case '+': ++optarg;
315 default:
316 if (optarg[scan_ulong(optarg, &ul)]) usage(); nicelvl =ul;
317 break;
318 }
319 break;
320 case 'l': if (lock) usage(); lock =optarg; lockdelay =1; break;
321 case 'L': if (lock) usage(); lock =optarg; lockdelay =0; break;
322 case 'v': verbose =1; break;
323 case 'P': pgrp =1; break;
324 case '0': nostdin =1; break;
325 case '1': nostdout =1; break;
326 case '2': nostderr =1; break;
327 case 'V': strerr_warn1("$Id: f279d44141c981dd7535a12260efcf1ef7beed26 $", 0);
328 case '?': usage();
329 }
330 argv +=optind;
331 if (! argv || ! *argv) usage();
332
333 if (pgrp) setsid();
334 if (env_dir) edir(env_dir);
335 if (root) {
336 if (chdir(root) == -1) fatal2("unable to change directory", root);
337 if (chroot(".") == -1) fatal("unable to change root directory");
338 }
339 if (nicelvl) {
340 errno =0;
341 if (nice(nicelvl) == -1) if (errno) fatal("unable to set nice level");
342 }
343 if (env_user) euidgid(env_user, 1);
344 if (set_user) suidgid(set_user, 1);
345 if (lock) slock(lock, lockdelay, 0);
346 if (nostdin) if (close(0) == -1) fatal("unable to close stdin");
347 if (nostdout) if (close(1) == -1) fatal("unable to close stdout");
348 if (nostderr) if (close(2) == -1) fatal("unable to close stderr");
349 slimit();
350
351 progname =*argv;
352 if (argv0) *argv =argv0;
353 pathexec_env_run(progname, argv);
354 fatal2("unable to run", *argv);
355 return(0);
356}
357
358/* argv[0] */
359#define USAGE_SETUIDGID " account child"
360#define USAGE_ENVUIDGID " account child"
361#define USAGE_ENVDIR " dir child"
362#define USAGE_PGRPHACK " child"
363#define USAGE_SETLOCK " [ -nNxX ] file program [ arg ... ]"
364#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"
365
366void setuidgid_usage() {
367 strerr_die4x(100, "usage: ", progname, USAGE_SETUIDGID, "\n");
368}
369void setuidgid(int argc, const char *const *argv) {
370 const char *account;
371
372 if (! (account =*++argv)) setuidgid_usage();
373 if (! *++argv) setuidgid_usage();
374 suidgid((char*)account, 0);
375 pathexec(argv);
376 fatal2("unable to run", *argv);
377}
378
379void envuidgid_usage() {
380 strerr_die4x(100, "usage: ", progname, USAGE_ENVUIDGID, "\n");
381}
382void envuidgid(int argc, const char *const *argv) {
383 const char *account;
384
385 if (! (account =*++argv)) envuidgid_usage();
386 if (! *++argv) envuidgid_usage();
387 euidgid((char*)account, 0);
388 pathexec(argv);
389 fatal2("unable to run", *argv);
390}
391
392void envdir_usage() {
393 strerr_die4x(100, "usage: ", progname, USAGE_ENVDIR, "\n");
394}
395void envdir(int argc, const char *const *argv) {
396 const char *dir;
397
398 if (! (dir =*++argv)) envdir_usage();
399 if (! *++argv) envdir_usage();
400 edir(dir);
401 pathexec(argv);
402 fatal2("unable to run", *argv);
403}
404
405void pgrphack_usage() {
406 strerr_die4x(100, "usage: ", progname, USAGE_PGRPHACK, "\n");
407}
408void pgrphack(int argc, const char *const *argv) {
409 if (! *++argv) pgrphack_usage();
410 setsid();
411 pathexec(argv);
412 fatal2("unable to run", *argv);
413}
414
415void setlock_usage() {
416 strerr_die4x(100, "usage: ", progname, USAGE_SETLOCK, "\n");
417}
418void setlock(int argc, const char *const *argv) {
419 int opt;
420 unsigned int delay =0;
421 unsigned int x =0;
422 const char *fn;
423
424 while ((opt =getopt(argc, argv, "nNxX")) != opteof)
425 switch(opt) {
426 case 'n': delay =1; break;
427 case 'N': delay =0; break;
428 case 'x': x =1; break;
429 case 'X': x =0; break;
430 default: setlock_usage();
431 }
432 argv +=optind;
433 if (! (fn =*argv)) setlock_usage();
434 if (! *++argv) setlock_usage();
435
436 slock(fn, delay, x);
437 pathexec(argv);
438 if (! x) fatal2("unable to run", *argv);
439 _exit(0);
440}
441
442void softlimit_usage() {
443 strerr_die4x(100, "usage: ", progname, USAGE_SOFTLIMIT, "\n");
444}
445void getlarg(long *l) {
446 unsigned long ul;
447
448 if (str_equal(optarg, "=")) { *l =-1; return; }
449 if (optarg[scan_ulong(optarg, &ul)]) usage();
450 *l =ul;
451}
452void softlimit(int argc, const char *const *argv) {
453 int opt;
454
455 while ((opt =getopt(argc,argv,"a:c:d:f:l:m:o:p:r:s:t:")) != opteof)
456 switch(opt) {
457 case '?': softlimit_usage();
458 case 'a': getlarg(&limita); break;
459 case 'c': getlarg(&limitc); break;
460 case 'd': getlarg(&limitd); break;
461 case 'f': getlarg(&limitf); break;
462 case 'l': getlarg(&limitl); break;
463 case 'm': getlarg(&limitd); limits =limitl =limita =limitd; break;
464 case 'o': getlarg(&limito); break;
465 case 'p': getlarg(&limitp); break;
466 case 'r': getlarg(&limitr); break;
467 case 's': getlarg(&limits); break;
468 case 't': getlarg(&limitt); break;
469 }
470 argv +=optind;
471 if (!*argv) softlimit_usage();
472 slimit();
473 pathexec(argv);
474 fatal2("unable to run", *argv);
475}
diff --git a/direntry.h b/direntry.h
new file mode 100644
index 0000000..bfd4d19
--- /dev/null
+++ b/direntry.h
@@ -0,0 +1,12 @@
1/* Public domain. */
2
3#ifndef DIRENTRY_H
4#define DIRENTRY_H
5
6/* sysdep: +dirent */
7
8#include <sys/types.h>
9#include <dirent.h>
10#define direntry struct dirent
11
12#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 @@
1/* Public domain. */
2
3#include "str.h"
4#include "env.h"
5
6extern /*@null@*/char *env_get(const char *s)
7{
8 int i;
9 unsigned int len;
10
11 if (!s) return 0;
12 len = str_len(s);
13 for (i = 0;environ[i];++i)
14 if (str_start(environ[i],s) && (environ[i][len] == '='))
15 return environ[i] + len + 1;
16 return 0;
17}
diff --git a/env.h b/env.h
new file mode 100644
index 0000000..834d331
--- /dev/null
+++ b/env.h
@@ -0,0 +1,10 @@
1/* Public domain. */
2
3#ifndef ENV_H
4#define ENV_H
5
6extern char **environ;
7
8extern /*@null@*/char *env_get(const char *);
9
10#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 @@
1/* Public domain. */
2
3#include <errno.h>
4#include "error.h"
5
6/* warning: as coverage improves here, should update error_{str,temp} */
7
8int error_intr =
9#ifdef EINTR
10EINTR;
11#else
12-1;
13#endif
14
15int error_nomem =
16#ifdef ENOMEM
17ENOMEM;
18#else
19-2;
20#endif
21
22int error_noent =
23#ifdef ENOENT
24ENOENT;
25#else
26-3;
27#endif
28
29int error_txtbsy =
30#ifdef ETXTBSY
31ETXTBSY;
32#else
33-4;
34#endif
35
36int error_io =
37#ifdef EIO
38EIO;
39#else
40-5;
41#endif
42
43int error_exist =
44#ifdef EEXIST
45EEXIST;
46#else
47-6;
48#endif
49
50int error_timeout =
51#ifdef ETIMEDOUT
52ETIMEDOUT;
53#else
54-7;
55#endif
56
57int error_inprogress =
58#ifdef EINPROGRESS
59EINPROGRESS;
60#else
61-8;
62#endif
63
64int error_wouldblock =
65#ifdef EWOULDBLOCK
66EWOULDBLOCK;
67#else
68-9;
69#endif
70
71int error_again =
72#ifdef EAGAIN
73EAGAIN;
74#else
75-10;
76#endif
77
78int error_pipe =
79#ifdef EPIPE
80EPIPE;
81#else
82-11;
83#endif
84
85int error_perm =
86#ifdef EPERM
87EPERM;
88#else
89-12;
90#endif
91
92int error_acces =
93#ifdef EACCES
94EACCES;
95#else
96-13;
97#endif
98
99int error_nodevice =
100#ifdef ENXIO
101ENXIO;
102#else
103-14;
104#endif
105
106int error_proto =
107#ifdef EPROTO
108EPROTO;
109#else
110-15;
111#endif
112
113int error_isdir =
114#ifdef EISDIR
115EISDIR;
116#else
117-16;
118#endif
119
120int error_connrefused =
121#ifdef ECONNREFUSED
122ECONNREFUSED;
123#else
124-17;
125#endif
126
127int error_notdir =
128#ifdef ENOTDIR
129ENOTDIR;
130#else
131-18;
132#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 @@
1/* Public domain. */
2
3#ifndef ERROR_H
4#define ERROR_H
5
6/* 20030124: include <errno.h> -upcoming glibc changes */
7#include <errno.h>
8
9/* extern int errno; */
10
11extern int error_intr;
12extern int error_nomem;
13extern int error_noent;
14extern int error_txtbsy;
15extern int error_io;
16extern int error_exist;
17extern int error_timeout;
18extern int error_inprogress;
19extern int error_wouldblock;
20extern int error_again;
21extern int error_pipe;
22extern int error_perm;
23extern int error_acces;
24extern int error_nodevice;
25extern int error_proto;
26extern int error_isdir;
27extern int error_connrefused;
28extern int error_notdir;
29
30extern const char *error_str(int);
31extern int error_temp(int);
32
33#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 @@
1/* Public domain. */
2
3#include <errno.h>
4#include "error.h"
5
6#define X(e,s) if (i == e) return s;
7
8const char *error_str(int i)
9{
10 X(0,"no error")
11 X(error_intr,"interrupted system call")
12 X(error_nomem,"out of memory")
13 X(error_noent,"file does not exist")
14 X(error_txtbsy,"text busy")
15 X(error_io,"input/output error")
16 X(error_exist,"file already exists")
17 X(error_timeout,"timed out")
18 X(error_inprogress,"operation in progress")
19 X(error_again,"temporary failure")
20 X(error_wouldblock,"input/output would block")
21 X(error_pipe,"broken pipe")
22 X(error_perm,"permission denied")
23 X(error_acces,"access denied")
24 X(error_nodevice,"device not configured")
25 X(error_proto,"protocol error")
26 X(error_isdir,"is a directory")
27 X(error_connrefused,"connection refused")
28 X(error_notdir,"not a directory")
29#ifdef ESRCH
30 X(ESRCH,"no such process")
31#endif
32#ifdef E2BIG
33 X(E2BIG,"argument list too long")
34#endif
35#ifdef ENOEXEC
36 X(ENOEXEC,"exec format error")
37#endif
38#ifdef EBADF
39 X(EBADF,"file descriptor not open")
40#endif
41#ifdef ECHILD
42 X(ECHILD,"no child processes")
43#endif
44#ifdef EDEADLK
45 X(EDEADLK,"operation would cause deadlock")
46#endif
47#ifdef EFAULT
48 X(EFAULT,"bad address")
49#endif
50#ifdef ENOTBLK
51 X(ENOTBLK,"not a block device")
52#endif
53#ifdef EBUSY
54 X(EBUSY,"device busy")
55#endif
56#ifdef EXDEV
57 X(EXDEV,"cross-device link")
58#endif
59#ifdef ENODEV
60 X(ENODEV,"device does not support operation")
61#endif
62#ifdef EINVAL
63 X(EINVAL,"invalid argument")
64#endif
65#ifdef ENFILE
66 X(ENFILE,"system cannot open more files")
67#endif
68#ifdef EMFILE
69 X(EMFILE,"process cannot open more files")
70#endif
71#ifdef ENOTTY
72 X(ENOTTY,"not a tty")
73#endif
74#ifdef EFBIG
75 X(EFBIG,"file too big")
76#endif
77#ifdef ENOSPC
78 X(ENOSPC,"out of disk space")
79#endif
80#ifdef ESPIPE
81 X(ESPIPE,"unseekable descriptor")
82#endif
83#ifdef EROFS
84 X(EROFS,"read-only file system")
85#endif
86#ifdef EMLINK
87 X(EMLINK,"too many links")
88#endif
89#ifdef EDOM
90 X(EDOM,"input out of range")
91#endif
92#ifdef ERANGE
93 X(ERANGE,"output out of range")
94#endif
95#ifdef EALREADY
96 X(EALREADY,"operation already in progress")
97#endif
98#ifdef ENOTSOCK
99 X(ENOTSOCK,"not a socket")
100#endif
101#ifdef EDESTADDRREQ
102 X(EDESTADDRREQ,"destination address required")
103#endif
104#ifdef EMSGSIZE
105 X(EMSGSIZE,"message too long")
106#endif
107#ifdef EPROTOTYPE
108 X(EPROTOTYPE,"incorrect protocol type")
109#endif
110#ifdef ENOPROTOOPT
111 X(ENOPROTOOPT,"protocol not available")
112#endif
113#ifdef EPROTONOSUPPORT
114 X(EPROTONOSUPPORT,"protocol not supported")
115#endif
116#ifdef ESOCKTNOSUPPORT
117 X(ESOCKTNOSUPPORT,"socket type not supported")
118#endif
119#ifdef EOPNOTSUPP
120 X(EOPNOTSUPP,"operation not supported")
121#endif
122#ifdef EPFNOSUPPORT
123 X(EPFNOSUPPORT,"protocol family not supported")
124#endif
125#ifdef EAFNOSUPPORT
126 X(EAFNOSUPPORT,"address family not supported")
127#endif
128#ifdef EADDRINUSE
129 X(EADDRINUSE,"address already used")
130#endif
131#ifdef EADDRNOTAVAIL
132 X(EADDRNOTAVAIL,"address not available")
133#endif
134#ifdef ENETDOWN
135 X(ENETDOWN,"network down")
136#endif
137#ifdef ENETUNREACH
138 X(ENETUNREACH,"network unreachable")
139#endif
140#ifdef ENETRESET
141 X(ENETRESET,"network reset")
142#endif
143#ifdef ECONNABORTED
144 X(ECONNABORTED,"connection aborted")
145#endif
146#ifdef ECONNRESET
147 X(ECONNRESET,"connection reset")
148#endif
149#ifdef ENOBUFS
150 X(ENOBUFS,"out of buffer space")
151#endif
152#ifdef EISCONN
153 X(EISCONN,"already connected")
154#endif
155#ifdef ENOTCONN
156 X(ENOTCONN,"not connected")
157#endif
158#ifdef ESHUTDOWN
159 X(ESHUTDOWN,"socket shut down")
160#endif
161#ifdef ETOOMANYREFS
162 X(ETOOMANYREFS,"too many references")
163#endif
164#ifdef ELOOP
165 X(ELOOP,"symbolic link loop")
166#endif
167#ifdef ENAMETOOLONG
168 X(ENAMETOOLONG,"file name too long")
169#endif
170#ifdef EHOSTDOWN
171 X(EHOSTDOWN,"host down")
172#endif
173#ifdef EHOSTUNREACH
174 X(EHOSTUNREACH,"host unreachable")
175#endif
176#ifdef ENOTEMPTY
177 X(ENOTEMPTY,"directory not empty")
178#endif
179#ifdef EPROCLIM
180 X(EPROCLIM,"too many processes")
181#endif
182#ifdef EUSERS
183 X(EUSERS,"too many users")
184#endif
185#ifdef EDQUOT
186 X(EDQUOT,"disk quota exceeded")
187#endif
188#ifdef ESTALE
189 X(ESTALE,"stale NFS file handle")
190#endif
191#ifdef EREMOTE
192 X(EREMOTE,"too many levels of remote in path")
193#endif
194#ifdef EBADRPC
195 X(EBADRPC,"RPC structure is bad")
196#endif
197#ifdef ERPCMISMATCH
198 X(ERPCMISMATCH,"RPC version mismatch")
199#endif
200#ifdef EPROGUNAVAIL
201 X(EPROGUNAVAIL,"RPC program unavailable")
202#endif
203#ifdef EPROGMISMATCH
204 X(EPROGMISMATCH,"program version mismatch")
205#endif
206#ifdef EPROCUNAVAIL
207 X(EPROCUNAVAIL,"bad procedure for program")
208#endif
209#ifdef ENOLCK
210 X(ENOLCK,"no locks available")
211#endif
212#ifdef ENOSYS
213 X(ENOSYS,"system call not available")
214#endif
215#ifdef EFTYPE
216 X(EFTYPE,"bad file type")
217#endif
218#ifdef EAUTH
219 X(EAUTH,"authentication error")
220#endif
221#ifdef ENEEDAUTH
222 X(ENEEDAUTH,"not authenticated")
223#endif
224#ifdef ENOSTR
225 X(ENOSTR,"not a stream device")
226#endif
227#ifdef ETIME
228 X(ETIME,"timer expired")
229#endif
230#ifdef ENOSR
231 X(ENOSR,"out of stream resources")
232#endif
233#ifdef ENOMSG
234 X(ENOMSG,"no message of desired type")
235#endif
236#ifdef EBADMSG
237 X(EBADMSG,"bad message type")
238#endif
239#ifdef EIDRM
240 X(EIDRM,"identifier removed")
241#endif
242#ifdef ENONET
243 X(ENONET,"machine not on network")
244#endif
245#ifdef ERREMOTE
246 X(ERREMOTE,"object not local")
247#endif
248#ifdef ENOLINK
249 X(ENOLINK,"link severed")
250#endif
251#ifdef EADV
252 X(EADV,"advertise error")
253#endif
254#ifdef ESRMNT
255 X(ESRMNT,"srmount error")
256#endif
257#ifdef ECOMM
258 X(ECOMM,"communication error")
259#endif
260#ifdef EMULTIHOP
261 X(EMULTIHOP,"multihop attempted")
262#endif
263#ifdef EREMCHG
264 X(EREMCHG,"remote address changed")
265#endif
266 return "unknown error";
267}
diff --git a/fmt.h b/fmt.h
new file mode 100644
index 0000000..8847fa6
--- /dev/null
+++ b/fmt.h
@@ -0,0 +1,27 @@
1/* Public domain. */
2
3#ifndef FMT_H
4#define FMT_H
5
6#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
7#define FMT_LEN ((char *) 0) /* convenient abbreviation */
8
9extern unsigned int fmt_uint(char *,unsigned int);
10extern unsigned int fmt_uint0(char *,unsigned int,unsigned int);
11extern unsigned int fmt_xint(char *,unsigned int);
12extern unsigned int fmt_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int);
13extern unsigned int fmt_ushort(char *,unsigned short);
14extern unsigned int fmt_xshort(char *,unsigned short);
15extern unsigned int fmt_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short);
16extern unsigned int fmt_ulong(char *,unsigned long);
17extern unsigned int fmt_xlong(char *,unsigned long);
18extern unsigned int fmt_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long);
19
20extern unsigned int fmt_plusminus(char *,int);
21extern unsigned int fmt_minus(char *,int);
22extern unsigned int fmt_0x(char *,int);
23
24extern unsigned int fmt_str(char *,const char *);
25extern unsigned int fmt_strn(char *,const char *,unsigned int);
26
27#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 @@
1/* Public domain. */
2
3#include "fmt.h"
4
5unsigned int fmt_ulong(register char *s,register unsigned long u)
6{
7 register unsigned int len; register unsigned long q;
8 len = 1; q = u;
9 while (q > 9) { ++len; q /= 10; }
10 if (s) {
11 s += len;
12 do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
13 }
14 return len;
15}
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 @@
1/* Public domain. */
2
3#ifndef GEN_ALLOC_H
4#define GEN_ALLOC_H
5
6#define GEN_ALLOC_typedef(ta,type,field,len,a) \
7 typedef struct ta { type *field; unsigned int len; unsigned int a; } ta;
8
9#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 @@
1/* Public domain. */
2
3#ifndef GEN_ALLOC_DEFS_H
4#define GEN_ALLOC_DEFS_H
5
6#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \
7int ta_ready(register ta *x,register unsigned int n) \
8{ register unsigned int i; \
9 if (x->field) { \
10 i = x->a; \
11 if (n > i) { \
12 x->a = base + n + (n >> 3); \
13 if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
14 x->a = i; return 0; } \
15 return 1; } \
16 x->len = 0; \
17 return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
18
19#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \
20int ta_rplus(register ta *x,register unsigned int n) \
21{ register unsigned int i; \
22 if (x->field) { \
23 i = x->a; n += x->len; \
24 if (n > i) { \
25 x->a = base + n + (n >> 3); \
26 if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
27 x->a = i; return 0; } \
28 return 1; } \
29 x->len = 0; \
30 return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
31
32#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \
33int ta_append(register ta *x,register const type *i) \
34{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; }
35
36#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 @@
1/* Public domain. */
2
3/* sysdep: +flock */
4#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 @@
1/* Public domain. */
2
3/* sysdep: +shortsetgroups */
4#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 @@
1/* Public domain. */
2
3#ifndef LOCK_H
4#define LOCK_H
5
6extern int lock_ex(int);
7extern int lock_un(int);
8extern int lock_exnb(int);
9
10#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 @@
1/* Public domain. */
2
3#include <sys/types.h>
4#include <sys/file.h>
5#include <fcntl.h>
6#include "hasflock.h"
7#include "lock.h"
8
9#ifdef HASFLOCK
10int lock_ex(int fd) { return flock(fd,LOCK_EX); }
11#else
12int lock_ex(int fd) { return lockf(fd,1,0); }
13#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 @@
1/* Public domain. */
2
3#include <sys/types.h>
4#include <sys/file.h>
5#include <fcntl.h>
6#include "hasflock.h"
7#include "lock.h"
8
9#ifdef HASFLOCK
10int lock_exnb(int fd) { return flock(fd,LOCK_EX | LOCK_NB); }
11#else
12int lock_exnb(int fd) { return lockf(fd,2,0); }
13#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 @@
1/* Public domain. */
2
3#ifndef OPEN_H
4#define OPEN_H
5
6extern int open_read(const char *);
7extern int open_excl(const char *);
8extern int open_append(const char *);
9extern int open_trunc(const char *);
10extern int open_write(const char *);
11
12#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 @@
1/* Public domain. */
2
3#include <sys/types.h>
4#include <fcntl.h>
5#include "open.h"
6
7int open_append(const char *fn)
8{ 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 @@
1/* Public domain. */
2
3#include <sys/types.h>
4#include <fcntl.h>
5#include "open.h"
6
7int open_read(const char *fn)
8{ 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 @@
1/* Public domain. */
2
3#include "error.h"
4#include "open.h"
5#include "readclose.h"
6#include "openreadclose.h"
7
8int openreadclose(const char *fn,stralloc *sa,unsigned int bufsize)
9{
10 int fd;
11 fd = open_read(fn);
12 if (fd == -1) {
13 if (errno == error_noent) return 0;
14 return -1;
15 }
16 if (readclose(fd,sa,bufsize) == -1) return -1;
17 return 1;
18}
diff --git a/openreadclose.h b/openreadclose.h
new file mode 100644
index 0000000..728899c
--- /dev/null
+++ b/openreadclose.h
@@ -0,0 +1,10 @@
1/* Public domain. */
2
3#ifndef OPENREADCLOSE_H
4#define OPENREADCLOSE_H
5
6#include "stralloc.h"
7
8extern int openreadclose(const char *,stralloc *,unsigned int);
9
10#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 @@
1/* Public domain. */
2
3#ifndef PATHEXEC_H
4#define PATHEXEC_H
5
6extern void pathexec_run(const char *,const char * const *,const char * const *);
7extern int pathexec_env(const char *,const char *);
8extern void pathexec_env_run(const char *, const char * const *);
9extern void pathexec(const char * const *);
10
11#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 @@
1/* Public domain. */
2
3#include "stralloc.h"
4#include "alloc.h"
5#include "str.h"
6#include "byte.h"
7#include "env.h"
8#include "pathexec.h"
9
10static stralloc plus;
11static stralloc tmp;
12
13int pathexec_env(const char *s,const char *t)
14{
15 if (!s) return 1;
16 if (!stralloc_copys(&tmp,s)) return 0;
17 if (t) {
18 if (!stralloc_cats(&tmp,"=")) return 0;
19 if (!stralloc_cats(&tmp,t)) return 0;
20 }
21 if (!stralloc_0(&tmp)) return 0;
22 return stralloc_cat(&plus,&tmp);
23}
24
25void pathexec_env_run(const char *file, const char *const *argv)
26{
27 const char **e;
28 unsigned int elen;
29 unsigned int i;
30 unsigned int j;
31 unsigned int split;
32 unsigned int t;
33
34 if (!stralloc_cats(&plus,"")) return;
35
36 elen = 0;
37 for (i = 0;environ[i];++i)
38 ++elen;
39 for (i = 0;i < plus.len;++i)
40 if (!plus.s[i])
41 ++elen;
42
43 e = (const char **) alloc((elen + 1) * sizeof(char *));
44 if (!e) return;
45
46 elen = 0;
47 for (i = 0;environ[i];++i)
48 e[elen++] = environ[i];
49
50 j = 0;
51 for (i = 0;i < plus.len;++i)
52 if (!plus.s[i]) {
53 split = str_chr(plus.s + j,'=');
54 for (t = 0;t < elen;++t)
55 if (byte_equal(plus.s + j,split,e[t]))
56 if (e[t][split] == '=') {
57 --elen;
58 e[t] = e[elen];
59 break;
60 }
61 if (plus.s[j + split])
62 e[elen++] = plus.s + j;
63 j = i + 1;
64 }
65 e[elen] = 0;
66
67 pathexec_run(file,argv,e);
68 alloc_free(e);
69}
70
71void pathexec(const char *const *argv)
72{
73 return pathexec_env_run(*argv, argv);
74}
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 @@
1/* Public domain. */
2
3#include "error.h"
4#include "stralloc.h"
5#include "str.h"
6#include "env.h"
7#include "pathexec.h"
8
9static stralloc tmp;
10
11void pathexec_run(const char *file,const char * const *argv,const char * const *envp)
12{
13 const char *path;
14 unsigned int split;
15 int savederrno;
16
17 if (file[str_chr(file,'/')]) {
18 execve(file,argv,envp);
19 return;
20 }
21
22 path = env_get("PATH");
23 if (!path) path = "/bin:/usr/bin";
24
25 savederrno = 0;
26 for (;;) {
27 split = str_chr(path,':');
28 if (!stralloc_copyb(&tmp,path,split)) return;
29 if (!split)
30 if (!stralloc_cats(&tmp,".")) return;
31 if (!stralloc_cats(&tmp,"/")) return;
32 if (!stralloc_cats(&tmp,file)) return;
33 if (!stralloc_0(&tmp)) return;
34
35 execve(tmp.s,argv,envp);
36 if (errno != error_noent) {
37 savederrno = errno;
38 if ((errno != error_acces) && (errno != error_perm) && (errno != error_isdir)) return;
39 }
40
41 if (!path[split]) {
42 if (savederrno) errno = savederrno;
43 return;
44 }
45 path += split;
46 path += 1;
47 }
48}
diff --git a/prot.c b/prot.c
new file mode 100644
index 0000000..79a88c5
--- /dev/null
+++ b/prot.c
@@ -0,0 +1,21 @@
1/* Public domain. */
2
3#include "hasshsgr.h"
4#include "prot.h"
5
6int prot_gid(int gid)
7{
8#ifdef HASSHORTSETGROUPS
9 short x[2];
10 x[0] = gid; x[1] = 73; /* catch errors */
11 if (setgroups(1,x) == -1) return -1;
12#else
13 if (setgroups(1,&gid) == -1) return -1;
14#endif
15 return setgid(gid); /* _should_ be redundant, but on some systems it isn't */
16}
17
18int prot_uid(int uid)
19{
20 return setuid(uid);
21}
diff --git a/prot.h b/prot.h
new file mode 100644
index 0000000..2e5cb81
--- /dev/null
+++ b/prot.h
@@ -0,0 +1,9 @@
1/* Public domain. */
2
3#ifndef PROT_H
4#define PROT_H
5
6extern int prot_gid(int);
7extern int prot_uid(int);
8
9#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 @@
1/* Public domain. */
2
3#include <unistd.h>
4#include "error.h"
5#include "readclose.h"
6
7int readclose_append(int fd,stralloc *sa,unsigned int bufsize)
8{
9 int r;
10 for (;;) {
11 if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; }
12 r = read(fd,sa->s + sa->len,bufsize);
13 if (r == -1) if (errno == error_intr) continue;
14 if (r <= 0) { close(fd); return r; }
15 sa->len += r;
16 }
17}
18
19int readclose(int fd,stralloc *sa,unsigned int bufsize)
20{
21 if (!stralloc_copys(sa,"")) { close(fd); return -1; }
22 return readclose_append(fd,sa,bufsize);
23}
diff --git a/readclose.h b/readclose.h
new file mode 100644
index 0000000..bde9889
--- /dev/null
+++ b/readclose.h
@@ -0,0 +1,11 @@
1/* Public domain. */
2
3#ifndef READCLOSE_H
4#define READCLOSE_H
5
6#include "stralloc.h"
7
8extern int readclose_append(int,stralloc *,unsigned int);
9extern int readclose(int,stralloc *,unsigned int);
10
11#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 @@
1/* Public domain. */
2
3#ifndef SCAN_H
4#define SCAN_H
5
6extern unsigned int scan_uint(const char *,unsigned int *);
7extern unsigned int scan_xint(const char *,unsigned int *);
8extern unsigned int scan_nbbint(const char *,unsigned int,unsigned int,unsigned int,unsigned int *);
9extern unsigned int scan_ushort(const char *,unsigned short *);
10extern unsigned int scan_xshort(const char *,unsigned short *);
11extern unsigned int scan_nbbshort(const char *,unsigned int,unsigned int,unsigned int,unsigned short *);
12extern unsigned int scan_ulong(const char *,unsigned long *);
13extern unsigned int scan_xlong(const char *,unsigned long *);
14extern unsigned int scan_nbblong(const char *,unsigned int,unsigned int,unsigned int,unsigned long *);
15
16extern unsigned int scan_plusminus(const char *,int *);
17extern unsigned int scan_0x(const char *,unsigned int *);
18
19extern unsigned int scan_whitenskip(const char *,unsigned int);
20extern unsigned int scan_nonwhitenskip(const char *,unsigned int);
21extern unsigned int scan_charsetnskip(const char *,const char *,unsigned int);
22extern unsigned int scan_noncharsetnskip(const char *,const char *,unsigned int);
23
24extern unsigned int scan_strncmp(const char *,const char *,unsigned int);
25extern unsigned int scan_memcmp(const char *,const char *,unsigned int);
26
27extern unsigned int scan_long(const char *,long *);
28extern unsigned int scan_8long(const char *,unsigned long *);
29
30#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 @@
1/* Public domain. */
2
3#include "scan.h"
4
5unsigned int scan_ulong(register const char *s,register unsigned long *u)
6{
7 register unsigned int pos = 0;
8 register unsigned long result = 0;
9 register unsigned long c;
10 while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) {
11 result = result * 10 + c;
12 ++pos;
13 }
14 *u = result;
15 return pos;
16}
diff --git a/sgetopt.c b/sgetopt.c
new file mode 100644
index 0000000..8bb608f
--- /dev/null
+++ b/sgetopt.c
@@ -0,0 +1,53 @@
1/* Public domain. */
2
3/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer
4D. J. Bernstein, djb@pobox.com.
5Depends on subgetopt.h, buffer.h.
6No system requirements.
719991219: Switched to buffer.h.
819970208: Cleanups.
9931201: Baseline.
10No known patent problems.
11
12Documentation in sgetopt.3.
13*/
14
15#include "buffer.h"
16#define SGETOPTNOSHORT
17#include "sgetopt.h"
18#define SUBGETOPTNOSHORT
19#include "subgetopt.h"
20
21#define getopt sgetoptmine
22#define optind subgetoptind
23#define opterr sgetopterr
24#define optproblem subgetoptproblem
25#define optprogname sgetoptprogname
26
27int opterr = 1;
28const char *optprogname = 0;
29
30int getopt(int argc,const char *const *argv,const char *opts)
31{
32 int c;
33 const char *s;
34
35 if (!optprogname) {
36 optprogname = *argv;
37 if (!optprogname) optprogname = "";
38 for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1;
39 }
40 c = subgetopt(argc,argv,opts);
41 if (opterr)
42 if (c == '?') {
43 char chp[2]; chp[0] = optproblem; chp[1] = '\n';
44 buffer_puts(buffer_2,optprogname);
45 if (argv[optind] && (optind < argc))
46 buffer_puts(buffer_2,": illegal option -- ");
47 else
48 buffer_puts(buffer_2,": option requires an argument -- ");
49 buffer_put(buffer_2,chp,2);
50 buffer_flush(buffer_2);
51 }
52 return c;
53}
diff --git a/sgetopt.h b/sgetopt.h
new file mode 100644
index 0000000..bf8bce6
--- /dev/null
+++ b/sgetopt.h
@@ -0,0 +1,23 @@
1/* Public domain. */
2
3#ifndef SGETOPT_H
4#define SGETOPT_H
5
6#ifndef SGETOPTNOSHORT
7#define getopt sgetoptmine
8#define optarg subgetoptarg
9#define optind subgetoptind
10#define optpos subgetoptpos
11#define opterr sgetopterr
12#define optproblem subgetoptproblem
13#define optprogname sgetoptprogname
14#define opteof subgetoptdone
15#endif
16
17#include "subgetopt.h"
18
19extern int sgetoptmine(int,const char *const *,const char *);
20extern int sgetopterr;
21extern const char *sgetoptprogname;
22
23#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 @@
1/* Public domain. */
2
3#ifndef STR_H
4#define STR_H
5
6extern unsigned int str_copy(char *,const char *);
7extern int str_diff(const char *,const char *);
8extern int str_diffn(const char *,const char *,unsigned int);
9extern unsigned int str_len(const char *);
10extern unsigned int str_chr(const char *,int);
11extern unsigned int str_rchr(const char *,int);
12extern int str_start(const char *,const char *);
13
14#define str_equal(s,t) (!str_diff((s),(t)))
15
16#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 @@
1/* Public domain. */
2
3#include "str.h"
4
5unsigned int str_chr(register const char *s,int c)
6{
7 register char ch;
8 register const char *t;
9
10 ch = c;
11 t = s;
12 for (;;) {
13 if (!*t) break; if (*t == ch) break; ++t;
14 if (!*t) break; if (*t == ch) break; ++t;
15 if (!*t) break; if (*t == ch) break; ++t;
16 if (!*t) break; if (*t == ch) break; ++t;
17 }
18 return t - s;
19}
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 @@
1/* Public domain. */
2
3#include "str.h"
4
5int str_diff(register const char *s,register const char *t)
6{
7 register char x;
8
9 for (;;) {
10 x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
11 x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
12 x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
13 x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
14 }
15 return ((int)(unsigned int)(unsigned char) x)
16 - ((int)(unsigned int)(unsigned char) *t);
17}
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 @@
1/* Public domain. */
2
3#include "str.h"
4
5unsigned int str_len(const char *s)
6{
7 register const char *t;
8
9 t = s;
10 for (;;) {
11 if (!*t) return t - s; ++t;
12 if (!*t) return t - s; ++t;
13 if (!*t) return t - s; ++t;
14 if (!*t) return t - s; ++t;
15 }
16}
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 @@
1/* Public domain. */
2
3#include "str.h"
4
5int str_start(register const char *s,register const char *t)
6{
7 register char x;
8
9 for (;;) {
10 x = *t++; if (!x) return 1; if (x != *s++) return 0;
11 x = *t++; if (!x) return 1; if (x != *s++) return 0;
12 x = *t++; if (!x) return 1; if (x != *s++) return 0;
13 x = *t++; if (!x) return 1; if (x != *s++) return 0;
14 }
15}
diff --git a/stralloc.h b/stralloc.h
new file mode 100644
index 0000000..51d61bd
--- /dev/null
+++ b/stralloc.h
@@ -0,0 +1,31 @@
1/* Public domain. */
2
3#ifndef STRALLOC_H
4#define STRALLOC_H
5
6#include "gen_alloc.h"
7
8GEN_ALLOC_typedef(stralloc,char,s,len,a)
9
10extern int stralloc_ready(stralloc *,unsigned int);
11extern int stralloc_readyplus(stralloc *,unsigned int);
12extern int stralloc_copy(stralloc *,const stralloc *);
13extern int stralloc_cat(stralloc *,const stralloc *);
14extern int stralloc_copys(stralloc *,const char *);
15extern int stralloc_cats(stralloc *,const char *);
16extern int stralloc_copyb(stralloc *,const char *,unsigned int);
17extern int stralloc_catb(stralloc *,const char *,unsigned int);
18extern int stralloc_append(stralloc *,const char *); /* beware: this takes a pointer to 1 char */
19extern int stralloc_starts(stralloc *,const char *);
20
21#define stralloc_0(sa) stralloc_append(sa,"")
22
23extern int stralloc_catulong0(stralloc *,unsigned long,unsigned int);
24extern int stralloc_catlong0(stralloc *,long,unsigned int);
25
26#define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0))
27#define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n)))
28#define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n)))
29#define stralloc_catint(sa,i) (stralloc_catlong0((sa),(i),0))
30
31#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 @@
1/* Public domain. */
2
3#include "byte.h"
4#include "stralloc.h"
5
6int stralloc_cat(stralloc *sato,const stralloc *safrom)
7{
8 return stralloc_catb(sato,safrom->s,safrom->len);
9}
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 @@
1/* Public domain. */
2
3#include "stralloc.h"
4#include "byte.h"
5
6int stralloc_catb(stralloc *sa,const char *s,unsigned int n)
7{
8 if (!sa->s) return stralloc_copyb(sa,s,n);
9 if (!stralloc_readyplus(sa,n + 1)) return 0;
10 byte_copy(sa->s + sa->len,n,s);
11 sa->len += n;
12 sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
13 return 1;
14}
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 @@
1/* Public domain. */
2
3#include "byte.h"
4#include "str.h"
5#include "stralloc.h"
6
7int stralloc_cats(stralloc *sa,const char *s)
8{
9 return stralloc_catb(sa,s,str_len(s));
10}
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 @@
1/* Public domain. */
2
3#include "alloc.h"
4#include "stralloc.h"
5#include "gen_allocdefs.h"
6
7GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
8GEN_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 @@
1/* Public domain. */
2
3#include "stralloc.h"
4#include "byte.h"
5
6int stralloc_copyb(stralloc *sa,const char *s,unsigned int n)
7{
8 if (!stralloc_ready(sa,n + 1)) return 0;
9 byte_copy(sa->s,n,s);
10 sa->len = n;
11 sa->s[n] = 'Z'; /* ``offensive programming'' */
12 return 1;
13}
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 @@
1/* Public domain. */
2
3#include "byte.h"
4#include "str.h"
5#include "stralloc.h"
6
7int stralloc_copys(stralloc *sa,const char *s)
8{
9 return stralloc_copyb(sa,s,str_len(s));
10}
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 @@
1/* Public domain. */
2
3#include "alloc.h"
4#include "stralloc.h"
5#include "gen_allocdefs.h"
6
7GEN_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 @@
1/* Public domain. */
2
3#ifndef STRERR_H
4#define STRERR_H
5
6struct strerr {
7 struct strerr *who;
8 const char *x;
9 const char *y;
10 const char *z;
11} ;
12
13extern struct strerr strerr_sys;
14extern void strerr_sysinit(void);
15
16extern const char *strerr(const struct strerr *);
17extern void strerr_warn(const char *,const char *,const char *,const char *,const char *,const char *,const struct strerr *);
18extern void strerr_die(int,const char *,const char *,const char *,const char *,const char *,const char *,const struct strerr *);
19
20#define STRERR(r,se,a) \
21{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; }
22
23#define STRERR_SYS(r,se,a) \
24{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; }
25#define STRERR_SYS3(r,se,a,b,c) \
26{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; }
27
28#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \
29strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(se))
30#define strerr_warn5(x1,x2,x3,x4,x5,se) \
31strerr_warn((x1),(x2),(x3),(x4),(x5),0,(se))
32#define strerr_warn4(x1,x2,x3,x4,se) \
33strerr_warn((x1),(x2),(x3),(x4),0,0,(se))
34#define strerr_warn3(x1,x2,x3,se) \
35strerr_warn((x1),(x2),(x3),0,0,0,(se))
36#define strerr_warn2(x1,x2,se) \
37strerr_warn((x1),(x2),0,0,0,0,(se))
38#define strerr_warn1(x1,se) \
39strerr_warn((x1),0,0,0,0,0,(se))
40
41#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \
42strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(se))
43#define strerr_die5(e,x1,x2,x3,x4,x5,se) \
44strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,(se))
45#define strerr_die4(e,x1,x2,x3,x4,se) \
46strerr_die((e),(x1),(x2),(x3),(x4),0,0,(se))
47#define strerr_die3(e,x1,x2,x3,se) \
48strerr_die((e),(x1),(x2),(x3),0,0,0,(se))
49#define strerr_die2(e,x1,x2,se) \
50strerr_die((e),(x1),(x2),0,0,0,0,(se))
51#define strerr_die1(e,x1,se) \
52strerr_die((e),(x1),0,0,0,0,0,(se))
53
54#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \
55strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys)
56#define strerr_die5sys(e,x1,x2,x3,x4,x5) \
57strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,&strerr_sys)
58#define strerr_die4sys(e,x1,x2,x3,x4) \
59strerr_die((e),(x1),(x2),(x3),(x4),0,0,&strerr_sys)
60#define strerr_die3sys(e,x1,x2,x3) \
61strerr_die((e),(x1),(x2),(x3),0,0,0,&strerr_sys)
62#define strerr_die2sys(e,x1,x2) \
63strerr_die((e),(x1),(x2),0,0,0,0,&strerr_sys)
64#define strerr_die1sys(e,x1) \
65strerr_die((e),(x1),0,0,0,0,0,&strerr_sys)
66
67#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \
68strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),0)
69#define strerr_die5x(e,x1,x2,x3,x4,x5) \
70strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,0)
71#define strerr_die4x(e,x1,x2,x3,x4) \
72strerr_die((e),(x1),(x2),(x3),(x4),0,0,0)
73#define strerr_die3x(e,x1,x2,x3) \
74strerr_die((e),(x1),(x2),(x3),0,0,0,0)
75#define strerr_die2x(e,x1,x2) \
76strerr_die((e),(x1),(x2),0,0,0,0,0)
77#define strerr_die1x(e,x1) \
78strerr_die((e),(x1),0,0,0,0,0,0)
79
80#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 @@
1/* Public domain. */
2
3#include <unistd.h>
4#include "buffer.h"
5#include "strerr.h"
6
7void strerr_warn(const char *x1,const char *x2,const char *x3,const char *x4,const char *x5,const char *x6,const struct strerr *se)
8{
9 strerr_sysinit();
10
11 if (x1) buffer_puts(buffer_2,x1);
12 if (x2) buffer_puts(buffer_2,x2);
13 if (x3) buffer_puts(buffer_2,x3);
14 if (x4) buffer_puts(buffer_2,x4);
15 if (x5) buffer_puts(buffer_2,x5);
16 if (x6) buffer_puts(buffer_2,x6);
17
18 while(se) {
19 if (se->x) buffer_puts(buffer_2,se->x);
20 if (se->y) buffer_puts(buffer_2,se->y);
21 if (se->z) buffer_puts(buffer_2,se->z);
22 se = se->who;
23 }
24
25 buffer_puts(buffer_2,"\n");
26 buffer_flush(buffer_2);
27}
28
29void 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)
30{
31 strerr_warn(x1,x2,x3,x4,x5,x6,se);
32 _exit(e);
33}
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 @@
1/* Public domain. */
2
3#include "error.h"
4#include "strerr.h"
5
6struct strerr strerr_sys;
7
8void strerr_sysinit(void)
9{
10 strerr_sys.who = 0;
11 strerr_sys.x = error_str(errno);
12 strerr_sys.y = "";
13 strerr_sys.z = "";
14}
diff --git a/subgetopt.c b/subgetopt.c
new file mode 100644
index 0000000..85ace96
--- /dev/null
+++ b/subgetopt.c
@@ -0,0 +1,67 @@
1/* Public domain. */
2
3#define SUBGETOPTNOSHORT
4#include "subgetopt.h"
5
6#define sgopt subgetopt
7#define optind subgetoptind
8#define optpos subgetoptpos
9#define optarg subgetoptarg
10#define optproblem subgetoptproblem
11#define optdone subgetoptdone
12
13int optind = 1;
14int optpos = 0;
15const char *optarg = 0;
16int optproblem = 0;
17int optdone = SUBGETOPTDONE;
18
19int sgopt(int argc,const char *const *argv,const char *opts)
20{
21 int c;
22 const char *s;
23
24 optarg = 0;
25 if (!argv || (optind >= argc) || !argv[optind]) return optdone;
26 if (optpos && !argv[optind][optpos]) {
27 ++optind;
28 optpos = 0;
29 if ((optind >= argc) || !argv[optind]) return optdone;
30 }
31 if (!optpos) {
32 if (argv[optind][0] != '-') return optdone;
33 ++optpos;
34 c = argv[optind][1];
35 if ((c == '-') || (c == 0)) {
36 if (c) ++optind;
37 optpos = 0;
38 return optdone;
39 }
40 /* otherwise c is reassigned below */
41 }
42 c = argv[optind][optpos];
43 ++optpos;
44 s = opts;
45 while (*s) {
46 if (c == *s) {
47 if (s[1] == ':') {
48 optarg = argv[optind] + optpos;
49 ++optind;
50 optpos = 0;
51 if (!*optarg) {
52 optarg = argv[optind];
53 if ((optind >= argc) || !optarg) { /* argument past end */
54 optproblem = c;
55 return '?';
56 }
57 ++optind;
58 }
59 }
60 return c;
61 }
62 ++s;
63 if (*s == ':') ++s;
64 }
65 optproblem = c;
66 return '?';
67}
diff --git a/subgetopt.h b/subgetopt.h
new file mode 100644
index 0000000..41ad26a
--- /dev/null
+++ b/subgetopt.h
@@ -0,0 +1,26 @@
1/* Public domain. */
2
3#ifndef SUBGETOPT_H
4#define SUBGETOPT_H
5
6#ifndef SUBGETOPTNOSHORT
7#define sgopt subgetopt
8#define sgoptarg subgetoptarg
9#define sgoptind subgetoptind
10#define sgoptpos subgetoptpos
11#define sgoptproblem subgetoptproblem
12#define sgoptprogname subgetoptprogname
13#define sgoptdone subgetoptdone
14#endif
15
16#define SUBGETOPTDONE -1
17
18extern int subgetopt(int,const char *const *,const char *);
19extern const char *subgetoptarg;
20extern int subgetoptind;
21extern int subgetoptpos;
22extern int subgetoptproblem;
23extern const char *subgetoptprogname;
24extern int subgetoptdone;
25
26#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 @@
1#include <sys/types.h>
2#include <pwd.h>
3#include <grp.h>
4#include "uidgid.h"
5#include "str.h"
6#include "scan.h"
7
8/* user */
9unsigned int uidgid_get(struct uidgid *u, char *ug) {
10 struct passwd *pwd =0;
11
12 if (! (pwd =getpwnam(ug))) return(0);
13 u->gid[0] =pwd->pw_gid; u->gids =1;
14 u->uid =pwd->pw_uid;
15 return(1);
16}
17
18/* uid:gid[:gid[:gid]...] */
19unsigned int uidgids_set(struct uidgid *u, char *ug) {
20 unsigned long id;
21 int i;
22
23 if (*(ug +=scan_ulong(ug, &id)) != ':') return(0);
24 u->uid =(uid_t)id;
25 ++ug;
26 for (i =0; i < 60; ++i, ++ug) {
27 ug +=scan_ulong(ug, &id);
28 u->gid[i] =(gid_t)id;
29 if (*ug != ':') { ++i; break; }
30 }
31 u->gid[i] =0;
32 u->gids =i;
33 if (*ug) return(0);
34 return(1);
35}
36
37/* [:]user[:group[:group]...] */
38unsigned int uidgids_get(struct uidgid *u, char *ug) {
39 char *g =0;
40 struct passwd *pwd =0;
41 struct group *gr =0;
42 int i, d =0;
43
44 if (*ug == ':') return(uidgids_set(u, ug +1));
45 if (ug[(d =str_chr(ug, ':'))] == ':') {
46 ug[d] =0;
47 g =ug +d +1;
48 }
49 if (! (pwd =getpwnam(ug))) { if (g) ug[d] =':'; return(0); }
50 u->uid =pwd->pw_uid;
51 if (! g) {
52 u->gid[0] =pwd->pw_gid;
53 u->gids =1;
54 return(1);
55 }
56 ug[d] =':';
57 for (i =0; i < 60; ++i) {
58 if (g[(d =str_chr(g, ':'))] == ':') {
59 g[d] =0;
60 if (! (gr =getgrnam(g))) { g[d] =':'; return(0); }
61 g[d] =':';
62 u->gid[i] =gr->gr_gid;
63 g +=d +1;
64 }
65 else {
66 if (! (gr =getgrnam(g))) return(0);
67 u->gid[i++] =gr->gr_gid;
68 break;
69 }
70 }
71 u->gid[i] =0;
72 u->gids =i;
73 return(1);
74}
diff --git a/uidgid.h b/uidgid.h
new file mode 100644
index 0000000..13cacbc
--- /dev/null
+++ b/uidgid.h
@@ -0,0 +1,18 @@
1#ifndef UIDGID_H
2#define UIDGID_H
3
4#include <sys/types.h>
5
6struct uidgid {
7 uid_t uid;
8 gid_t gid[61];
9 int gids;
10};
11
12/* user */
13extern unsigned int uidgid_get(struct uidgid *, char *);
14
15/* [:]user[:group[:group]...] */
16extern unsigned int uidgids_get(struct uidgid *, char *);
17
18#endif