25 |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 |
*/ |
*/ |
27 |
|
|
28 |
/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */ |
/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */ |
29 |
/* Collected into one file from runit's many tiny files */ |
/* Collected into one file from runit's many tiny files */ |
30 |
/* TODO: review, eliminate unneeded stuff, move good stuff to libbb */ |
/* TODO: review, eliminate unneeded stuff, move good stuff to libbb */ |
31 |
|
|
34 |
#include "libbb.h" |
#include "libbb.h" |
35 |
#include "runit_lib.h" |
#include "runit_lib.h" |
36 |
|
|
|
/*** buffer.c ***/ |
|
|
|
|
|
void buffer_init(buffer *s,int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len) |
|
|
{ |
|
|
s->x = buf; |
|
|
s->fd = fd; |
|
|
s->op = op; |
|
|
s->p = 0; |
|
|
s->n = len; |
|
|
} |
|
|
|
|
|
|
|
|
/*** buffer_get.c ***/ |
|
|
|
|
|
static int oneread(int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len) |
|
|
{ |
|
|
int r; |
|
|
|
|
|
for (;;) { |
|
|
r = op(fd,buf,len); |
|
|
if (r == -1) if (errno == EINTR) continue; |
|
|
return r; |
|
|
} |
|
|
} |
|
|
|
|
|
static int getthis(buffer *s,char *buf,unsigned len) |
|
|
{ |
|
|
if (len > s->p) len = s->p; |
|
|
s->p -= len; |
|
|
memcpy(buf,s->x + s->n,len); |
|
|
s->n += len; |
|
|
return len; |
|
|
} |
|
|
|
|
|
int buffer_feed(buffer *s) |
|
|
{ |
|
|
int r; |
|
|
|
|
|
if (s->p) return s->p; |
|
|
r = oneread(s->op,s->fd,s->x,s->n); |
|
|
if (r <= 0) return r; |
|
|
s->p = r; |
|
|
s->n -= r; |
|
|
if (s->n > 0) memmove(s->x + s->n,s->x,r); |
|
|
return r; |
|
|
} |
|
|
|
|
|
int buffer_bget(buffer *s,char *buf,unsigned len) |
|
|
{ |
|
|
int r; |
|
|
|
|
|
if (s->p > 0) return getthis(s,buf,len); |
|
|
if (s->n <= len) return oneread(s->op,s->fd,buf,s->n); |
|
|
r = buffer_feed(s); if (r <= 0) return r; |
|
|
return getthis(s,buf,len); |
|
|
} |
|
|
|
|
|
int buffer_get(buffer *s,char *buf,unsigned len) |
|
|
{ |
|
|
int r; |
|
|
|
|
|
if (s->p > 0) return getthis(s,buf,len); |
|
|
if (s->n <= len) return oneread(s->op,s->fd,buf,len); |
|
|
r = buffer_feed(s); if (r <= 0) return r; |
|
|
return getthis(s,buf,len); |
|
|
} |
|
|
|
|
|
char *buffer_peek(buffer *s) |
|
|
{ |
|
|
return s->x + s->n; |
|
|
} |
|
|
|
|
|
void buffer_seek(buffer *s,unsigned len) |
|
|
{ |
|
|
s->n += len; |
|
|
s->p -= len; |
|
|
} |
|
|
|
|
|
|
|
|
/*** buffer_put.c ***/ |
|
|
|
|
|
static int allwrite(int (*op)(int fd,char *buf,unsigned len),int fd,const char *buf,unsigned len) |
|
|
{ |
|
|
int w; |
|
|
|
|
|
while (len) { |
|
|
w = op(fd,(char*)buf,len); |
|
|
if (w == -1) { |
|
|
if (errno == EINTR) 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 len) |
|
|
{ |
|
|
unsigned n; |
|
|
|
|
|
while (len > (n = s->n - s->p)) { |
|
|
memcpy(s->x + s->p,buf,n); |
|
|
s->p += n; |
|
|
buf += n; |
|
|
len -= n; |
|
|
if (buffer_flush(s) == -1) return -1; |
|
|
} |
|
|
/* now len <= s->n - s->p */ |
|
|
memcpy(s->x + s->p,buf,len); |
|
|
s->p += len; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int buffer_put(buffer *s,const char *buf,unsigned len) |
|
|
{ |
|
|
unsigned 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 */ |
|
|
memcpy(s->x + s->p,buf,len); |
|
|
s->p += len; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int buffer_putflush(buffer *s,const char *buf,unsigned 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,strlen(buf)); |
|
|
} |
|
|
|
|
|
int buffer_puts(buffer *s,const char *buf) |
|
|
{ |
|
|
return buffer_put(s,buf,strlen(buf)); |
|
|
} |
|
|
|
|
|
int buffer_putsflush(buffer *s,const char *buf) |
|
|
{ |
|
|
return buffer_putflush(s,buf,strlen(buf)); |
|
|
} |
|
|
|
|
|
|
|
|
/*** buffer_read.c ***/ |
|
|
|
|
|
int buffer_unixread(int fd,char *buf,unsigned len) |
|
|
{ |
|
|
return read(fd,buf,len); |
|
|
} |
|
|
|
|
|
|
|
|
/*** buffer_write.c ***/ |
|
|
|
|
|
int buffer_unixwrite(int fd,char *buf,unsigned len) |
|
|
{ |
|
|
return write(fd,buf,len); |
|
|
} |
|
|
|
|
|
|
|
|
/*** byte_chr.c ***/ |
|
|
|
|
37 |
unsigned byte_chr(char *s,unsigned n,int c) |
unsigned byte_chr(char *s,unsigned n,int c) |
38 |
{ |
{ |
39 |
char ch; |
char ch; |
42 |
ch = c; |
ch = c; |
43 |
t = s; |
t = s; |
44 |
for (;;) { |
for (;;) { |
45 |
if (!n) break; if (*t == ch) break; ++t; --n; |
if (!n) break; |
46 |
if (!n) break; if (*t == ch) break; ++t; --n; |
if (*t == ch) break; |
47 |
if (!n) break; if (*t == ch) break; ++t; --n; |
++t; |
48 |
if (!n) break; if (*t == ch) break; ++t; --n; |
--n; |
49 |
} |
} |
50 |
return t - s; |
return t - s; |
51 |
} |
} |
52 |
|
|
53 |
|
#ifdef UNUSED |
54 |
/*** coe.c ***/ |
static /* as it isn't used anywhere else */ |
55 |
|
void tai_pack(char *s, const struct tai *t) |
|
int coe(int fd) |
|
|
{ |
|
|
return fcntl(fd,F_SETFD,FD_CLOEXEC); |
|
|
} |
|
|
|
|
|
|
|
|
/*** fd_copy.c ***/ |
|
|
|
|
|
int fd_copy(int to,int from) |
|
|
{ |
|
|
if (to == from) return 0; |
|
|
if (fcntl(from,F_GETFL,0) == -1) return -1; |
|
|
close(to); |
|
|
if (fcntl(from,F_DUPFD,to) == -1) return -1; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
/*** fd_move.c ***/ |
|
|
|
|
|
int fd_move(int to,int from) |
|
|
{ |
|
|
if (to == from) return 0; |
|
|
if (fd_copy(to,from) == -1) return -1; |
|
|
close(from); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
/*** fifo.c ***/ |
|
|
|
|
|
int fifo_make(const char *fn,int mode) { return mkfifo(fn,mode); } |
|
|
|
|
|
|
|
|
/*** fmt_ptime.c ***/ |
|
|
|
|
|
unsigned fmt_ptime(char *s, struct taia *ta) { |
|
|
struct tm *t; |
|
|
unsigned long u; |
|
|
|
|
|
if (ta->sec.x < 4611686018427387914ULL) return 0; /* impossible? */ |
|
|
u = ta->sec.x -4611686018427387914ULL; |
|
|
if (!(t = gmtime((time_t*)&u))) return 0; |
|
|
fmt_ulong(s, 1900 + t->tm_year); |
|
|
s[4] = '-'; fmt_uint0(&s[5], t->tm_mon+1, 2); |
|
|
s[7] = '-'; fmt_uint0(&s[8], t->tm_mday, 2); |
|
|
s[10] = '_'; fmt_uint0(&s[11], t->tm_hour, 2); |
|
|
s[13] = ':'; fmt_uint0(&s[14], t->tm_min, 2); |
|
|
s[16] = ':'; fmt_uint0(&s[17], t->tm_sec, 2); |
|
|
s[19] = '.'; fmt_uint0(&s[20], ta->nano, 9); |
|
|
return 25; |
|
|
} |
|
|
|
|
|
unsigned fmt_taia(char *s, struct taia *t) { |
|
|
static char pack[TAIA_PACK]; |
|
|
|
|
|
taia_pack(pack, t); |
|
|
*s++ = '@'; |
|
|
bin2hex(s, pack, 12); |
|
|
return 25; |
|
|
} |
|
|
|
|
|
|
|
|
/*** fmt_uint.c ***/ |
|
|
|
|
|
unsigned fmt_uint(char *s,unsigned u) |
|
|
{ |
|
|
return fmt_ulong(s,u); |
|
|
} |
|
|
|
|
|
|
|
|
/*** fmt_uint0.c ***/ |
|
|
|
|
|
unsigned fmt_uint0(char *s,unsigned u,unsigned n) |
|
|
{ |
|
|
unsigned len; |
|
|
len = fmt_uint(FMT_LEN,u); |
|
|
while (len < n) { if (s) *s++ = '0'; ++len; } |
|
|
if (s) fmt_uint(s,u); |
|
|
return len; |
|
|
} |
|
|
|
|
|
|
|
|
/*** fmt_ulong.c ***/ |
|
|
|
|
|
unsigned fmt_ulong(char *s,unsigned long u) |
|
|
{ |
|
|
unsigned len; 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; |
|
|
} |
|
|
|
|
|
|
|
|
/*** tai_now.c ***/ |
|
|
|
|
|
void tai_now(struct tai *t) |
|
|
{ |
|
|
tai_unix(t,time((time_t *) 0)); |
|
|
} |
|
|
|
|
|
|
|
|
/*** tai_pack.c ***/ |
|
|
|
|
|
void tai_pack(char *s,const struct tai *t) |
|
56 |
{ |
{ |
57 |
uint64_t x; |
uint64_t x; |
58 |
|
|
67 |
s[0] = x; |
s[0] = x; |
68 |
} |
} |
69 |
|
|
|
|
|
|
/*** tai_sub.c ***/ |
|
|
|
|
|
void tai_sub(struct tai *t,const struct tai *u,const struct tai *v) |
|
|
{ |
|
|
t->x = u->x - v->x; |
|
|
} |
|
|
|
|
|
|
|
|
/*** tai_unpack.c ***/ |
|
|
|
|
70 |
void tai_unpack(const char *s,struct tai *t) |
void tai_unpack(const char *s,struct tai *t) |
71 |
{ |
{ |
72 |
uint64_t x; |
uint64_t x; |
83 |
} |
} |
84 |
|
|
85 |
|
|
|
/*** taia_add.c ***/ |
|
|
|
|
|
/* XXX: breaks tai encapsulation */ |
|
|
|
|
86 |
void taia_add(struct taia *t,const struct taia *u,const struct taia *v) |
void taia_add(struct taia *t,const struct taia *u,const struct taia *v) |
87 |
{ |
{ |
88 |
t->sec.x = u->sec.x + v->sec.x; |
t->sec.x = u->sec.x + v->sec.x; |
98 |
} |
} |
99 |
} |
} |
100 |
|
|
101 |
|
int taia_less(const struct taia *t, const struct taia *u) |
|
/*** taia_approx.c ***/ |
|
|
|
|
|
double taia_approx(const struct taia *t) |
|
|
{ |
|
|
return tai_approx(&t->sec) + taia_frac(t); |
|
|
} |
|
|
|
|
|
|
|
|
/*** taia_frac.c ***/ |
|
|
|
|
|
double taia_frac(const struct taia *t) |
|
|
{ |
|
|
return (t->atto * 0.000000001 + t->nano) * 0.000000001; |
|
|
} |
|
|
|
|
|
|
|
|
/*** taia_less.c ***/ |
|
|
|
|
|
/* XXX: breaks tai encapsulation */ |
|
|
|
|
|
int taia_less(const struct taia *t,const struct taia *u) |
|
102 |
{ |
{ |
103 |
if (t->sec.x < u->sec.x) return 1; |
if (t->sec.x < u->sec.x) return 1; |
104 |
if (t->sec.x > u->sec.x) return 0; |
if (t->sec.x > u->sec.x) return 0; |
107 |
return t->atto < u->atto; |
return t->atto < u->atto; |
108 |
} |
} |
109 |
|
|
|
|
|
|
/*** taia_now.c ***/ |
|
|
|
|
110 |
void taia_now(struct taia *t) |
void taia_now(struct taia *t) |
111 |
{ |
{ |
112 |
struct timeval now; |
struct timeval now; |
113 |
gettimeofday(&now,(struct timezone *) 0); |
gettimeofday(&now, NULL); |
114 |
tai_unix(&t->sec,now.tv_sec); |
tai_unix(&t->sec, now.tv_sec); |
115 |
t->nano = 1000 * now.tv_usec + 500; |
t->nano = 1000 * now.tv_usec + 500; |
116 |
t->atto = 0; |
t->atto = 0; |
117 |
} |
} |
118 |
|
|
119 |
|
/* UNUSED |
120 |
/*** taia_pack.c ***/ |
void taia_pack(char *s, const struct taia *t) |
|
|
|
|
void taia_pack(char *s,const struct taia *t) |
|
121 |
{ |
{ |
122 |
unsigned long x; |
unsigned long x; |
123 |
|
|
124 |
tai_pack(s,&t->sec); |
tai_pack(s, &t->sec); |
125 |
s += 8; |
s += 8; |
126 |
|
|
127 |
x = t->atto; |
x = t->atto; |
135 |
s[1] = x & 255; x >>= 8; |
s[1] = x & 255; x >>= 8; |
136 |
s[0] = x; |
s[0] = x; |
137 |
} |
} |
138 |
|
*/ |
139 |
|
|
140 |
|
void taia_sub(struct taia *t, const struct taia *u, const struct taia *v) |
|
/*** taia_sub.c ***/ |
|
|
|
|
|
/* XXX: breaks tai encapsulation */ |
|
|
|
|
|
void taia_sub(struct taia *t,const struct taia *u,const struct taia *v) |
|
141 |
{ |
{ |
142 |
unsigned long unano = u->nano; |
unsigned long unano = u->nano; |
143 |
unsigned long uatto = u->atto; |
unsigned long uatto = u->atto; |
155 |
} |
} |
156 |
} |
} |
157 |
|
|
|
|
|
|
/*** taia_uint.c ***/ |
|
|
|
|
158 |
/* XXX: breaks tai encapsulation */ |
/* XXX: breaks tai encapsulation */ |
159 |
|
void taia_uint(struct taia *t, unsigned s) |
|
void taia_uint(struct taia *t,unsigned s) |
|
160 |
{ |
{ |
161 |
t->sec.x = s; |
t->sec.x = s; |
162 |
t->nano = 0; |
t->nano = 0; |
163 |
t->atto = 0; |
t->atto = 0; |
164 |
} |
} |
165 |
|
|
166 |
|
static |
167 |
/*** stralloc_cat.c ***/ |
uint64_t taia2millisec(const struct taia *t) |
|
#if 0 |
|
|
|
|
|
int stralloc_cat(stralloc *sato,const stralloc *safrom) |
|
|
{ |
|
|
return stralloc_catb(sato,safrom->s,safrom->len); |
|
|
} |
|
|
|
|
|
|
|
|
/*** stralloc_catb.c ***/ |
|
|
|
|
|
int stralloc_catb(stralloc *sa,const char *s,unsigned n) |
|
|
{ |
|
|
if (!sa->s) return stralloc_copyb(sa,s,n); |
|
|
if (!stralloc_readyplus(sa,n + 1)) return 0; |
|
|
memcpy(sa->s + sa->len,s,n); |
|
|
sa->len += n; |
|
|
sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ |
|
|
return 1; |
|
|
} |
|
|
|
|
|
|
|
|
/*** stralloc_cats.c ***/ |
|
|
|
|
|
int stralloc_cats(stralloc *sa,const char *s) |
|
|
{ |
|
|
return stralloc_catb(sa,s,strlen(s)); |
|
|
} |
|
|
|
|
|
|
|
|
/*** stralloc_eady.c ***/ |
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
/*** stralloc_opyb.c ***/ |
|
|
|
|
|
int stralloc_copyb(stralloc *sa,const char *s,unsigned n) |
|
168 |
{ |
{ |
169 |
if (!stralloc_ready(sa,n + 1)) return 0; |
return (t->sec.x * 1000) + (t->nano / 1000000); |
|
memcpy(sa->s,s,n); |
|
|
sa->len = n; |
|
|
sa->s[n] = 'Z'; /* ``offensive programming'' */ |
|
|
return 1; |
|
170 |
} |
} |
171 |
|
|
172 |
|
void iopause(iopause_fd *x, unsigned len, struct taia *deadline, struct taia *stamp) |
|
/*** stralloc_opys.c ***/ |
|
|
|
|
|
int stralloc_copys(stralloc *sa,const char *s) |
|
173 |
{ |
{ |
|
return stralloc_copyb(sa,s,strlen(s)); |
|
|
} |
|
|
|
|
|
|
|
|
/*** stralloc_pend.c ***/ |
|
|
|
|
|
GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) |
|
|
|
|
|
#endif /* stralloc */ |
|
|
|
|
|
/*** iopause.c ***/ |
|
|
|
|
|
void iopause(iopause_fd *x,unsigned len,struct taia *deadline,struct taia *stamp) |
|
|
{ |
|
|
struct taia t; |
|
174 |
int millisecs; |
int millisecs; |
|
double d; |
|
175 |
int i; |
int i; |
176 |
|
|
177 |
if (taia_less(deadline,stamp)) |
if (taia_less(deadline, stamp)) |
178 |
millisecs = 0; |
millisecs = 0; |
179 |
else { |
else { |
180 |
|
uint64_t m; |
181 |
|
struct taia t; |
182 |
t = *stamp; |
t = *stamp; |
183 |
taia_sub(&t,deadline,&t); |
taia_sub(&t, deadline, &t); |
184 |
d = taia_approx(&t); |
millisecs = m = taia2millisec(&t); |
185 |
if (d > 1000.0) d = 1000.0; |
if (m > 1000) millisecs = 1000; |
186 |
millisecs = d * 1000.0 + 20.0; |
millisecs += 20; |
187 |
} |
} |
188 |
|
|
189 |
for (i = 0;i < len;++i) |
for (i = 0; i < len; ++i) |
190 |
x[i].revents = 0; |
x[i].revents = 0; |
191 |
|
|
192 |
poll(x,len,millisecs); |
poll(x, len, millisecs); |
193 |
/* XXX: some kernels apparently need x[0] even if len is 0 */ |
/* XXX: some kernels apparently need x[0] even if len is 0 */ |
194 |
/* XXX: how to handle EAGAIN? are kernels really this dumb? */ |
/* XXX: how to handle EAGAIN? are kernels really this dumb? */ |
195 |
/* XXX: how to handle EINVAL? when exactly can this happen? */ |
/* XXX: how to handle EINVAL? when exactly can this happen? */ |
196 |
} |
} |
197 |
|
#endif |
|
|
|
|
/*** lock_ex.c ***/ |
|
198 |
|
|
199 |
int lock_ex(int fd) |
int lock_ex(int fd) |
200 |
{ |
{ |
201 |
return flock(fd,LOCK_EX); |
return flock(fd,LOCK_EX); |
202 |
} |
} |
203 |
|
|
|
|
|
|
/*** lock_exnb.c ***/ |
|
|
|
|
204 |
int lock_exnb(int fd) |
int lock_exnb(int fd) |
205 |
{ |
{ |
206 |
return flock(fd,LOCK_EX | LOCK_NB); |
return flock(fd,LOCK_EX | LOCK_NB); |
207 |
} |
} |
208 |
|
|
|
|
|
|
/*** open_append.c ***/ |
|
|
|
|
209 |
int open_append(const char *fn) |
int open_append(const char *fn) |
210 |
{ |
{ |
211 |
return open(fn, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); |
return open(fn, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); |
212 |
} |
} |
213 |
|
|
|
|
|
|
/*** open_read.c ***/ |
|
|
|
|
214 |
int open_read(const char *fn) |
int open_read(const char *fn) |
215 |
{ |
{ |
216 |
return open(fn, O_RDONLY|O_NDELAY); |
return open(fn, O_RDONLY|O_NDELAY); |
217 |
} |
} |
218 |
|
|
|
|
|
|
/*** open_trunc.c ***/ |
|
|
|
|
219 |
int open_trunc(const char *fn) |
int open_trunc(const char *fn) |
220 |
{ |
{ |
221 |
return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); |
return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); |
222 |
} |
} |
223 |
|
|
|
|
|
|
/*** open_write.c ***/ |
|
|
|
|
224 |
int open_write(const char *fn) |
int open_write(const char *fn) |
225 |
{ |
{ |
226 |
return open(fn, O_WRONLY|O_NDELAY); |
return open(fn, O_WRONLY|O_NDELAY); |
227 |
} |
} |
228 |
|
|
229 |
|
unsigned pmatch(const char *p, const char *s, unsigned len) |
|
/*** openreadclose.c ***/ |
|
|
#if 0 |
|
|
int openreadclose(const char *fn,stralloc *sa,unsigned bufsize) |
|
|
{ |
|
|
int fd; |
|
|
fd = open_read(fn); |
|
|
if (fd == -1) { |
|
|
if (errno == ENOENT) return 0; |
|
|
return -1; |
|
|
} |
|
|
if (readclose(fd,sa,bufsize) == -1) return -1; |
|
|
return 1; |
|
|
} |
|
|
#endif |
|
|
|
|
|
|
|
|
/*** pathexec_env.c ***/ |
|
|
#if 0 |
|
|
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(char **argv) |
|
230 |
{ |
{ |
|
char **e; |
|
|
unsigned elen; |
|
|
unsigned i; |
|
|
unsigned j; |
|
|
unsigned split; |
|
|
unsigned 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 = malloc((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 (memcmp(plus.s + j,e[t],split) == 0) |
|
|
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(*argv,argv,e); |
|
|
free(e); |
|
|
} |
|
|
#endif |
|
|
|
|
|
/*** pathexec_run.c ***/ |
|
|
#if 0 |
|
|
static stralloc tmp; |
|
|
|
|
|
void pathexec_run(const char *file,char *const *argv,char *const *envp) |
|
|
{ |
|
|
const char *path; |
|
|
unsigned split; |
|
|
int savederrno; |
|
|
|
|
|
if (file[str_chr(file,'/')]) { |
|
|
execve(file,argv,envp); |
|
|
return; |
|
|
} |
|
|
|
|
|
path = getenv("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 != ENOENT) { |
|
|
savederrno = errno; |
|
|
if ((errno != EACCES) && (errno != EPERM) && (errno != EISDIR)) return; |
|
|
} |
|
|
|
|
|
if (!path[split]) { |
|
|
if (savederrno) errno = savederrno; |
|
|
return; |
|
|
} |
|
|
path += split; |
|
|
path += 1; |
|
|
} |
|
|
} |
|
|
#endif |
|
|
|
|
|
/*** pmatch.c ***/ |
|
|
|
|
|
unsigned pmatch(const char *p, const char *s, unsigned len) { |
|
231 |
for (;;) { |
for (;;) { |
232 |
char c = *p++; |
char c = *p++; |
233 |
if (!c) return !len; |
if (!c) return !len; |
234 |
switch (c) { |
switch (c) { |
235 |
case '*': |
case '*': |
236 |
if (!(c = *p)) return 1; |
c = *p; |
237 |
|
if (!c) return 1; |
238 |
for (;;) { |
for (;;) { |
239 |
if (!len) return 0; |
if (!len) return 0; |
240 |
if (*s == c) break; |
if (*s == c) break; |
241 |
++s; --len; |
++s; |
242 |
|
--len; |
243 |
} |
} |
244 |
continue; |
continue; |
245 |
case '+': |
case '+': |
246 |
if ((c = *p++) != *s) return 0; |
c = *p++; |
247 |
|
if (c != *s) return 0; |
248 |
for (;;) { |
for (;;) { |
249 |
if (!len) return 1; |
if (!len) return 1; |
250 |
if (*s != c) break; |
if (*s != c) break; |
251 |
++s; --len; |
++s; |
252 |
|
--len; |
253 |
} |
} |
254 |
continue; |
continue; |
255 |
/* |
/* |
264 |
default: |
default: |
265 |
if (!len) return 0; |
if (!len) return 0; |
266 |
if (*s != c) return 0; |
if (*s != c) return 0; |
267 |
++s; --len; |
++s; |
268 |
|
--len; |
269 |
continue; |
continue; |
270 |
} |
} |
271 |
} |
} |
272 |
return 0; |
return 0; |
273 |
} |
} |
|
|
|
|
|
|
|
/*** prot.c ***/ |
|
|
|
|
|
int prot_gid(int gid) |
|
|
{ |
|
|
gid_t x = gid; |
|
|
if (setgroups(1,&x) == -1) return -1; |
|
|
return setgid(gid); /* _should_ be redundant, but on some systems it isn't */ |
|
|
} |
|
|
|
|
|
int prot_uid(int uid) |
|
|
{ |
|
|
return setuid(uid); |
|
|
} |
|
|
|
|
|
|
|
|
/*** readclose.c ***/ |
|
|
#if 0 |
|
|
int readclose_append(int fd,stralloc *sa,unsigned 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 == EINTR) continue; |
|
|
if (r <= 0) { close(fd); return r; } |
|
|
sa->len += r; |
|
|
} |
|
|
} |
|
|
|
|
|
int readclose(int fd,stralloc *sa,unsigned bufsize) |
|
|
{ |
|
|
if (!stralloc_copys(sa,"")) { close(fd); return -1; } |
|
|
return readclose_append(fd,sa,bufsize); |
|
|
} |
|
|
#endif |
|
|
|
|
|
/*** scan_ulong.c ***/ |
|
|
|
|
|
unsigned scan_ulong(const char *s,unsigned long *u) |
|
|
{ |
|
|
unsigned pos = 0; |
|
|
unsigned long result = 0; |
|
|
unsigned long c; |
|
|
while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) { |
|
|
result = result * 10 + c; |
|
|
++pos; |
|
|
} |
|
|
*u = result; |
|
|
return pos; |
|
|
} |
|
|
|
|
|
|
|
|
/*** seek_set.c ***/ |
|
|
|
|
|
int seek_set(int fd,seek_pos pos) |
|
|
{ |
|
|
if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; return 0; |
|
|
} |
|
|
|
|
|
|
|
|
/*** sig.c ***/ |
|
|
|
|
|
int sig_alarm = SIGALRM; |
|
|
int sig_child = SIGCHLD; |
|
|
int sig_cont = SIGCONT; |
|
|
int sig_hangup = SIGHUP; |
|
|
int sig_int = SIGINT; |
|
|
int sig_pipe = SIGPIPE; |
|
|
int sig_term = SIGTERM; |
|
|
|
|
|
void (*sig_defaulthandler)(int) = SIG_DFL; |
|
|
void (*sig_ignorehandler)(int) = SIG_IGN; |
|
|
|
|
|
|
|
|
/*** sig_block.c ***/ |
|
|
|
|
|
void sig_block(int sig) |
|
|
{ |
|
|
sigset_t ss; |
|
|
sigemptyset(&ss); |
|
|
sigaddset(&ss,sig); |
|
|
sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0); |
|
|
} |
|
|
|
|
|
void sig_unblock(int sig) |
|
|
{ |
|
|
sigset_t ss; |
|
|
sigemptyset(&ss); |
|
|
sigaddset(&ss,sig); |
|
|
sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0); |
|
|
} |
|
|
|
|
|
void sig_blocknone(void) |
|
|
{ |
|
|
sigset_t ss; |
|
|
sigemptyset(&ss); |
|
|
sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0); |
|
|
} |
|
|
|
|
|
|
|
|
/*** sig_catch.c ***/ |
|
|
|
|
|
void sig_catch(int sig,void (*f)(int)) |
|
|
{ |
|
|
struct sigaction sa; |
|
|
sa.sa_handler = f; |
|
|
sa.sa_flags = 0; |
|
|
sigemptyset(&sa.sa_mask); |
|
|
sigaction(sig,&sa,(struct sigaction *) 0); |
|
|
} |
|
|
|
|
|
|
|
|
/*** sig_pause.c ***/ |
|
|
|
|
|
void sig_pause(void) |
|
|
{ |
|
|
sigset_t ss; |
|
|
sigemptyset(&ss); |
|
|
sigsuspend(&ss); |
|
|
} |
|
|
|
|
|
|
|
|
/*** str_chr.c ***/ |
|
|
|
|
|
unsigned str_chr(const char *s,int c) |
|
|
{ |
|
|
char ch; |
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
/*** wait_nohang.c ***/ |
|
|
|
|
|
int wait_nohang(int *wstat) |
|
|
{ |
|
|
return waitpid(-1,wstat,WNOHANG); |
|
|
} |
|
|
|
|
|
|
|
|
/*** wait_pid.c ***/ |
|
|
|
|
|
int wait_pid(int *wstat, int pid) |
|
|
{ |
|
|
int r; |
|
|
|
|
|
do |
|
|
r = waitpid(pid,wstat,0); |
|
|
while ((r == -1) && (errno == EINTR)); |
|
|
return r; |
|
|
} |
|