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