add compile-time check for correct DHCP packet size
[oweals/busybox.git] / runit / runit_lib.c
1 /*
2 Copyright (c) 2001-2006, Gerrit Pape
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8    1. Redistributions of source code must retain the above copyright notice,
9       this list of conditions and the following disclaimer.
10    2. Redistributions in binary form must reproduce the above copyright
11       notice, this list of conditions and the following disclaimer in the
12       documentation and/or other materials provided with the distribution.
13    3. The name of the author may not be used to endorse or promote products
14       derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
29 /* Collected into one file from runit's many tiny files */
30 /* TODO: review, eliminate unneeded stuff, move good stuff to libbb */
31
32 #include <sys/poll.h>
33 #include <sys/file.h>
34 #include "libbb.h"
35 #include "runit_lib.h"
36
37 #ifndef O_NONBLOCK
38 #define O_NONBLOCK O_NDELAY
39 #endif
40
41 /*** buffer.c ***/
42
43 void buffer_init(buffer *s,int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len)
44 {
45         s->x = buf;
46         s->fd = fd;
47         s->op = op;
48         s->p = 0;
49         s->n = len;
50 }
51
52
53 /*** buffer_get.c ***/
54
55 static int oneread(int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len)
56 {
57         int r;
58
59         for (;;) {
60                 r = op(fd,buf,len);
61                 if (r == -1) if (errno == EINTR) continue;
62                 return r;
63         }
64 }
65
66 static int getthis(buffer *s,char *buf,unsigned len)
67 {
68         if (len > s->p) len = s->p;
69         s->p -= len;
70         memcpy(buf,s->x + s->n,len);
71         s->n += len;
72         return len;
73 }
74
75 int buffer_feed(buffer *s)
76 {
77         int r;
78
79         if (s->p) return s->p;
80         r = oneread(s->op,s->fd,s->x,s->n);
81         if (r <= 0) return r;
82         s->p = r;
83         s->n -= r;
84         if (s->n > 0) memmove(s->x + s->n,s->x,r);
85         return r;
86 }
87
88 int buffer_bget(buffer *s,char *buf,unsigned len)
89 {
90         int r;
91  
92         if (s->p > 0) return getthis(s,buf,len);
93         if (s->n <= len) return oneread(s->op,s->fd,buf,s->n);
94         r = buffer_feed(s); if (r <= 0) return r;
95         return getthis(s,buf,len);
96 }
97
98 int buffer_get(buffer *s,char *buf,unsigned len)
99 {
100         int r;
101  
102         if (s->p > 0) return getthis(s,buf,len);
103         if (s->n <= len) return oneread(s->op,s->fd,buf,len);
104         r = buffer_feed(s); if (r <= 0) return r;
105         return getthis(s,buf,len);
106 }
107
108 char *buffer_peek(buffer *s)
109 {
110         return s->x + s->n;
111 }
112
113 void buffer_seek(buffer *s,unsigned len)
114 {
115         s->n += len;
116         s->p -= len;
117 }
118
119
120 /*** buffer_put.c ***/
121
122 static int allwrite(int (*op)(int fd,char *buf,unsigned len),int fd,const char *buf,unsigned len)
123 {
124         int w;
125
126         while (len) {
127                 w = op(fd,(char*)buf,len);
128                 if (w == -1) {
129                         if (errno == EINTR) continue;
130                         return -1; /* note that some data may have been written */
131                 }
132                 if (w == 0) ; /* luser's fault */
133                 buf += w;
134                 len -= w;
135         }
136         return 0;
137 }
138
139 int buffer_flush(buffer *s)
140 {
141         int p;
142  
143         p = s->p;
144         if (!p) return 0;
145         s->p = 0;
146         return allwrite(s->op,s->fd,s->x,p);
147 }
148
149 int buffer_putalign(buffer *s,const char *buf,unsigned len)
150 {
151         unsigned n;
152  
153         while (len > (n = s->n - s->p)) {
154                 memcpy(s->x + s->p,buf,n);
155                 s->p += n;
156                 buf += n;
157                 len -= n;
158                 if (buffer_flush(s) == -1) return -1;
159         }
160         /* now len <= s->n - s->p */
161         memcpy(s->x + s->p,buf,len);
162         s->p += len;
163         return 0;
164 }
165
166 int buffer_put(buffer *s,const char *buf,unsigned len)
167 {
168         unsigned n;
169  
170         n = s->n;
171         if (len > n - s->p) {
172                 if (buffer_flush(s) == -1) return -1;
173                 /* now s->p == 0 */
174                 if (n < BUFFER_OUTSIZE) n = BUFFER_OUTSIZE;
175                 while (len > s->n) {
176                         if (n > len) n = len;
177                         if (allwrite(s->op,s->fd,buf,n) == -1) return -1;
178                         buf += n;
179                         len -= n;
180                 }
181         }
182         /* now len <= s->n - s->p */
183         memcpy(s->x + s->p,buf,len);
184         s->p += len;
185         return 0;
186 }
187
188 int buffer_putflush(buffer *s,const char *buf,unsigned len)
189 {
190         if (buffer_flush(s) == -1) return -1;
191         return allwrite(s->op,s->fd,buf,len);
192 }
193
194 int buffer_putsalign(buffer *s,const char *buf)
195 {
196         return buffer_putalign(s,buf,strlen(buf));
197 }
198
199 int buffer_puts(buffer *s,const char *buf)
200 {
201         return buffer_put(s,buf,strlen(buf));
202 }
203
204 int buffer_putsflush(buffer *s,const char *buf)
205 {
206         return buffer_putflush(s,buf,strlen(buf));
207 }
208
209
210 /*** buffer_read.c ***/
211
212 int buffer_unixread(int fd,char *buf,unsigned len)
213 {
214         return read(fd,buf,len);
215 }
216
217
218 /*** buffer_write.c ***/
219
220 int buffer_unixwrite(int fd,char *buf,unsigned len)
221 {
222         return write(fd,buf,len);
223 }
224
225
226 /*** byte_chr.c ***/
227
228 unsigned byte_chr(char *s,unsigned n,int c)
229 {
230         char ch;
231         char *t;
232
233         ch = c;
234         t = s;
235         for (;;) {
236                 if (!n) break; if (*t == ch) break; ++t; --n;
237                 if (!n) break; if (*t == ch) break; ++t; --n;
238                 if (!n) break; if (*t == ch) break; ++t; --n;
239                 if (!n) break; if (*t == ch) break; ++t; --n;
240         }
241         return t - s;
242 }
243
244
245 /*** coe.c ***/
246
247 int coe(int fd)
248 {
249         return fcntl(fd,F_SETFD,FD_CLOEXEC);
250 }
251
252
253 /*** fd_copy.c ***/
254
255 int fd_copy(int to,int from)
256 {
257         if (to == from) return 0;
258         if (fcntl(from,F_GETFL,0) == -1) return -1;
259         close(to);
260         if (fcntl(from,F_DUPFD,to) == -1) return -1;
261         return 0;
262 }
263
264
265 /*** fd_move.c ***/
266
267 int fd_move(int to,int from)
268 {
269         if (to == from) return 0;
270         if (fd_copy(to,from) == -1) return -1;
271         close(from);
272         return 0;
273 }
274
275
276 /*** fifo.c ***/
277
278 int fifo_make(const char *fn,int mode) { return mkfifo(fn,mode); }
279
280
281 /*** fmt_ptime.c ***/
282
283 unsigned fmt_ptime(char *s, struct taia *ta) {
284         struct tm *t;
285         unsigned long u;
286
287         if (ta->sec.x < 4611686018427387914ULL) return 0; /* impossible? */
288         u = ta->sec.x -4611686018427387914ULL;
289         if (!(t = gmtime((time_t*)&u))) return 0;
290         fmt_ulong(s, 1900 + t->tm_year);
291         s[4] = '-'; fmt_uint0(&s[5], t->tm_mon+1, 2);
292         s[7] = '-'; fmt_uint0(&s[8], t->tm_mday, 2);
293         s[10] = '_'; fmt_uint0(&s[11], t->tm_hour, 2);
294         s[13] = ':'; fmt_uint0(&s[14], t->tm_min, 2);
295         s[16] = ':'; fmt_uint0(&s[17], t->tm_sec, 2);
296         s[19] = '.'; fmt_uint0(&s[20], ta->nano, 9);
297         return 25;
298 }
299
300 unsigned fmt_taia(char *s, struct taia *t) {
301         static char hex[16] = "0123456789abcdef";
302         static char pack[TAIA_PACK];
303         int i;
304
305         taia_pack(pack, t);
306         s[0] = '@';
307         for (i = 0; i < 12; ++i) {
308                 s[i*2+1] = hex[(pack[i] >> 4) &15];
309                 s[i*2+2] = hex[pack[i] &15];
310         }
311         return 25;
312 }
313
314
315 /*** fmt_uint.c ***/
316
317 unsigned fmt_uint(char *s,unsigned u)
318 {
319         return fmt_ulong(s,u);
320 }
321
322
323 /*** fmt_uint0.c ***/
324
325 unsigned fmt_uint0(char *s,unsigned u,unsigned n)
326 {
327         unsigned len;
328         len = fmt_uint(FMT_LEN,u);
329         while (len < n) { if (s) *s++ = '0'; ++len; }
330         if (s) fmt_uint(s,u);
331         return len;
332 }
333
334
335 /*** fmt_ulong.c ***/
336
337 unsigned fmt_ulong(char *s,unsigned long u)
338 {
339         unsigned len; unsigned long q;
340         len = 1; q = u;
341         while (q > 9) { ++len; q /= 10; }
342         if (s) {
343                 s += len;
344                 do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
345         }
346         return len;
347 }
348
349
350 /*** tai_now.c ***/
351
352 void tai_now(struct tai *t)
353 {
354         tai_unix(t,time((time_t *) 0));
355 }
356
357
358 /*** tai_pack.c ***/
359
360 void tai_pack(char *s,const struct tai *t)
361 {
362         uint64_t x;
363
364         x = t->x;
365         s[7] = x & 255; x >>= 8;
366         s[6] = x & 255; x >>= 8;
367         s[5] = x & 255; x >>= 8;
368         s[4] = x & 255; x >>= 8;
369         s[3] = x & 255; x >>= 8;
370         s[2] = x & 255; x >>= 8;
371         s[1] = x & 255; x >>= 8;
372         s[0] = x;
373 }
374
375
376 /*** tai_sub.c ***/
377
378 void tai_sub(struct tai *t,const struct tai *u,const struct tai *v)
379 {
380         t->x = u->x - v->x;
381 }
382
383
384 /*** tai_unpack.c ***/
385
386 void tai_unpack(const char *s,struct tai *t)
387 {
388         uint64_t x;
389
390         x = (unsigned char) s[0];
391         x <<= 8; x += (unsigned char) s[1];
392         x <<= 8; x += (unsigned char) s[2];
393         x <<= 8; x += (unsigned char) s[3];
394         x <<= 8; x += (unsigned char) s[4];
395         x <<= 8; x += (unsigned char) s[5];
396         x <<= 8; x += (unsigned char) s[6];
397         x <<= 8; x += (unsigned char) s[7];
398         t->x = x;
399 }
400
401
402 /*** taia_add.c ***/
403
404 /* XXX: breaks tai encapsulation */
405
406 void taia_add(struct taia *t,const struct taia *u,const struct taia *v)
407 {
408         t->sec.x = u->sec.x + v->sec.x;
409         t->nano = u->nano + v->nano;
410         t->atto = u->atto + v->atto;
411         if (t->atto > 999999999UL) {
412                 t->atto -= 1000000000UL;
413                 ++t->nano;
414         }
415         if (t->nano > 999999999UL) {
416                 t->nano -= 1000000000UL;
417                 ++t->sec.x;
418         }
419 }
420
421
422 /*** taia_approx.c ***/
423
424 double taia_approx(const struct taia *t)
425 {
426         return tai_approx(&t->sec) + taia_frac(t);
427 }
428
429
430 /*** taia_frac.c ***/
431
432 double taia_frac(const struct taia *t)
433 {
434         return (t->atto * 0.000000001 + t->nano) * 0.000000001;
435 }
436
437
438 /*** taia_less.c ***/
439
440 /* XXX: breaks tai encapsulation */
441
442 int taia_less(const struct taia *t,const struct taia *u)
443 {
444         if (t->sec.x < u->sec.x) return 1;
445         if (t->sec.x > u->sec.x) return 0;
446         if (t->nano < u->nano) return 1;
447         if (t->nano > u->nano) return 0;
448         return t->atto < u->atto;
449 }
450
451
452 /*** taia_now.c ***/
453
454 void taia_now(struct taia *t)
455 {
456         struct timeval now;
457         gettimeofday(&now,(struct timezone *) 0);
458         tai_unix(&t->sec,now.tv_sec);
459         t->nano = 1000 * now.tv_usec + 500;
460         t->atto = 0;
461 }
462
463
464 /*** taia_pack.c ***/
465
466 void taia_pack(char *s,const struct taia *t)
467 {
468         unsigned long x;
469
470         tai_pack(s,&t->sec);
471         s += 8;
472
473         x = t->atto;
474         s[7] = x & 255; x >>= 8;
475         s[6] = x & 255; x >>= 8;
476         s[5] = x & 255; x >>= 8;
477         s[4] = x;
478         x = t->nano;
479         s[3] = x & 255; x >>= 8;
480         s[2] = x & 255; x >>= 8;
481         s[1] = x & 255; x >>= 8;
482         s[0] = x;
483 }
484
485
486 /*** taia_sub.c ***/
487
488 /* XXX: breaks tai encapsulation */
489
490 void taia_sub(struct taia *t,const struct taia *u,const struct taia *v)
491 {
492         unsigned long unano = u->nano;
493         unsigned long uatto = u->atto;
494         
495         t->sec.x = u->sec.x - v->sec.x;
496         t->nano = unano - v->nano;
497         t->atto = uatto - v->atto;
498         if (t->atto > uatto) {
499                 t->atto += 1000000000UL;
500                 --t->nano;
501         }
502         if (t->nano > unano) {
503                 t->nano += 1000000000UL;
504                 --t->sec.x;
505         }
506 }
507
508
509 /*** taia_uint.c ***/
510
511 /* XXX: breaks tai encapsulation */
512
513 void taia_uint(struct taia *t,unsigned s)
514 {
515         t->sec.x = s;
516         t->nano = 0;
517         t->atto = 0;
518 }
519
520
521 /*** stralloc_cat.c ***/
522 #if 0
523
524 int stralloc_cat(stralloc *sato,const stralloc *safrom)
525 {
526         return stralloc_catb(sato,safrom->s,safrom->len);
527 }
528
529
530 /*** stralloc_catb.c ***/
531
532 int stralloc_catb(stralloc *sa,const char *s,unsigned n)
533 {
534         if (!sa->s) return stralloc_copyb(sa,s,n);
535         if (!stralloc_readyplus(sa,n + 1)) return 0;
536         memcpy(sa->s + sa->len,s,n);
537         sa->len += n;
538         sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
539         return 1;
540 }
541
542
543 /*** stralloc_cats.c ***/
544
545 int stralloc_cats(stralloc *sa,const char *s)
546 {
547         return stralloc_catb(sa,s,strlen(s));
548 }
549
550
551 /*** stralloc_eady.c ***/
552
553 GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
554 GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus)
555
556
557 /*** stralloc_opyb.c ***/
558
559 int stralloc_copyb(stralloc *sa,const char *s,unsigned n)
560 {
561         if (!stralloc_ready(sa,n + 1)) return 0;
562         memcpy(sa->s,s,n);
563         sa->len = n;
564         sa->s[n] = 'Z'; /* ``offensive programming'' */
565         return 1;
566 }
567
568
569 /*** stralloc_opys.c ***/
570
571 int stralloc_copys(stralloc *sa,const char *s)
572 {
573         return stralloc_copyb(sa,s,strlen(s));
574 }
575
576
577 /*** stralloc_pend.c ***/
578
579 GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append)
580
581 #endif /* stralloc */
582
583 /*** iopause.c ***/
584
585 void iopause(iopause_fd *x,unsigned len,struct taia *deadline,struct taia *stamp)
586 {
587         struct taia t;
588         int millisecs;
589         double d;
590         int i;
591
592         if (taia_less(deadline,stamp))
593                 millisecs = 0;
594         else {
595                 t = *stamp;
596                 taia_sub(&t,deadline,&t);
597                 d = taia_approx(&t);
598                 if (d > 1000.0) d = 1000.0;
599                 millisecs = d * 1000.0 + 20.0;
600         }
601
602         for (i = 0;i < len;++i)
603                 x[i].revents = 0;
604
605         poll(x,len,millisecs);
606         /* XXX: some kernels apparently need x[0] even if len is 0 */
607         /* XXX: how to handle EAGAIN? are kernels really this dumb? */
608         /* XXX: how to handle EINVAL? when exactly can this happen? */
609 }
610
611
612 /*** lock_ex.c ***/
613
614 int lock_ex(int fd)
615 {
616         return flock(fd,LOCK_EX);
617 }
618
619
620 /*** lock_exnb.c ***/
621
622 int lock_exnb(int fd)
623 {
624         return flock(fd,LOCK_EX | LOCK_NB);
625 }
626
627
628 /*** ndelay_off.c ***/
629
630 int ndelay_off(int fd)
631 {
632         return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK);
633 }
634
635
636 /*** ndelay_on.c ***/
637
638 int ndelay_on(int fd)
639 {
640         return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK);
641 }
642
643
644 /*** open_append.c ***/
645
646 int open_append(const char *fn)
647 {
648         return open(fn, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
649 }
650
651
652 /*** open_read.c ***/
653
654 int open_read(const char *fn)
655 {
656         return open(fn, O_RDONLY|O_NDELAY);
657 }
658
659
660 /*** open_trunc.c ***/
661
662 int open_trunc(const char *fn)
663 {
664         return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644);
665 }
666
667
668 /*** open_write.c ***/
669
670 int open_write(const char *fn)
671 {
672         return open(fn, O_WRONLY|O_NDELAY);
673 }
674
675
676 /*** openreadclose.c ***/
677 #if 0
678 int openreadclose(const char *fn,stralloc *sa,unsigned bufsize)
679 {
680         int fd;
681         fd = open_read(fn);
682         if (fd == -1) {
683                 if (errno == ENOENT) return 0;
684                 return -1;
685         }
686         if (readclose(fd,sa,bufsize) == -1) return -1;
687         return 1;
688 }
689 #endif
690
691
692 /*** pathexec_env.c ***/
693 #if 0
694 static stralloc plus;
695 static stralloc tmp;
696
697 int pathexec_env(const char *s,const char *t)
698 {
699         if (!s) return 1;
700         if (!stralloc_copys(&tmp,s)) return 0;
701         if (t) {
702                 if (!stralloc_cats(&tmp,"=")) return 0;
703                 if (!stralloc_cats(&tmp,t)) return 0;
704         }
705         if (!stralloc_0(&tmp)) return 0;
706         return stralloc_cat(&plus,&tmp);
707 }
708
709 void pathexec(char **argv)
710 {
711         char **e;
712         unsigned elen;
713         unsigned i;
714         unsigned j;
715         unsigned split;
716         unsigned t;
717
718         if (!stralloc_cats(&plus,"")) return;
719
720         elen = 0;
721         for (i = 0;environ[i];++i)
722                 ++elen;
723         for (i = 0;i < plus.len;++i)
724                 if (!plus.s[i])
725                         ++elen;
726
727         e = malloc((elen + 1) * sizeof(char *));
728         if (!e) return;
729
730         elen = 0;
731         for (i = 0;environ[i];++i)
732                 e[elen++] = environ[i];
733
734         j = 0;
735         for (i = 0;i < plus.len;++i)
736                 if (!plus.s[i]) {
737                         split = str_chr(plus.s + j,'=');
738                         for (t = 0;t < elen;++t)
739                                 if (memcmp(plus.s + j,e[t],split) == 0)
740                                         if (e[t][split] == '=') {
741                                                 --elen;
742                                                 e[t] = e[elen];
743                                                 break;
744                                         }
745                         if (plus.s[j + split])
746                                 e[elen++] = plus.s + j;
747                         j = i + 1;
748                 }
749         e[elen] = 0;
750
751         pathexec_run(*argv,argv,e);
752         free(e);
753 }
754 #endif
755
756 /*** pathexec_run.c ***/
757 #if 0
758 static stralloc tmp;
759
760 void pathexec_run(const char *file,char *const *argv,char *const *envp)
761 {
762         const char *path;
763         unsigned split;
764         int savederrno;
765
766         if (file[str_chr(file,'/')]) {
767                 execve(file,argv,envp);
768                 return;
769         }
770
771         path = getenv("PATH");
772         if (!path) path = "/bin:/usr/bin";
773
774         savederrno = 0;
775         for (;;) {
776                 split = str_chr(path,':');
777                 if (!stralloc_copyb(&tmp,path,split)) return;
778                 if (!split)
779                         if (!stralloc_cats(&tmp,".")) return;
780                 if (!stralloc_cats(&tmp,"/"))  return;
781                 if (!stralloc_cats(&tmp,file)) return;
782                 if (!stralloc_0(&tmp)) return;
783
784                 execve(tmp.s,argv,envp);
785                 if (errno != ENOENT) {
786                         savederrno = errno;
787                         if ((errno != EACCES) && (errno != EPERM) && (errno != EISDIR)) return;
788                 }
789
790                 if (!path[split]) {
791                         if (savederrno) errno = savederrno;
792                         return;
793                 }
794                 path += split;
795                 path += 1;
796         }
797 }
798 #endif
799
800 /*** pmatch.c ***/
801
802 unsigned pmatch(const char *p, const char *s, unsigned len) {
803         for (;;) {
804                 char c = *p++;
805                 if (!c) return !len;
806                 switch (c) {
807                 case '*':
808                         if (!(c = *p)) return 1;
809                         for (;;) {
810                                 if (!len) return 0;
811                                 if (*s == c) break;
812                                 ++s; --len;
813                         }
814                         continue;
815                 case '+':
816                         if ((c = *p++) != *s) return 0;
817                         for (;;) {
818                                 if (!len) return 1;
819                                 if (*s != c) break;
820                                 ++s; --len;
821                         }
822                         continue;
823                         /*
824                 case '?':
825                         if (*p == '?') {
826                                 if (*s != '?') return 0;
827                                 ++p;
828                         }
829                         ++s; --len;
830                         continue;
831                         */
832                 default:
833                         if (!len) return 0;
834                         if (*s != c) return 0;
835                         ++s; --len;
836                         continue;
837                 }
838         }
839         return 0;
840 }
841
842
843 /*** prot.c ***/
844
845 int prot_gid(int gid)
846 {
847         gid_t x = gid;
848         if (setgroups(1,&x) == -1) return -1;
849         return setgid(gid); /* _should_ be redundant, but on some systems it isn't */
850 }
851
852 int prot_uid(int uid)
853 {
854         return setuid(uid);
855 }
856
857
858 /*** readclose.c ***/
859 #if 0
860 int readclose_append(int fd,stralloc *sa,unsigned bufsize)
861 {
862         int r;
863         for (;;) {
864                 if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; }
865                 r = read(fd,sa->s + sa->len,bufsize);
866                 if (r == -1) if (errno == EINTR) continue;
867                 if (r <= 0) { close(fd); return r; }
868                 sa->len += r;
869         }
870 }
871
872 int readclose(int fd,stralloc *sa,unsigned bufsize)
873 {
874         if (!stralloc_copys(sa,"")) { close(fd); return -1; }
875         return readclose_append(fd,sa,bufsize);
876 }
877 #endif
878
879 /*** scan_ulong.c ***/
880
881 unsigned scan_ulong(const char *s,unsigned long *u)
882 {
883         unsigned pos = 0;
884         unsigned long result = 0;
885         unsigned long c;
886         while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) {
887                 result = result * 10 + c;
888                 ++pos;
889         }
890         *u = result;
891         return pos;
892 }
893
894
895 /*** seek_set.c ***/
896
897 int seek_set(int fd,seek_pos pos)
898 {
899         if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; return 0;
900 }
901
902
903 /*** sig.c ***/
904
905 int sig_alarm = SIGALRM;
906 int sig_child = SIGCHLD;
907 int sig_cont = SIGCONT;
908 int sig_hangup = SIGHUP;
909 int sig_int = SIGINT;
910 int sig_pipe = SIGPIPE;
911 int sig_term = SIGTERM;
912
913 void (*sig_defaulthandler)(int) = SIG_DFL;
914 void (*sig_ignorehandler)(int) = SIG_IGN;
915
916
917 /*** sig_block.c ***/
918
919 void sig_block(int sig)
920 {
921         sigset_t ss;
922         sigemptyset(&ss);
923         sigaddset(&ss,sig);
924         sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0);
925 }
926
927 void sig_unblock(int sig)
928 {
929         sigset_t ss;
930         sigemptyset(&ss);
931         sigaddset(&ss,sig);
932         sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0);
933 }
934
935 void sig_blocknone(void)
936 {
937         sigset_t ss;
938         sigemptyset(&ss);
939         sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0);
940 }
941
942
943 /*** sig_catch.c ***/
944
945 void sig_catch(int sig,void (*f)(int))
946 {
947         struct sigaction sa;
948         sa.sa_handler = f;
949         sa.sa_flags = 0;
950         sigemptyset(&sa.sa_mask);
951         sigaction(sig,&sa,(struct sigaction *) 0);
952 }
953
954
955 /*** sig_pause.c ***/
956
957 void sig_pause(void)
958 {
959         sigset_t ss;
960         sigemptyset(&ss);
961         sigsuspend(&ss);
962 }
963
964
965 /*** str_chr.c ***/
966
967 unsigned str_chr(const char *s,int c)
968 {
969         char ch;
970         const char *t;
971
972         ch = c;
973         t = s;
974         for (;;) {
975                 if (!*t) break; if (*t == ch) break; ++t;
976                 if (!*t) break; if (*t == ch) break; ++t;
977                 if (!*t) break; if (*t == ch) break; ++t;
978                 if (!*t) break; if (*t == ch) break; ++t;
979         }
980         return t - s;
981 }
982
983
984 /*** wait_nohang.c ***/
985
986 int wait_nohang(int *wstat)
987 {
988         return waitpid(-1,wstat,WNOHANG);
989 }
990
991
992 /*** wait_pid.c ***/
993
994 int wait_pid(int *wstat, int pid)
995 {
996         int r;
997
998         do
999                 r = waitpid(pid,wstat,0);
1000         while ((r == -1) && (errno == EINTR));
1001         return r;
1002 }