| /* |
| Copyright (c) 2001-2006, Gerrit Pape |
| All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are met: |
| |
| 1. Redistributions of source code must retain the above copyright notice, |
| this list of conditions and the following disclaimer. |
| 2. Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| 3. The name of the author may not be used to endorse or promote products |
| derived from this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */ |
| /* Collected into one file from runit's many tiny files */ |
| /* TODO: review, eliminate unneeded stuff, move good stuff to libbb */ |
| |
| #include <sys/poll.h> |
| #include <sys/file.h> |
| #include "libbb.h" |
| #include "runit_lib.h" |
| |
| /*** 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 ***/ |
| |
| unsigned byte_chr(char *s,unsigned n,int c) |
| { |
| char ch; |
| 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; |
| } |
| |
| |
| /*** coe.c ***/ |
| |
| 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) |
| { |
| uint64_t x; |
| |
| x = t->x; |
| s[7] = x & 255; x >>= 8; |
| s[6] = x & 255; x >>= 8; |
| s[5] = x & 255; x >>= 8; |
| s[4] = x & 255; x >>= 8; |
| s[3] = x & 255; x >>= 8; |
| s[2] = x & 255; x >>= 8; |
| s[1] = x & 255; x >>= 8; |
| s[0] = x; |
| } |
| |
| |
| /*** 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 ***/ |
| |
| void tai_unpack(const char *s,struct tai *t) |
| { |
| uint64_t x; |
| |
| x = (unsigned char) s[0]; |
| x <<= 8; x += (unsigned char) s[1]; |
| x <<= 8; x += (unsigned char) s[2]; |
| x <<= 8; x += (unsigned char) s[3]; |
| x <<= 8; x += (unsigned char) s[4]; |
| x <<= 8; x += (unsigned char) s[5]; |
| x <<= 8; x += (unsigned char) s[6]; |
| x <<= 8; x += (unsigned char) s[7]; |
| t->x = x; |
| } |
| |
| |
| /*** taia_add.c ***/ |
| |
| /* XXX: breaks tai encapsulation */ |
| |
| void taia_add(struct taia *t,const struct taia *u,const struct taia *v) |
| { |
| t->sec.x = u->sec.x + v->sec.x; |
| t->nano = u->nano + v->nano; |
| t->atto = u->atto + v->atto; |
| if (t->atto > 999999999UL) { |
| t->atto -= 1000000000UL; |
| ++t->nano; |
| } |
| if (t->nano > 999999999UL) { |
| t->nano -= 1000000000UL; |
| ++t->sec.x; |
| } |
| } |
| |
| |
| /*** 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) |
| { |
| if (t->sec.x < u->sec.x) return 1; |
| if (t->sec.x > u->sec.x) return 0; |
| if (t->nano < u->nano) return 1; |
| if (t->nano > u->nano) return 0; |
| return t->atto < u->atto; |
| } |
| |
| |
| /*** taia_now.c ***/ |
| |
| void taia_now(struct taia *t) |
| { |
| struct timeval now; |
| gettimeofday(&now,(struct timezone *) 0); |
| tai_unix(&t->sec,now.tv_sec); |
| t->nano = 1000 * now.tv_usec + 500; |
| t->atto = 0; |
| } |
| |
| |
| /*** taia_pack.c ***/ |
| |
| void taia_pack(char *s,const struct taia *t) |
| { |
| unsigned long x; |
| |
| tai_pack(s,&t->sec); |
| s += 8; |
| |
| x = t->atto; |
| s[7] = x & 255; x >>= 8; |
| s[6] = x & 255; x >>= 8; |
| s[5] = x & 255; x >>= 8; |
| s[4] = x; |
| x = t->nano; |
| s[3] = x & 255; x >>= 8; |
| s[2] = x & 255; x >>= 8; |
| s[1] = x & 255; x >>= 8; |
| s[0] = x; |
| } |
| |
| |
| /*** taia_sub.c ***/ |
| |
| /* XXX: breaks tai encapsulation */ |
| |
| void taia_sub(struct taia *t,const struct taia *u,const struct taia *v) |
| { |
| unsigned long unano = u->nano; |
| unsigned long uatto = u->atto; |
| |
| t->sec.x = u->sec.x - v->sec.x; |
| t->nano = unano - v->nano; |
| t->atto = uatto - v->atto; |
| if (t->atto > uatto) { |
| t->atto += 1000000000UL; |
| --t->nano; |
| } |
| if (t->nano > unano) { |
| t->nano += 1000000000UL; |
| --t->sec.x; |
| } |
| } |
| |
| |
| /*** taia_uint.c ***/ |
| |
| /* XXX: breaks tai encapsulation */ |
| |
| void taia_uint(struct taia *t,unsigned s) |
| { |
| t->sec.x = s; |
| t->nano = 0; |
| t->atto = 0; |
| } |
| |
| |
| /*** stralloc_cat.c ***/ |
| #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) |
| { |
| if (!stralloc_ready(sa,n + 1)) return 0; |
| memcpy(sa->s,s,n); |
| sa->len = n; |
| sa->s[n] = 'Z'; /* ``offensive programming'' */ |
| return 1; |
| } |
| |
| |
| /*** stralloc_opys.c ***/ |
| |
| int stralloc_copys(stralloc *sa,const char *s) |
| { |
| 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; |
| int millisecs; |
| double d; |
| int i; |
| |
| if (taia_less(deadline,stamp)) |
| millisecs = 0; |
| else { |
| t = *stamp; |
| taia_sub(&t,deadline,&t); |
| d = taia_approx(&t); |
| if (d > 1000.0) d = 1000.0; |
| millisecs = d * 1000.0 + 20.0; |
| } |
| |
| for (i = 0;i < len;++i) |
| x[i].revents = 0; |
| |
| poll(x,len,millisecs); |
| /* XXX: some kernels apparently need x[0] even if len is 0 */ |
| /* XXX: how to handle EAGAIN? are kernels really this dumb? */ |
| /* XXX: how to handle EINVAL? when exactly can this happen? */ |
| } |
| |
| |
| /*** lock_ex.c ***/ |
| |
| int lock_ex(int fd) |
| { |
| return flock(fd,LOCK_EX); |
| } |
| |
| |
| /*** lock_exnb.c ***/ |
| |
| int lock_exnb(int fd) |
| { |
| return flock(fd,LOCK_EX | LOCK_NB); |
| } |
| |
| |
| /*** open_append.c ***/ |
| |
| int open_append(const char *fn) |
| { |
| return open(fn, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); |
| } |
| |
| |
| /*** open_read.c ***/ |
| |
| int open_read(const char *fn) |
| { |
| return open(fn, O_RDONLY|O_NDELAY); |
| } |
| |
| |
| /*** open_trunc.c ***/ |
| |
| int open_trunc(const char *fn) |
| { |
| return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); |
| } |
| |
| |
| /*** open_write.c ***/ |
| |
| int open_write(const char *fn) |
| { |
| return open(fn, O_WRONLY|O_NDELAY); |
| } |
| |
| |
| /*** 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) |
| { |
| 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) { |
| for (;;) { |
| char c = *p++; |
| if (!c) return !len; |
| switch (c) { |
| case '*': |
| if (!(c = *p)) return 1; |
| for (;;) { |
| if (!len) return 0; |
| if (*s == c) break; |
| ++s; --len; |
| } |
| continue; |
| case '+': |
| if ((c = *p++) != *s) return 0; |
| for (;;) { |
| if (!len) return 1; |
| if (*s != c) break; |
| ++s; --len; |
| } |
| continue; |
| /* |
| case '?': |
| if (*p == '?') { |
| if (*s != '?') return 0; |
| ++p; |
| } |
| ++s; --len; |
| continue; |
| */ |
| default: |
| if (!len) return 0; |
| if (*s != c) return 0; |
| ++s; --len; |
| continue; |
| } |
| } |
| return 0; |
| } |
| |
| |
| /*** 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; |
| } |