5ebbc58406adbbc0619cab0f354cddcd72cf38d3
[oweals/busybox.git] / 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 hex[16] = "0123456789abcdef";
298         static char pack[TAIA_PACK];
299         int i;
300
301         taia_pack(pack, t);
302         s[0] = '@';
303         for (i = 0; i < 12; ++i) {
304                 s[i*2+1] = hex[(pack[i] >> 4) &15];
305                 s[i*2+2] = hex[pack[i] &15];
306         }
307         return 25;
308 }
309
310
311 /*** fmt_uint.c ***/
312
313 unsigned fmt_uint(char *s,unsigned u)
314 {
315         return fmt_ulong(s,u);
316 }
317
318
319 /*** fmt_uint0.c ***/
320
321 unsigned fmt_uint0(char *s,unsigned u,unsigned n)
322 {
323         unsigned len;
324         len = fmt_uint(FMT_LEN,u);
325         while (len < n) { if (s) *s++ = '0'; ++len; }
326         if (s) fmt_uint(s,u);
327         return len;
328 }
329
330
331 /*** fmt_ulong.c ***/
332
333 unsigned fmt_ulong(char *s,unsigned long u)
334 {
335         unsigned len; unsigned long q;
336         len = 1; q = u;
337         while (q > 9) { ++len; q /= 10; }
338         if (s) {
339                 s += len;
340                 do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
341         }
342         return len;
343 }
344
345
346 /*** tai_now.c ***/
347
348 void tai_now(struct tai *t)
349 {
350         tai_unix(t,time((time_t *) 0));
351 }
352
353
354 /*** tai_pack.c ***/
355
356 void tai_pack(char *s,const struct tai *t)
357 {
358         uint64_t x;
359
360         x = t->x;
361         s[7] = x & 255; x >>= 8;
362         s[6] = x & 255; x >>= 8;
363         s[5] = x & 255; x >>= 8;
364         s[4] = x & 255; x >>= 8;
365         s[3] = x & 255; x >>= 8;
366         s[2] = x & 255; x >>= 8;
367         s[1] = x & 255; x >>= 8;
368         s[0] = x;
369 }
370
371
372 /*** tai_sub.c ***/
373
374 void tai_sub(struct tai *t,const struct tai *u,const struct tai *v)
375 {
376         t->x = u->x - v->x;
377 }
378
379
380 /*** tai_unpack.c ***/
381
382 void tai_unpack(const char *s,struct tai *t)
383 {
384         uint64_t x;
385
386         x = (unsigned char) s[0];
387         x <<= 8; x += (unsigned char) s[1];
388         x <<= 8; x += (unsigned char) s[2];
389         x <<= 8; x += (unsigned char) s[3];
390         x <<= 8; x += (unsigned char) s[4];
391         x <<= 8; x += (unsigned char) s[5];
392         x <<= 8; x += (unsigned char) s[6];
393         x <<= 8; x += (unsigned char) s[7];
394         t->x = x;
395 }
396
397
398 /*** taia_add.c ***/
399
400 /* XXX: breaks tai encapsulation */
401
402 void taia_add(struct taia *t,const struct taia *u,const struct taia *v)
403 {
404         t->sec.x = u->sec.x + v->sec.x;
405         t->nano = u->nano + v->nano;
406         t->atto = u->atto + v->atto;
407         if (t->atto > 999999999UL) {
408                 t->atto -= 1000000000UL;
409                 ++t->nano;
410         }
411         if (t->nano > 999999999UL) {
412                 t->nano -= 1000000000UL;
413                 ++t->sec.x;
414         }
415 }
416
417
418 /*** taia_approx.c ***/
419
420 double taia_approx(const struct taia *t)
421 {
422         return tai_approx(&t->sec) + taia_frac(t);
423 }
424
425
426 /*** taia_frac.c ***/
427
428 double taia_frac(const struct taia *t)
429 {
430         return (t->atto * 0.000000001 + t->nano) * 0.000000001;
431 }
432
433
434 /*** taia_less.c ***/
435
436 /* XXX: breaks tai encapsulation */
437
438 int taia_less(const struct taia *t,const struct taia *u)
439 {
440         if (t->sec.x < u->sec.x) return 1;
441         if (t->sec.x > u->sec.x) return 0;
442         if (t->nano < u->nano) return 1;
443         if (t->nano > u->nano) return 0;
444         return t->atto < u->atto;
445 }
446
447
448 /*** taia_now.c ***/
449
450 void taia_now(struct taia *t)
451 {
452         struct timeval now;
453         gettimeofday(&now,(struct timezone *) 0);
454         tai_unix(&t->sec,now.tv_sec);
455         t->nano = 1000 * now.tv_usec + 500;
456         t->atto = 0;
457 }
458
459
460 /*** taia_pack.c ***/
461
462 void taia_pack(char *s,const struct taia *t)
463 {
464         unsigned long x;
465
466         tai_pack(s,&t->sec);
467         s += 8;
468
469         x = t->atto;
470         s[7] = x & 255; x >>= 8;
471         s[6] = x & 255; x >>= 8;
472         s[5] = x & 255; x >>= 8;
473         s[4] = x;
474         x = t->nano;
475         s[3] = x & 255; x >>= 8;
476         s[2] = x & 255; x >>= 8;
477         s[1] = x & 255; x >>= 8;
478         s[0] = x;
479 }
480
481
482 /*** taia_sub.c ***/
483
484 /* XXX: breaks tai encapsulation */
485
486 void taia_sub(struct taia *t,const struct taia *u,const struct taia *v)
487 {
488         unsigned long unano = u->nano;
489         unsigned long uatto = u->atto;
490         
491         t->sec.x = u->sec.x - v->sec.x;
492         t->nano = unano - v->nano;
493         t->atto = uatto - v->atto;
494         if (t->atto > uatto) {
495                 t->atto += 1000000000UL;
496                 --t->nano;
497         }
498         if (t->nano > unano) {
499                 t->nano += 1000000000UL;
500                 --t->sec.x;
501         }
502 }
503
504
505 /*** taia_uint.c ***/
506
507 /* XXX: breaks tai encapsulation */
508
509 void taia_uint(struct taia *t,unsigned s)
510 {
511         t->sec.x = s;
512         t->nano = 0;
513         t->atto = 0;
514 }
515
516
517 /*** stralloc_cat.c ***/
518 #if 0
519
520 int stralloc_cat(stralloc *sato,const stralloc *safrom)
521 {
522         return stralloc_catb(sato,safrom->s,safrom->len);
523 }
524
525
526 /*** stralloc_catb.c ***/
527
528 int stralloc_catb(stralloc *sa,const char *s,unsigned n)
529 {
530         if (!sa->s) return stralloc_copyb(sa,s,n);
531         if (!stralloc_readyplus(sa,n + 1)) return 0;
532         memcpy(sa->s + sa->len,s,n);
533         sa->len += n;
534         sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
535         return 1;
536 }
537
538
539 /*** stralloc_cats.c ***/
540
541 int stralloc_cats(stralloc *sa,const char *s)
542 {
543         return stralloc_catb(sa,s,strlen(s));
544 }
545
546
547 /*** stralloc_eady.c ***/
548
549 GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
550 GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus)
551
552
553 /*** stralloc_opyb.c ***/
554
555 int stralloc_copyb(stralloc *sa,const char *s,unsigned n)
556 {
557         if (!stralloc_ready(sa,n + 1)) return 0;
558         memcpy(sa->s,s,n);
559         sa->len = n;
560         sa->s[n] = 'Z'; /* ``offensive programming'' */
561         return 1;
562 }
563
564
565 /*** stralloc_opys.c ***/
566
567 int stralloc_copys(stralloc *sa,const char *s)
568 {
569         return stralloc_copyb(sa,s,strlen(s));
570 }
571
572
573 /*** stralloc_pend.c ***/
574
575 GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append)
576
577 #endif /* stralloc */
578
579 /*** iopause.c ***/
580
581 void iopause(iopause_fd *x,unsigned len,struct taia *deadline,struct taia *stamp)
582 {
583         struct taia t;
584         int millisecs;
585         double d;
586         int i;
587
588         if (taia_less(deadline,stamp))
589                 millisecs = 0;
590         else {
591                 t = *stamp;
592                 taia_sub(&t,deadline,&t);
593                 d = taia_approx(&t);
594                 if (d > 1000.0) d = 1000.0;
595                 millisecs = d * 1000.0 + 20.0;
596         }
597
598         for (i = 0;i < len;++i)
599                 x[i].revents = 0;
600
601         poll(x,len,millisecs);
602         /* XXX: some kernels apparently need x[0] even if len is 0 */
603         /* XXX: how to handle EAGAIN? are kernels really this dumb? */
604         /* XXX: how to handle EINVAL? when exactly can this happen? */
605 }
606
607
608 /*** lock_ex.c ***/
609
610 int lock_ex(int fd)
611 {
612         return flock(fd,LOCK_EX);
613 }
614
615
616 /*** lock_exnb.c ***/
617
618 int lock_exnb(int fd)
619 {
620         return flock(fd,LOCK_EX | LOCK_NB);
621 }
622
623
624 /*** open_append.c ***/
625
626 int open_append(const char *fn)
627 {
628         return open(fn, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
629 }
630
631
632 /*** open_read.c ***/
633
634 int open_read(const char *fn)
635 {
636         return open(fn, O_RDONLY|O_NDELAY);
637 }
638
639
640 /*** open_trunc.c ***/
641
642 int open_trunc(const char *fn)
643 {
644         return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644);
645 }
646
647
648 /*** open_write.c ***/
649
650 int open_write(const char *fn)
651 {
652         return open(fn, O_WRONLY|O_NDELAY);
653 }
654
655
656 /*** openreadclose.c ***/
657 #if 0
658 int openreadclose(const char *fn,stralloc *sa,unsigned bufsize)
659 {
660         int fd;
661         fd = open_read(fn);
662         if (fd == -1) {
663                 if (errno == ENOENT) return 0;
664                 return -1;
665         }
666         if (readclose(fd,sa,bufsize) == -1) return -1;
667         return 1;
668 }
669 #endif
670
671
672 /*** pathexec_env.c ***/
673 #if 0
674 static stralloc plus;
675 static stralloc tmp;
676
677 int pathexec_env(const char *s,const char *t)
678 {
679         if (!s) return 1;
680         if (!stralloc_copys(&tmp,s)) return 0;
681         if (t) {
682                 if (!stralloc_cats(&tmp,"=")) return 0;
683                 if (!stralloc_cats(&tmp,t)) return 0;
684         }
685         if (!stralloc_0(&tmp)) return 0;
686         return stralloc_cat(&plus,&tmp);
687 }
688
689 void pathexec(char **argv)
690 {
691         char **e;
692         unsigned elen;
693         unsigned i;
694         unsigned j;
695         unsigned split;
696         unsigned t;
697
698         if (!stralloc_cats(&plus,"")) return;
699
700         elen = 0;
701         for (i = 0;environ[i];++i)
702                 ++elen;
703         for (i = 0;i < plus.len;++i)
704                 if (!plus.s[i])
705                         ++elen;
706
707         e = malloc((elen + 1) * sizeof(char *));
708         if (!e) return;
709
710         elen = 0;
711         for (i = 0;environ[i];++i)
712                 e[elen++] = environ[i];
713
714         j = 0;
715         for (i = 0;i < plus.len;++i)
716                 if (!plus.s[i]) {
717                         split = str_chr(plus.s + j,'=');
718                         for (t = 0;t < elen;++t)
719                                 if (memcmp(plus.s + j,e[t],split) == 0)
720                                         if (e[t][split] == '=') {
721                                                 --elen;
722                                                 e[t] = e[elen];
723                                                 break;
724                                         }
725                         if (plus.s[j + split])
726                                 e[elen++] = plus.s + j;
727                         j = i + 1;
728                 }
729         e[elen] = 0;
730
731         pathexec_run(*argv,argv,e);
732         free(e);
733 }
734 #endif
735
736 /*** pathexec_run.c ***/
737 #if 0
738 static stralloc tmp;
739
740 void pathexec_run(const char *file,char *const *argv,char *const *envp)
741 {
742         const char *path;
743         unsigned split;
744         int savederrno;
745
746         if (file[str_chr(file,'/')]) {
747                 execve(file,argv,envp);
748                 return;
749         }
750
751         path = getenv("PATH");
752         if (!path) path = "/bin:/usr/bin";
753
754         savederrno = 0;
755         for (;;) {
756                 split = str_chr(path,':');
757                 if (!stralloc_copyb(&tmp,path,split)) return;
758                 if (!split)
759                         if (!stralloc_cats(&tmp,".")) return;
760                 if (!stralloc_cats(&tmp,"/"))  return;
761                 if (!stralloc_cats(&tmp,file)) return;
762                 if (!stralloc_0(&tmp)) return;
763
764                 execve(tmp.s,argv,envp);
765                 if (errno != ENOENT) {
766                         savederrno = errno;
767                         if ((errno != EACCES) && (errno != EPERM) && (errno != EISDIR)) return;
768                 }
769
770                 if (!path[split]) {
771                         if (savederrno) errno = savederrno;
772                         return;
773                 }
774                 path += split;
775                 path += 1;
776         }
777 }
778 #endif
779
780 /*** pmatch.c ***/
781
782 unsigned pmatch(const char *p, const char *s, unsigned len) {
783         for (;;) {
784                 char c = *p++;
785                 if (!c) return !len;
786                 switch (c) {
787                 case '*':
788                         if (!(c = *p)) return 1;
789                         for (;;) {
790                                 if (!len) return 0;
791                                 if (*s == c) break;
792                                 ++s; --len;
793                         }
794                         continue;
795                 case '+':
796                         if ((c = *p++) != *s) return 0;
797                         for (;;) {
798                                 if (!len) return 1;
799                                 if (*s != c) break;
800                                 ++s; --len;
801                         }
802                         continue;
803                         /*
804                 case '?':
805                         if (*p == '?') {
806                                 if (*s != '?') return 0;
807                                 ++p;
808                         }
809                         ++s; --len;
810                         continue;
811                         */
812                 default:
813                         if (!len) return 0;
814                         if (*s != c) return 0;
815                         ++s; --len;
816                         continue;
817                 }
818         }
819         return 0;
820 }
821
822
823 /*** prot.c ***/
824
825 int prot_gid(int gid)
826 {
827         gid_t x = gid;
828         if (setgroups(1,&x) == -1) return -1;
829         return setgid(gid); /* _should_ be redundant, but on some systems it isn't */
830 }
831
832 int prot_uid(int uid)
833 {
834         return setuid(uid);
835 }
836
837
838 /*** readclose.c ***/
839 #if 0
840 int readclose_append(int fd,stralloc *sa,unsigned bufsize)
841 {
842         int r;
843         for (;;) {
844                 if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; }
845                 r = read(fd,sa->s + sa->len,bufsize);
846                 if (r == -1) if (errno == EINTR) continue;
847                 if (r <= 0) { close(fd); return r; }
848                 sa->len += r;
849         }
850 }
851
852 int readclose(int fd,stralloc *sa,unsigned bufsize)
853 {
854         if (!stralloc_copys(sa,"")) { close(fd); return -1; }
855         return readclose_append(fd,sa,bufsize);
856 }
857 #endif
858
859 /*** scan_ulong.c ***/
860
861 unsigned scan_ulong(const char *s,unsigned long *u)
862 {
863         unsigned pos = 0;
864         unsigned long result = 0;
865         unsigned long c;
866         while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) {
867                 result = result * 10 + c;
868                 ++pos;
869         }
870         *u = result;
871         return pos;
872 }
873
874
875 /*** seek_set.c ***/
876
877 int seek_set(int fd,seek_pos pos)
878 {
879         if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; return 0;
880 }
881
882
883 /*** sig.c ***/
884
885 int sig_alarm = SIGALRM;
886 int sig_child = SIGCHLD;
887 int sig_cont = SIGCONT;
888 int sig_hangup = SIGHUP;
889 int sig_int = SIGINT;
890 int sig_pipe = SIGPIPE;
891 int sig_term = SIGTERM;
892
893 void (*sig_defaulthandler)(int) = SIG_DFL;
894 void (*sig_ignorehandler)(int) = SIG_IGN;
895
896
897 /*** sig_block.c ***/
898
899 void sig_block(int sig)
900 {
901         sigset_t ss;
902         sigemptyset(&ss);
903         sigaddset(&ss,sig);
904         sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0);
905 }
906
907 void sig_unblock(int sig)
908 {
909         sigset_t ss;
910         sigemptyset(&ss);
911         sigaddset(&ss,sig);
912         sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0);
913 }
914
915 void sig_blocknone(void)
916 {
917         sigset_t ss;
918         sigemptyset(&ss);
919         sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0);
920 }
921
922
923 /*** sig_catch.c ***/
924
925 void sig_catch(int sig,void (*f)(int))
926 {
927         struct sigaction sa;
928         sa.sa_handler = f;
929         sa.sa_flags = 0;
930         sigemptyset(&sa.sa_mask);
931         sigaction(sig,&sa,(struct sigaction *) 0);
932 }
933
934
935 /*** sig_pause.c ***/
936
937 void sig_pause(void)
938 {
939         sigset_t ss;
940         sigemptyset(&ss);
941         sigsuspend(&ss);
942 }
943
944
945 /*** str_chr.c ***/
946
947 unsigned str_chr(const char *s,int c)
948 {
949         char ch;
950         const char *t;
951
952         ch = c;
953         t = s;
954         for (;;) {
955                 if (!*t) break; if (*t == ch) break; ++t;
956                 if (!*t) break; if (*t == ch) break; ++t;
957                 if (!*t) break; if (*t == ch) break; ++t;
958                 if (!*t) break; if (*t == ch) break; ++t;
959         }
960         return t - s;
961 }
962
963
964 /*** wait_nohang.c ***/
965
966 int wait_nohang(int *wstat)
967 {
968         return waitpid(-1,wstat,WNOHANG);
969 }
970
971
972 /*** wait_pid.c ***/
973
974 int wait_pid(int *wstat, int pid)
975 {
976         int r;
977
978         do
979                 r = waitpid(pid,wstat,0);
980         while ((r == -1) && (errno == EINTR));
981         return r;
982 }