about summary refs log tree commit diff
path: root/doc/libstddjb/djbunix.html
blob: e70fe4fb532d8312efcc5684d4cf95834cc3aa8f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="Content-Language" content="en" />
    <title>skalibs: the djbunix library interface</title>
    <meta name="Description" content="skalibs: the djbunix library interface" />
    <meta name="Keywords" content="skalibs c unix djbunix library libstddjb" />
    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
  </head>
<body>

<p>
<a href="index.html">libstddjb</a><br />
<a href="../libskarnet.html">libskarnet</a><br />
<a href="../index.html">skalibs</a><br />
<a href="//skarnet.org/software/">Software</a><br />
<a href="//skarnet.org/">skarnet.org</a>
</p>

<h1> The <tt>djbunix</tt> library interface </h1>

<p>
 The following functions are declared in the <tt>skalibs/djbunix.h</tt> header,
and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
</p>

<h2> General information </h2>

<p>
 <tt>djbunix</tt> is an alternative API to management of basic Unix
concepts: file descriptors, files, environment, and so on. It is a
rather chaotic mix of <a href="safewrappers.html">safe wrappers</a>
around Unix system calls, better reimplementations of standard libc
functionalities, and higher-level manipulations of Unix concepts.
</p>

<p>
 Understanding <tt>djbunix</tt> is essential to understanding any piece
of code depending on skalibs.
</p>

<h2> Functions </h2>

<h3> Basic fd operations </h3>

<p>
<code> int coe (int fd) </code> <br />
Sets the close-on-exec flag on <em>fd</em>.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int uncoe (int fd) </code> <br />
Clears the close-on-exec flag on <em>fd</em>.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int ndelay_on (int fd) </code> <br />
Sets the O_NONBLOCK flag on <em>fd</em>: sets it to non-blocking mode.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int ndelay_off (int fd) </code> <br />
Clears the O_NONBLOCK flag on <em>fd</em>: sets it to blocking mode.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int pipenb (int *p) </code> <br />
Like
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html">pipe()</a>,
but both ends of the created pipe are in non-blocking mode.
</p>

<p>
<code> int pipecoe (int *p) </code> <br />
Like
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html">pipe()</a>,
but both ends of the created pipe are close-on-exec.
</p>

<p>
<code> int pipenbcoe (int *p) </code> <br />
Like
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html">pipe()</a>,
but both ends of the created pipe are in non-blocking mode <em>and</em> close-on-exec.
</p>

<p>
<code> int fd_copy (int to, int from) </code> <br />
Copies the open fd <em>from</em> to number <em>to</em>. If <em>to</em>
was already open, it is closed before the copy.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int fd_copy2 (int to1, int from1, int to2, int from2) </code> <br />
Copies the open fd <em>from1</em> to number <em>to2</em>. Also copies
<em>from2</em> to <em>to2</em> at the same time.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int fd_move (int to, int from) </code> <br />
Moves the open fd <em>from</em> to number <em>to</em>. If <em>to</em>
was already open, it is closed before the move.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int fd_move2 (int to1, int from1, int to2, int from2) </code> <br />
Moves the open fd <em>from</em> to number <em>to</em>. Also moves
<em>from2</em> to <em>to2</em> at the same time. This is useful for instance
when you want to swap two fds: <tt>fd_move2</tt> will handle the situation
correctly.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> void fd_close (int fd) </code> <br />
Closes <em>fd</em>.
This is a <a href="safewrappers.html">safe wrapper</a> around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/close.html">close()</a>.
</p>

<p>
<code> int fd_chmod (int fd, unsigned int mode) </code> <br />
Safe wrapper around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/fchmod.html">fchmod()</a>.
</p>

<p>
<code> int fd_chown (int fd, uid_t uid, gid_t gid) </code> <br />
Safe wrapper around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/fchown.html">fchown()</a>.
This function requires root privileges.
</p>

<p>
<code> int fd_sync (int fd) </code> <br />
Safe wrapper around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/fsync.html">fsync()</a>.
</p>

<p>
<code> int fd_chdir (int fd) </code> <br />
Safe wrapper around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/fchdir.html">fchdir()</a>.
</p>

<p>
<code> int fd_cat (int from, int to) </code> <br />
Synchronously copies data from fd <em>from</em> to fd <em>to</em>,
until it encounters EOF or an error. Returns -1 (and sets errno) if
it fails; returns the number of transmitted bytes if it gets an EOF.
</p>

<p>
When the underlying OS allows it, zero-copy transmission is
performed. Currently, the following zero-copy implementations are
supported:
</p>

<ul>
 <li> <a href="https://man7.org/linux/man-pages/man2/splice.2.html">splice()</a>,
in Linux 2.6.17 and later </li>
</ul>

<p>
<code> size_t fd_catn (int from, int to, size_t n) </code> <br />
Synchronously copies at most <em>n</em> bytes from fd <em>from</em> to fd <em>to</em>.
Returns the total number of transmitted bytes; sets errno if this number
is lesser than <em>n</em>. EOF is reported as EPIPE. See above for zero-copy
transmission; zero-copy transmission is not attempted for less than 64k of data.
</p>

<p>
<code> int fd_ensure_open (int fd, int w) </code> <br />
If <em>fd</em> is not open, opens it to <tt>/dev/null</tt>,
for reading if <em>w</em> is zero, and for writing otherwise.
Returns 1 if it succeeds and 0 if it fails.
</p>

<p>
<code> int fd_sanitize (void) </code> <br />
Ensures stdin, stdout and stderr are open. If one of those
file descriptors was closed, it now points to <tt>/dev/null</tt>.
Returns 1 if it succeeds and 0 if it fails.
</p>

<p>
<code> void fd_shutdown (int fd, int w) </code> <br />
Shuts down socket <em>fd</em>, for reading if <em>w</em> is zero,
and for writing otherwise. Does not return an error code; does
not modify errno. This is just a call to
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html">shutdown()</a>
with errno saved, used essentially to isolate application code from
<tt>sys/socket.h</tt> which is a portability nightmare.
</p>

<p>
<code> int lock_ex (int fd) </code> <br />
Gets an exclusive advisory lock on <em>fd</em>. <em>fd</em> must point to
a regular file, open for writing. Blocks until the lock can be obtained.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int lock_exnb (int fd) </code> <br />
Gets an exclusive advisory lock on <em>fd</em>. <em>fd</em> must point to
a regular file, open for writing.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails. If the lock
is held and the function would block, it immediately returns with -1 EWOULDBLOCK.
</p>

<p>
<code> int lock_sh (int fd) </code> <br />
Gets a shared advisory lock on <em>fd</em>. <em>fd</em> must point to
a regular file, open for reading. Blocks until the lock can be obtained.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int lock_shnb (int fd) </code> <br />
Gets a shared advisory lock on <em>fd</em>. <em>fd</em> must point to
a regular file, open for reading.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails. If the lock
is held and the function would block, it immediately returns with -1 EWOULDBLOCK.
</p>

<p>
<code> int lock_un (int fd) </code> <br />
Releases a previously held lock on <em>fd</em>.
Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> void lock_unx (int fd) </code> <br />
Like <tt>lock_un</tt>, but without a return code and without
modifying errno.
</p>

<p>
<code> int open2 (char const *file, unsigned int flags) </code> <br />
Safe wrapper around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/open.html">open()</a>
when it takes 2 arguments.
</p>

<p>
<code> int open3 (char const *file, unsigned int flags) </code> <br />
Safe wrapper around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/open.html">open()</a>
when it takes 3 arguments.
</p>

<p>
<code> int open_read (char const *file) </code> <br />
Opens <em>file</em> in read-only, non-blocking mode.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openc_read (char const *file) </code> <br />
Opens <em>file</em> in read-only, non-blocking mode, close-on-exec.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openb_read (char const *file) </code> <br />
Opens <em>file</em> in read-only, blocking mode.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openbc_read (char const *file) </code> <br />
Opens <em>file</em> in read-only, blocking mode, close-on-exec.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int open_readb (char const *file) </code> <br />
Opens <em>file</em> in read-only, blocking mode.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
<em>This call does not block.</em> The
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/open.html">open()</a>
system call is actually performed with the O_NONBLOCK option, and blocking mode
is set afterwards; this behaviour allows for more transparent interactions
with FIFOs.
</p>

<p>
<code> int openc_readb (char const *file) </code> <br />
Same as above, but the file is opened close-on-exec.
</p>

<p>
<code> int open_excl (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, with the
additional O_EXCL and O_CREAT flags.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openc_excl (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, close-on-exec, with the
additional O_EXCL and O_CREAT flags.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int open_append (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, with the
additional O_APPEND and O_CREAT flags.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openc_append (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, close-on-exec, with the
additional O_APPEND and O_CREAT flags.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int open_trunc (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, with the
additional O_TRUNC and O_CREAT flags.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openc_trunc (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, close-on-exec, with the
additional O_TRUNC and O_CREAT flags.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int open_create (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, with the
additional O_CREAT flag.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openc_create (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, close-on-exec, with the
additional O_CREAT flag.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int open_write (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<p>
<code> int openc_write (char const *file) </code> <br />
Opens <em>file</em> in write-only, non-blocking mode, close-on-exec.
Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
</p>

<h3> Executable search and execution, and environment </h3>

<p>
<code> void execvep_loose (char const *file, char const *const *argv, char const *const *envp, char const *path) </code> <br />
Executes into the executable file at <em>file</em>, with the command line
set to <em>argv</em> and the environment set to <em>envp</em>.
If <em>file</em> is not an absolute path, it is searched in the
<em>path</em> string, which must contain a colon-separated list of
search directories such as the contents of the PATH environment variable.
The function returns if it fails, and sets errno to the most relevant
error that happened.
</p>

<p>
<code> void execvep (char const *file, char const *const *argv, char const *const *envp, char const *path) </code> <br />
Like <tt>execvep_loose()</tt>, but if <em>file</em> contains a slash,
it is treated as an absolute path.
</p>

<p>
<code> void pathexec_run (char const *file, char const *const *argv, char const *const *envp) </code> <br />
Performs <tt>execvep(file, argv, envp, path)</tt>, <em>path</em> being the
contents of the PATH environment variable. If PATH is not set, <em>path</em>
is set to the value given to the <tt>--with-default-path</tt> option of the
skalibs' <tt>./configure</tt> script, or to <tt>/usr/bin:/bin</tt> by default.
The function returns if it fails, and sets errno appropriately.
</p>

<p>
 <tt>pathexec_run()</tt> is the standard skalibs API to perform an
<tt>exec</tt> call with a path search. It is recommended that you use
it instead of the Single Unix
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/execvp.html">execvp()</a> or
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/execlp.html">execlp()</a>
functions, because <tt>execvp</tt> and <tt>execlp</tt> default to execution of
the <tt>/bin/sh</tt> interpreter with <em>file</em> as an argument if they
cannot find a suitable executable <em>file</em>, and this is:
</p>

<ol>
 <li> a security risk, </li>
 <li> probably not what you want. </li>
</ol>

<p>
 <tt>execvep()</tt> and <tt>pathexec_run()</tt> just fail with ENOENT
when they cannot find a <em>file</em> to exec into, which is the
sensible behaviour.
</p>

<p>
<code> void pathexec0_run (char const *const *argv, char const *const *envp) </code> <br />
Performs <tt>pathexec_run(argv[0], argv, envp)</tt>. If <em>argv</em> is empty, i.e.
<em>argv</em>[0] is null, the process exits 0 instead. Rationale: executing
the empty command line should amount to executing <tt>true</tt>, i.e.
simply exiting 0.
</p>

<p>
<code> void pathexec_r_name (char const *file, char const *const *argv, char const *const *envp, size_t envlen, char const *modifs, size_t modiflen) </code> <br />
Alters <em>envp</em> (which does not have to be NULL-terminated, but the
number <em>envlen</em> of elements must be provided) with the modifier
string <em>modifs</em> of length <em>modiflen</em>, then performs
<tt>pathexec_run(file, argv, altered-envp)</tt>.
</p>

<p>
<code> void pathexec_r (char const *const *argv, char const *const *envp, size_t envlen, char const *modifs, size_t modiflen) </code> <br />
Same as <tt>pathexec_r_name</tt>, except that the <em>file</em> argument is read from <em>argv</em>[0].
</p>

<p>
<code> int pathexec_env (char const *var, char const *value) </code> <br />
Adds the "add variable <em>var</em> with value <em>value</em>" instruction
(if <em>value</em> is not null) or the "unset <em>var</em>" instruction
(if <em>value</em> is null) to a static hidden modifier string, used by the
following three functions.
Returns 1 if it succeeds and 0 (and sets errno) if it fails. 
</p>

<p>
<code> void pathexec_fromenv (char const *const *argv, char const *const *envp, size_t envlen) </code> <br />
Performs <tt>pathexec_r()</tt> with the given arguments and the hidden modifier
string.
</p>

<p>
<code> void pathexec (char const *const *argv) </code> <br />
Executes into the <em>argv</em> command line, with the current environment
modified by the hidden modifier string.
</p>

<p>
<code> void pathexec0 (char const *const *argv) </code> <br />
Executes into the <em>argv</em> command line, with the current environment
modified by the hidden modifier string. If this command line is empty,
exit 0 instead.
</p>

<p> <code>
void xexecvep (char const *, char const *const *, char const *const *, char const *) <br />
void xpathexec_r (char const *const *, char const *const *, size_t, char const *, size_t) <br />
void xpathexec_r_name (char const *, char const *const *, char const *const *, size_t, char const *, size_t) <br />
void xpathexec_fromenv (char const *const *, char const *const *, size_t) <br />
void xpathexec_run (char const *, char const *const *, char const *const *) <br />
void xpathexec0_run (char const *const *, char const *const *) <br />
void xpathexec (char const *const *) <br />
void xpathexec0 (char const *const *)
</code> </p>

<p>
 Those functions provide the same functionality as the non-x-prefixed versions,
but if the execution fails (i.e. the process cannot exec into a new program), then
the process dies with a 111 exit code and an error message on stderr.
</p>

<p>
 The <a href="env.html">env</a> library interface provides additional functions
to manipulate modifier strings and environments.
</p>

<h3> Forking children </h3>

<p>
<code> pid_t doublefork () </code> <br />
Performs a double fork. Returns -1 if it fails (and
sets errno, EINTR meaning that the intermediate process
was killed by a signal), 0 if the current process is the grandchild,
and the grandchild's PID if the current process is the parent.
</p>

<p>
<code> pid_t child_spawn0 (char const *file, char const *const *argv, char const *const *envp) </code> <br />
Forks and executes a child as with <tt>pathexec_run(file, argv, envp)</tt>.
Returns 0 if it fails, and the pid of the child if it succeeds.
Implemented via <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html">posix_spawn()</a>
on systems that support it.
</p>

<p>
<code> pid_t child_spawn1_pipe (char const *file, char const *const *argv, char const *const *envp, int *fd, int w) </code> <br />
Like <tt>child_spawn0()</tt>, except that a pipe is created between the child's
stdin (if <em>w</em> is 0) or stdout (if <em>w</em> is nonzero) and the parent.
The parent's end of the pipe will be stored in *<em>fd</em>.
</p>

<p>
<code> pid_t child_spawn1_socket (char const *file, char const *const *argv, char const *const *envp, int *fd) </code> <br />
Like <tt>child_spawn0</tt>, except that a socket is created between the parent
and the child. Both the child's stdin and stdout point to the socket; the parent has
its end of the socket available in *<em>fd</em>.
</p>

<p>
<code> pid_t child_spawn2 (char const *file, char const *const *argv, char const *const *envp, int *fds) </code> <br />
Like <tt>child_spawn0()</tt>, except that two pipes are created between the
parent and the child. <em>fds</em> must point to an array of 2 ints: this
array is read as well as written by <tt>child_spawn2()</tt>. On function
call, the numbers in <em>fds</em> must describe what fds should be used
in the child to contain the communication pipes (for instance, if the child
will read from its parent on stdin and writes to its parent on stdout, <em>fds</em>
must contain 0 and 1). On function return, <em>fds</em> contains the
descriptors for the pipes that read from / write to the child.
</p>

<p>
<code> pid_t child_spawn (char const *file, char const *const *argv, char const *const *envp, int *fds, unsigned int nfds) </code> <br />
More generic spawning function. <em>fds</em> must point to an array of at least <em>nfds</em> ints;
file descriptors reading from or writing to the child will be stored there. The function returns
0 on failure or the pid of the child on success.
</p>
<ul>
 <li> If <em>nfds</em> is 0, then the function behaves like <tt>child_spawn0</tt>, except
all ignored signals will be un-ignored in the child </li>
 <li> If <em>nfds</em> is 1 or more, then <em>fds</em> will contain pipes between the
child and the parent. The parent will read on even-numbered ones (starting on <em>fds</em>[0])
and write on odd-numbered ones. </li>
</ul>

<h3> Waiting for children </h3>

<p>
<code> unsigned int wait_reap () </code> <br />
Instantly reaps all the pending zombies, without blocking, without a look at
the exit codes.
Returns the number of reaped zombies.
</p>

<p>
<code> int waitn (pid_t *pids, unsigned int n) </code> <br />
Waits until all processes whose PIDs are stored in the
<em>pids</em> array, of size <em>n</em>, have died.
Returns 1 if it succeeds, and 0 (and sets errno) if it fails. The
<em>pid</em> array is not guaranteed to be unchanged.
</p>

<p>
<code> int waitn_reap (pid_t *pids, unsigned int n) </code> <br />
Instantly reaps all zombies whose PIDs are stored in the
<em>pids</em> array, of size <em>n</em>.
Returns -1 (and sets errno) if it fails, and the number of reaped
zombies if it succeeds. The <em>pid</em> array is not guaranteed to
be unchanged.
</p>

<p>
<code> pid_t wait_nohang (int *wstat) </code> <br />
Instantly reaps one zombie, and stores the status information into
*<em>wstat</em>.
Returns the PID of the reaped zombie if it succeeds, 0 if there was
nothing to reap (and the current process still has children), -1 ECHILD
if there was nothing to reap (and the current process has no children),
or -1 (and sets errno) if it fails.
</p>

<p>
<code> pid_t waitpid_nointr (pid_t pid, int *wstat, int flags) </code> <br />
Safe wrapper around
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/waitpid.html">waitpid()</a>.
</p>

<p>
<code> pid_t wait_pid_nohang (pid_t pid, int *wstat) </code> <br />
Instantly reaps an undetermined number of zombies until it finds <em>pid</em>.
Stores the status information for dead <em>pid</em> into *<em>wstat</em>.
Returns <em>pid</em> if it succeeds, 0 if there was
nothing to reap (and the current process still has children), -1 ECHILD
if there was nothing to reap (and the current process has no children),
or -1 (and sets errno) if it fails.
</p>

<p>
<code> int wait_pids_nohang (pid_t const *pids, unsigned int len, int *wstat) </code> <br />
Instantly reaps an undetermined number of zombies until it finds one whose
PID is in the <em>pids</em> array, of size <em>len</em>.
Stores the status information for that dead process into *<em>wstat</em>.
Returns the index of the found PID in <em>pids</em>, starting at 1.
Returns 0 if there was
nothing to reap (and the current process still has children), -1 ECHILD
if there was nothing to reap (and the current process has no children),
or -1 (and sets errno) if it fails.
</p>

<p>
 When asynchronously dealing with a child (resp. several children) and
getting a SIGCHLD - which should be handled via a
<a href="selfpipe.html">selfpipe</a> - it is generally a good idea to
use the <tt>wait_pid_nohang()</tt> (resp. <tt>wait_pids_nohang()</tt>)
function over the basic Unix APIs. This allows a program to:
</p>

<ul>
 <li> Automatically and silently take care of children it does not know
it has. This situation can happen when a process forks and the parent
execs. When the child dies, the new parent process has to drag the
"zombie bastard" along, which is ugly; <tt>wait_pids_nohang()</tt>
prevents this. </li>
 <li> Still take appropriate care of its legitimate children, in
any order. </li>
</ul>

<h3> Reading and writing whole files </h3>

<p>
<code> int slurp (stralloc *sa, int fd) </code> <br />
Slurps the contents of open descriptor <em>fd</em> into
the *<em>sa</em> <a href="stralloc.html">stralloc</a>. If you are
doing this, you should either have full control over the slurped
file, or run your process with suitable
<a href="//skarnet.org/software/s6/s6-softlimit.html">limits</a>
to the amount of heap memory it can get.
The function returns 1 if it succeeds, or 0 (and sets errno) if it fails.
</p>

<p>
<code> int openslurpclose (stralloc *sa, char const *file) </code> <br />
Slurps the contents of file <em>file</em> into *<em>sa</em>.
Returns 1 if it succeeds, and 0 (and sets errno) if it fails.
</p>

<p>
<code> ssize_t openreadnclose (char const *file, char *s, size_t n) </code> <br />
Reads at most <em>n</em> bytes from file <em>file</em> into preallocated
buffer <em>s</em>. Returns -1 (and sets errno) if it fails; else returns the
number of read bytes. If that number is not <em>n</em>, errno is set to EPIPE.
</p>

<p>
<code> ssize_t openreadnclose_nb (char const *file, char *s, size_t n) </code> <br />
Like <tt>openreadnclose</tt>, but can fail with EAGAIN if the file cannot be
immediately read (for instance if it's a named pipe or other special file).
</p>

<p>
<code> int openreadfileclose (char const *file, stralloc *sa, size_t n) </code> <br />
Reads at most <em>n</em> bytes from file <em>file</em> into the *<em>sa</em>
stralloc, which is grown (if needed) to <em>just</em> accommodate the file
size. Returns 1 if it succeeds and 0 (and sets errno) if it fails.
</p>

<p>
<code> int openwritenclose_unsafe_internal (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino, int dosync) </code> <br />
Writes the <em>n</em> bytes stored at <em>s</em> into file <em>file</em>.
The previous contents of <em>file</em> are destroyed even if the function
fails. If <em>dosync</em> is nonzero, the new contents of <em>file</em>
are synced to disk before the function returns. If <em>dev</em> and <em>ino</em>
are not null, they're used to store the device and inode number of <em>file</em>.
The function returns 1 if it succeeds, or 0 (and sets errno) if it fails.
</p>

<p>
<code> int openwritenclose_unsafe (char const *file, char const *s, size_t len) <br />
int openwritenclose_unsafe_sync (char const *file, char const *s, size_t len) <br />
int openwritenclose_unsafe_devino (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino) <br />
int openwritenclose_unsafe_devino_sync (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino) </code> <br />
Trivial shortcuts around <tt>openwritenclose_unsafe_internal()</tt>. The
reader can easily figure out what they do.
</p>

<p>
<code> int openwritenclose_suffix_internal (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino, int dosync, char const *suffix) </code> <br />
Writes the <em>n</em> bytes stored at <em>s</em> into file <em>file</em>,
by first writing into <em>filesuffix</em> and atomically renaming
<em>filesuffix</em> to <em>file</em>. IOW, the old contents of <em>file</em>
are preserved if the operation fails, and are atomically replaced with the
new contents if the operation succeeds.
If <em>dosync</em> is nonzero, the new contents of <em>filesuffix</em>
are synced to disk before the atomic replace. If <em>dev</em> and <em>ino</em>
are not null, they're used to store the device and inode number of <em>file</em>.
The function returns 1 if it succeeds, or 0 (and sets errno) if it fails.
</p>

<p>
<code> int openwritenclose_suffix (char const *file, char const *s, size_t len, char const *suffix) <br />
int openwritenclose_suffix_sync (char const *file, char const *s, size_t len, char const *suffix) <br />
int openwritenclose_suffix_devino (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino, char const *suffix) <br />
int openwritenclose_suffix_devino_sync (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino, char const *suffix) </code> <br />
Trivial shortcuts around <tt>openwritenclose_suffix_internal()</tt>. The
reader can easily figure out what they do.
</p>

<p>
<code> int openwritevnclose_unsafe_internal (char const *file, struct iovec const *v, unsigned int vlen, dev_t *dev, ino_t *ino, int dosync) </code> <br />
Like <tt>openwritenclose_unsafe_internal</tt>, but the content to
write is taken from a
<a href="siovec.html">scatter/gather array</a> of <em>vlen</em>
elements instead of a single string.
</p>

<p>
<code> int openwritevnclose_unsafe (char const *file, struct iovec const *v, unsigned int vlen) <br />
int openwritevnclose_unsafe_sync (char const *file, struct iovec const *v, unsigned int vlen) <br />
int openwritevnclose_unsafe_devino (char const *file, struct iovec const *v, unsigned int vlen, dev_t *dev, ino_t *ino) <br />
int openwritevnclose_unsafe_devino_sync (char const *file, struct iovec const *v, unsigned int vlen, dev_t *dev, ino_t *ino) </code> <br />
Trivial wrappers around <tt>openwritevnclose_unsafe_internal()</tt>.
</p>

<p>
<code> int openwritevnclose_suffix_internal (char const *file, struct iovec const *v, unsigned int vlen, dev_t *dev, ino_t *ino, int dosync, char const *suffix) </code> <br />
Like <tt>openwritenclose_suffix_internal</tt>, but the content to
write is taken from a
<a href="siovec.html">scatter/gather array</a> of <em>vlen</em>
elements instead of a single string.
</p>

<p>
<code> int openwritenclose_suffix (char const *file, char const *s, size_t len, char const *suffix) <br />
int openwritenclose_suffix_sync (char const *file, char const *s, size_t len, char const *suffix) <br />
int openwritenclose_suffix_devino (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino, char const *suffix) <br />
int openwritenclose_suffix_devino_sync (char const *file, char const *s, size_t len, dev_t *dev, ino_t *ino, char const *suffix) </code> <br />
Trivial wrappers around <tt>openwritevnclose_suffix_internal()</tt>.
</p>

<h3> Filesystem deletion </h3>

<p>
The following operations are not atomic, so if they fail, the
relevant subtree might end up partially deleted.
</p>

<p>
<code> int rm_rf (char const *path) </code> <br />
Deletes the filesystem subtree at <em>path</em>.
Returns 0 if it succeeds or -1 (and sets errno) if it fails.
</p>

<p>
<code> int rm_rf_tmp (char const *path, stralloc *tmp) </code> <br />
Deletes the filesystem subtree at <em>path</em>, using *<em>tmp</em>
as heap-allocated temporary space.
Returns 0 if it succeeds or -1 (and sets errno) if it fails.
</p>

<p>
<code> int rm_rf_in_tmp (stralloc *tmp, size_t n) </code> <br />
Deletes a filesystem subtree, using *<em>tmp</em>
as heap-allocated temporary space.
Returns 0 if it succeeds or -1 (and sets errno) if it fails.
When the function is called, *<em>tmp</em> must contain the
null-terminated name of the subtree to delete at offset <em>n</em>.
</p>

<p>
<code> int rmstar (char const *dir) </code> <br />
Deletes all the filesystem subtrees in directory <em>dir</em>.
Returns 0 if it succeeds or -1 (and sets errno) if it fails.
</p>

<p>
<code> int rmstar_tmp (char const *dir, stralloc *tmp) </code> <br />
Deletes all the filesystem subtrees in directory <em>dir</em>,
using *<em>tmp</em> as heap-allocated temporary space.
Returns 0 if it succeeds or -1 (and sets errno) if it fails.
</p>

<h3> Filesystem copy </h3>

<p>
<code> int hiercopy_tmp (char const *src, char const *dst, stralloc *tmp) </code> <br />
Recursively copies the filesystem hierarchy at <em>src</em> into
<em>dst</em>, preserving modes, and also preserving the uids/gids if the
process is running as the super-user.
Uses *<em>tmp</em> as heap-allocated temporary space.
Returns 1 if it succeeds or 0 (and sets errno) if it fails.
</p>

<p>
<code> int hiercopy (char const *src, char const *dst) </code> <br />
Same as above, using the <tt>satmp</tt> global stralloc as
heap-allocated temporary space.
</p>

<h3> Variable length wrappers around Single Unix calls </h3>

<p>
<code> int sarealpath (stralloc *sa, char const *path) </code> <br />
Resolves <em>path</em> into a symlink-free absolute path, appending
the result to the *<em>sa</em>
<a href="stralloc.html">stralloc</a>.
Returns 0 if it succeeds and -1 (and sets errno) if it fails.
</p>

<p>
<code> int sarealpath_tmp (stralloc *sa, char const *path, stralloc *tmp) </code> <br />
Resolves <em>path</em> into a symlink-free absolute path, appending
the result to *<em>sa</em>. Uses *<em>tmp</em> as heap-allocated
temporary space.
Returns 0 if it succeeds and -1 (and sets errno) if it fails.
</p>

<p>
<code> int sabasename (stralloc *sa, char const *s, size_t len) </code> <br />
Appends the basename of filename <em>s</em> (of length <em>len</em>)
to *<em>sa</em>.
Returns 1 if it succeeds and 0 (and sets errno) if it fails.
</p>

<p>
<code> int sadirname (stralloc *sa, char const *s, size_t len) </code> <br />
Appends the dirname of filename <em>s</em> (of length <em>len</em>)
to *<em>sa</em>.
Returns 1 if it succeeds and 0 (and sets errno) if it fails.
</p>

<p>
<code> int sagetcwd (stralloc *sa) </code> <br />
Appends the current working directory to *<em>sa</em>.
Returns 0 if it succeeds and -1 (and sets errno) if it fails.
</p>

<p>
<code> int sareadlink (stralloc *sa, char const *link) </code> <br />
Appends the contents of symbolic link <em>link</em> to *<em>sa</em>.
Returns 0 if it succeeds and -1 (and sets errno) if it fails.
</p>

<p>
<code> int sagethostname (stralloc *sa) </code> <br />
Appends the machine's hostname to *<em>sa</em>.
Returns 0 if it succeeds and -1 (and sets errno) if it fails.
</p>

<h3> Temporization </h3>

<p>
<code> void deepsleepuntil (tain_t const *deadline, tain_t *stamp) </code> <br />
Sleeps until the absolute time represented by the
<a href="tai.html">tain_t</a> *<em>deadline</em>. *<em>stamp</em>
must contain the current time. When the function returns, *<em>stamp</em>
has been updated to reflect the new current time.
</p>

<p>
<code> void deepsleep (unsigned int n) </code> <br />
Sleeps <em>n</em> seconds. Signals received during that time are handled,
but <em>do not</em> interrupt the sleep.
</p>

<p>
<code> void deepmillisleep (unsigned long n) </code> <br />
Sleeps <em>n</em> milliseconds. Signals received during that time are handled,
but <em>do not</em> interrupt the sleep.
</p>

<h3> Miscellaneous functions </h3>

<p>
<code> size_t path_canonicalize (char *out, char const *in, int check) </code> <br />
Writes into <em>out</em> the canonical form of the Unix path given in
<em>in</em>. The <em>out</em> array must be preallocated with at least
<tt>strlen(in)+2</tt> bytes. Returns the length of the <em>out</em> path, without
counting the terminating null byte. If <em>check</em> is nonzero, <em>in</em> is tested
for every <tt>foobar/..</tt> element, and the function returns 0, and sets errno
appropriately, if <tt>foobar</tt> is not a valid directory; in that case, <em>out</em>
contains the problematic path.
</p>

</body>
</html>