/
libbb.h
1914 lines (1754 loc) · 72.6 KB
/
libbb.h
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
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* vi: set sw=4 ts=4: */
/*
* Busybox main internal header file
*
* Based in part on code from sash, Copyright (c) 1999 by David I. Bell
* Permission has been granted to redistribute this code under GPL.
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
#ifndef LIBBB_H
#define LIBBB_H 1
#include "platform.h"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <netdb.h>
#include <setjmp.h>
#include <signal.h>
#if defined __UCLIBC__ /* TODO: and glibc? */
/* use inlined versions of these: */
# define sigfillset(s) __sigfillset(s)
# define sigemptyset(s) __sigemptyset(s)
# define sigisemptyset(s) __sigisemptyset(s)
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
/* There are two incompatible basename's, let not use them! */
/* See the dirname/basename man page for details */
#include <libgen.h> /* dirname,basename */
#undef basename
#define basename dont_use_basename
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#ifndef major
# include <sys/sysmacros.h>
#endif
#include <sys/wait.h>
#include <termios.h>
#include <time.h>
#include <sys/param.h>
#include <pwd.h>
#include <grp.h>
#if ENABLE_FEATURE_SHADOWPASSWDS
# if !ENABLE_USE_BB_SHADOW
/* If using busybox's shadow implementation, do not include the shadow.h
* header as the toolchain may not provide it at all.
*/
# include <shadow.h>
# endif
#endif
#if defined(ANDROID) || defined(__ANDROID__)
# define endpwent() ((void)0)
# define endgrent() ((void)0)
#endif
#ifdef HAVE_MNTENT_H
# include <mntent.h>
#endif
#ifdef HAVE_SYS_STATFS_H
# include <sys/statfs.h>
#endif
/* Don't do this here:
* #include <sys/sysinfo.h>
* Some linux/ includes pull in conflicting definition
* of struct sysinfo (only in some toolchanins), which breaks build.
* Include sys/sysinfo.h only in those files which need it.
*/
#if ENABLE_SELINUX
# include <selinux/selinux.h>
# include <selinux/context.h>
# include <selinux/flask.h>
# include <selinux/av_permissions.h>
#endif
#if ENABLE_FEATURE_UTMP
# include <utmp.h>
#endif
#if ENABLE_LOCALE_SUPPORT
# include <locale.h>
#else
# define setlocale(x,y) ((void)0)
#endif
#ifdef DMALLOC
# include <dmalloc.h>
#endif
/* Just in case libc doesn't define some of these... */
#ifndef _PATH_PASSWD
#define _PATH_PASSWD "/etc/passwd"
#endif
#ifndef _PATH_GROUP
#define _PATH_GROUP "/etc/group"
#endif
#ifndef _PATH_SHADOW
#define _PATH_SHADOW "/etc/shadow"
#endif
#ifndef _PATH_GSHADOW
#define _PATH_GSHADOW "/etc/gshadow"
#endif
#if defined __FreeBSD__ || defined __OpenBSD__
# include <netinet/in.h>
# include <arpa/inet.h>
#elif defined __APPLE__
# include <netinet/in.h>
#else
# include <arpa/inet.h>
# if !defined(__socklen_t_defined) && !defined(_SOCKLEN_T_DECLARED)
/* We #define socklen_t *after* includes, otherwise we get
* typedef redefinition errors from system headers
* (in case "is it defined already" detection above failed)
*/
# define socklen_t bb_socklen_t
typedef unsigned socklen_t;
# endif
#endif
#ifndef HAVE_CLEARENV
# define clearenv() do { if (environ) environ[0] = NULL; } while (0)
#endif
#ifndef HAVE_FDATASYNC
# define fdatasync fsync
#endif
#ifndef HAVE_XTABS
# define XTABS TAB3
#endif
/* Some libc's forget to declare these, do it ourself */
extern char **environ;
#if defined(__GLIBC__) && __GLIBC__ < 2
int vdprintf(int d, const char *format, va_list ap);
#endif
/* klogctl is in libc's klog.h, but we cheat and not #include that */
int klogctl(int type, char *b, int len);
#ifndef PATH_MAX
# define PATH_MAX 256
#endif
#ifndef BUFSIZ
# define BUFSIZ 4096
#endif
/* Busybox does not use threads, we can speed up stdio. */
#ifdef HAVE_UNLOCKED_STDIO
# undef getc
# define getc(stream) getc_unlocked(stream)
# undef getchar
# define getchar() getchar_unlocked()
# undef putc
# define putc(c, stream) putc_unlocked(c, stream)
# undef putchar
# define putchar(c) putchar_unlocked(c)
# undef fgetc
# define fgetc(stream) getc_unlocked(stream)
# undef fputc
# define fputc(c, stream) putc_unlocked(c, stream)
#endif
/* Above functions are required by POSIX.1-2008, below ones are extensions */
#ifdef HAVE_UNLOCKED_LINE_OPS
# undef fgets
# define fgets(s, n, stream) fgets_unlocked(s, n, stream)
# undef fputs
# define fputs(s, stream) fputs_unlocked(s, stream)
#endif
/* Make all declarations hidden (-fvisibility flag only affects definitions) */
/* (don't include system headers after this until corresponding pop!) */
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
#if ENABLE_USE_BB_PWD_GRP
# include "pwd_.h"
# include "grp_.h"
#endif
#if ENABLE_FEATURE_SHADOWPASSWDS
# if ENABLE_USE_BB_SHADOW
# include "shadow_.h"
# endif
#endif
/* Tested to work correctly with all int types (IIRC :]) */
#define MAXINT(T) (T)( \
((T)-1) > 0 \
? (T)-1 \
: (T)~((T)1 << (sizeof(T)*8-1)) \
)
#define MININT(T) (T)( \
((T)-1) > 0 \
? (T)0 \
: ((T)1 << (sizeof(T)*8-1)) \
)
/* Large file support */
/* Note that CONFIG_LFS=y forces bbox to be built with all common ops
* (stat, lseek etc) mapped to "largefile" variants by libc.
* Practically it means that open() automatically has O_LARGEFILE added
* and all filesize/file_offset parameters and struct members are "large"
* (in today's world - signed 64bit). For full support of large files,
* we need a few helper #defines (below) and careful use of off_t
* instead of int/ssize_t. No lseek64(), O_LARGEFILE etc necessary */
#if ENABLE_LFS
/* CONFIG_LFS is on */
# if ULONG_MAX > 0xffffffff
/* "long" is long enough on this system */
typedef unsigned long uoff_t;
# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX)
/* usage: sz = BB_STRTOOFF(s, NULL, 10); if (errno || sz < 0) die(); */
# define BB_STRTOOFF bb_strtoul
# define STRTOOFF strtoul
/* usage: printf("size: %"OFF_FMT"d (%"OFF_FMT"x)\n", sz, sz); */
# define OFF_FMT "l"
# else
/* "long" is too short, need "long long" */
typedef unsigned long long uoff_t;
# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX)
# define BB_STRTOOFF bb_strtoull
# define STRTOOFF strtoull
# define OFF_FMT "ll"
# endif
#else
/* CONFIG_LFS is off */
# if UINT_MAX == 0xffffffff
/* While sizeof(off_t) == sizeof(int), off_t is typedef'ed to long anyway.
* gcc will throw warnings on printf("%d", off_t). Crap... */
typedef unsigned long uoff_t;
# define XATOOFF(a) xatoi_positive(a)
# define BB_STRTOOFF bb_strtou
# define STRTOOFF strtol
# define OFF_FMT "l"
# else
typedef unsigned long uoff_t;
# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX)
# define BB_STRTOOFF bb_strtoul
# define STRTOOFF strtol
# define OFF_FMT "l"
# endif
#endif
/* scary. better ideas? (but do *test* them first!) */
#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1)))
/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested.
* We misdetected that. Don't let it build:
*/
struct BUG_off_t_size_is_misdetected {
char BUG_off_t_size_is_misdetected[sizeof(off_t) == sizeof(uoff_t) ? 1 : -1];
};
/* Some useful definitions */
#undef FALSE
#define FALSE ((int) 0)
#undef TRUE
#define TRUE ((int) 1)
#undef SKIP
#define SKIP ((int) 2)
/* Macros for min/max. */
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
/* buffer allocation schemes */
#if ENABLE_FEATURE_BUFFERS_GO_ON_STACK
#define RESERVE_CONFIG_BUFFER(buffer,len) char buffer[len]
#define RESERVE_CONFIG_UBUFFER(buffer,len) unsigned char buffer[len]
#define RELEASE_CONFIG_BUFFER(buffer) ((void)0)
#else
#if ENABLE_FEATURE_BUFFERS_GO_IN_BSS
#define RESERVE_CONFIG_BUFFER(buffer,len) static char buffer[len]
#define RESERVE_CONFIG_UBUFFER(buffer,len) static unsigned char buffer[len]
#define RELEASE_CONFIG_BUFFER(buffer) ((void)0)
#else
#define RESERVE_CONFIG_BUFFER(buffer,len) char *buffer = xmalloc(len)
#define RESERVE_CONFIG_UBUFFER(buffer,len) unsigned char *buffer = xmalloc(len)
#define RELEASE_CONFIG_BUFFER(buffer) free(buffer)
#endif
#endif
#if defined(__GLIBC__)
/* glibc uses __errno_location() to get a ptr to errno */
/* We can just memorize it once - no multithreading in busybox :) */
extern int *const bb_errno;
#undef errno
#define errno (*bb_errno)
#endif
#if !(ULONG_MAX > 0xffffffff)
/* Only 32-bit CPUs need this, 64-bit ones use inlined version */
uint64_t bb_bswap_64(uint64_t x) FAST_FUNC;
#endif
unsigned long long monotonic_ns(void) FAST_FUNC;
unsigned long long monotonic_us(void) FAST_FUNC;
unsigned long long monotonic_ms(void) FAST_FUNC;
unsigned monotonic_sec(void) FAST_FUNC;
extern void chomp(char *s) FAST_FUNC;
extern void trim(char *s) FAST_FUNC;
extern char *skip_whitespace(const char *) FAST_FUNC;
extern char *skip_non_whitespace(const char *) FAST_FUNC;
extern char *skip_dev_pfx(const char *tty_name) FAST_FUNC;
extern char *strrstr(const char *haystack, const char *needle) FAST_FUNC;
//TODO: supply a pointer to char[11] buffer (avoid statics)?
extern const char *bb_mode_string(mode_t mode) FAST_FUNC;
extern int is_directory(const char *name, int followLinks) FAST_FUNC;
enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */
FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */
FILEUTILS_DEREFERENCE = 1 << 1, /* !-d */
FILEUTILS_RECUR = 1 << 2, /* -R */
FILEUTILS_FORCE = 1 << 3, /* -f */
FILEUTILS_INTERACTIVE = 1 << 4, /* -i */
FILEUTILS_MAKE_HARDLINK = 1 << 5, /* -l */
FILEUTILS_MAKE_SOFTLINK = 1 << 6, /* -s */
FILEUTILS_DEREF_SOFTLINK = 1 << 7, /* -L */
FILEUTILS_DEREFERENCE_L0 = 1 << 8, /* -H */
#if ENABLE_SELINUX
FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 9, /* -c */
FILEUTILS_SET_SECURITY_CONTEXT = 1 << 10,
#endif
FILEUTILS_IGNORE_CHMOD_ERR = 1 << 11,
};
#define FILEUTILS_CP_OPTSTR "pdRfilsLH" IF_SELINUX("c")
extern int remove_file(const char *path, int flags) FAST_FUNC;
/* NB: without FILEUTILS_RECUR in flags, it will basically "cat"
* the source, not copy (unless "source" is a directory).
* This makes "cp /dev/null file" and "install /dev/null file" (!!!)
* work coreutils-compatibly. */
extern int copy_file(const char *source, const char *dest, int flags) FAST_FUNC;
#if ENABLE_XATTR
extern int copy_file_attr(const char *src_path, const char *dst_path) FAST_FUNC;
#endif
enum {
ACTION_RECURSE = (1 << 0),
ACTION_FOLLOWLINKS = (1 << 1),
ACTION_FOLLOWLINKS_L0 = (1 << 2),
ACTION_DEPTHFIRST = (1 << 3),
/*ACTION_REVERSE = (1 << 4), - unused */
ACTION_QUIET = (1 << 5),
ACTION_DANGLING_OK = (1 << 6),
};
typedef uint8_t recurse_flags_t;
extern int recursive_action(const char *fileName, unsigned flags,
int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth),
int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth),
void* userData, unsigned depth) FAST_FUNC;
extern int device_open(const char *device, int mode) FAST_FUNC;
enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */
extern int xgetpty(char *line) FAST_FUNC;
extern int get_console_fd_or_die(void) FAST_FUNC;
extern void console_make_active(int fd, const int vt_num) FAST_FUNC;
extern char *find_block_device(const char *path) FAST_FUNC;
/* bb_copyfd_XX print read/write errors and return -1 if they occur */
extern off_t bb_copyfd_eof(int fd1, int fd2) FAST_FUNC;
extern off_t bb_copyfd_size(int fd1, int fd2, off_t size) FAST_FUNC;
extern void bb_copyfd_exact_size(int fd1, int fd2, off_t size) FAST_FUNC;
/* "short" copy can be detected by return value < size */
/* this helper yells "short read!" if param is not -1 */
extern void complain_copyfd_and_die(off_t sz) NORETURN FAST_FUNC;
extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC;
char* strcpy_and_process_escape_sequences(char *dst, const char *src) FAST_FUNC;
/* xxxx_strip version can modify its parameter:
* "/" -> "/"
* "abc" -> "abc"
* "abc/def" -> "def"
* "abc/def/" -> "def" !!
*/
char *bb_get_last_path_component_strip(char *path) FAST_FUNC;
/* "abc/def/" -> "" and it never modifies 'path' */
char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC;
/* Simpler version: does not special case "/" string */
const char *bb_basename(const char *name) FAST_FUNC;
/* NB: can violate const-ness (similarly to strchr) */
char *last_char_is(const char *s, int c) FAST_FUNC;
void ndelay_on(int fd) FAST_FUNC;
void ndelay_off(int fd) FAST_FUNC;
void close_on_exec_on(int fd) FAST_FUNC;
void xdup2(int, int) FAST_FUNC;
void xmove_fd(int, int) FAST_FUNC;
DIR *xopendir(const char *path) FAST_FUNC;
DIR *warn_opendir(const char *path) FAST_FUNC;
char *xmalloc_realpath(const char *path) FAST_FUNC RETURNS_MALLOC;
char *xmalloc_readlink(const char *path) FAST_FUNC RETURNS_MALLOC;
char *xmalloc_readlink_or_warn(const char *path) FAST_FUNC RETURNS_MALLOC;
/* !RETURNS_MALLOC: it's a realloc-like function */
char *xrealloc_getcwd_or_warn(char *cwd) FAST_FUNC;
char *xmalloc_follow_symlinks(const char *path) FAST_FUNC RETURNS_MALLOC;
enum {
/* bb_signals(BB_FATAL_SIGS, handler) catches all signals which
* otherwise would kill us, except for those resulting from bugs:
* SIGSEGV, SIGILL, SIGFPE.
* Other fatal signals not included (TODO?):
* SIGBUS Bus error (bad memory access)
* SIGPOLL Pollable event. Synonym of SIGIO
* SIGPROF Profiling timer expired
* SIGSYS Bad argument to routine
* SIGTRAP Trace/breakpoint trap
*
* The only known arch with some of these sigs not fitting
* into 32 bits is parisc (SIGXCPU=33, SIGXFSZ=34, SIGSTKFLT=36).
* Dance around with long long to guard against that...
*/
BB_FATAL_SIGS = (int)(0
+ (1LL << SIGHUP)
+ (1LL << SIGINT)
+ (1LL << SIGTERM)
+ (1LL << SIGPIPE) // Write to pipe with no readers
+ (1LL << SIGQUIT) // Quit from keyboard
+ (1LL << SIGABRT) // Abort signal from abort(3)
+ (1LL << SIGALRM) // Timer signal from alarm(2)
+ (1LL << SIGVTALRM) // Virtual alarm clock
+ (1LL << SIGXCPU) // CPU time limit exceeded
+ (1LL << SIGXFSZ) // File size limit exceeded
+ (1LL << SIGUSR1) // Yes kids, these are also fatal!
+ (1LL << SIGUSR2)
+ 0),
};
void bb_signals(int sigs, void (*f)(int)) FAST_FUNC;
/* Unlike signal() and bb_signals, sets handler with sigaction()
* and in a way that while signal handler is run, no other signals
* will be blocked; syscalls will not be restarted: */
void bb_signals_recursive_norestart(int sigs, void (*f)(int)) FAST_FUNC;
/* syscalls like read() will be interrupted with EINTR: */
void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int)) FAST_FUNC;
/* syscalls like read() won't be interrupted (though select/poll will be): */
void signal_SA_RESTART_empty_mask(int sig, void (*handler)(int)) FAST_FUNC;
void wait_for_any_sig(void) FAST_FUNC;
void kill_myself_with_sig(int sig) NORETURN FAST_FUNC;
void sig_block(int sig) FAST_FUNC;
void sig_unblock(int sig) FAST_FUNC;
/* Will do sigaction(signum, act, NULL): */
int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC;
/* SIG_BLOCK/SIG_UNBLOCK all signals: */
int sigprocmask_allsigs(int how) FAST_FUNC;
/* Standard handler which just records signo */
extern smallint bb_got_signal;
void record_signo(int signo); /* not FAST_FUNC! */
void xsetgid(gid_t gid) FAST_FUNC;
void xsetuid(uid_t uid) FAST_FUNC;
void xchdir(const char *path) FAST_FUNC;
void xchroot(const char *path) FAST_FUNC;
void xsetenv(const char *key, const char *value) FAST_FUNC;
void bb_unsetenv(const char *key) FAST_FUNC;
void bb_unsetenv_and_free(char *key) FAST_FUNC;
void xunlink(const char *pathname) FAST_FUNC;
void xstat(const char *pathname, struct stat *buf) FAST_FUNC;
void xfstat(int fd, struct stat *buf, const char *errmsg) FAST_FUNC;
int xopen(const char *pathname, int flags) FAST_FUNC;
int xopen_nonblocking(const char *pathname) FAST_FUNC;
int xopen3(const char *pathname, int flags, int mode) FAST_FUNC;
int open_or_warn(const char *pathname, int flags) FAST_FUNC;
int open3_or_warn(const char *pathname, int flags, int mode) FAST_FUNC;
int open_or_warn_stdin(const char *pathname) FAST_FUNC;
int xopen_stdin(const char *pathname) FAST_FUNC;
void xrename(const char *oldpath, const char *newpath) FAST_FUNC;
int rename_or_warn(const char *oldpath, const char *newpath) FAST_FUNC;
off_t xlseek(int fd, off_t offset, int whence) FAST_FUNC;
int xmkstemp(char *template) FAST_FUNC;
off_t fdlength(int fd) FAST_FUNC;
uoff_t FAST_FUNC get_volume_size_in_bytes(int fd,
const char *override,
unsigned override_units,
int extend);
void xpipe(int filedes[2]) FAST_FUNC;
/* In this form code with pipes is much more readable */
struct fd_pair { int rd; int wr; };
#define piped_pair(pair) pipe(&((pair).rd))
#define xpiped_pair(pair) xpipe(&((pair).rd))
/* Useful for having small structure members/global variables */
typedef int8_t socktype_t;
typedef int8_t family_t;
struct BUG_too_small {
char BUG_socktype_t_too_small[(0
| SOCK_STREAM
| SOCK_DGRAM
| SOCK_RDM
| SOCK_SEQPACKET
| SOCK_RAW
) <= 127 ? 1 : -1];
char BUG_family_t_too_small[(0
| AF_UNSPEC
| AF_INET
| AF_INET6
| AF_UNIX
#ifdef AF_PACKET
| AF_PACKET
#endif
#ifdef AF_NETLINK
| AF_NETLINK
#endif
/* | AF_DECnet */
/* | AF_IPX */
) <= 127 ? 1 : -1];
};
void parse_datestr(const char *date_str, struct tm *ptm) FAST_FUNC;
time_t validate_tm_time(const char *date_str, struct tm *ptm) FAST_FUNC;
int xsocket(int domain, int type, int protocol) FAST_FUNC;
void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC;
void xlisten(int s, int backlog) FAST_FUNC;
void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC;
ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
socklen_t tolen) FAST_FUNC;
/* SO_REUSEADDR allows a server to rebind to an address that is already
* "in use" by old connections to e.g. previous server instance which is
* killed or crashed. Without it bind will fail until all such connections
* time out. Linux does not allow multiple live binds on same ip:port
* regardless of SO_REUSEADDR (unlike some other flavors of Unix).
* Turn it on before you call bind(). */
void setsockopt_reuseaddr(int fd) FAST_FUNC; /* On Linux this never fails. */
int setsockopt_broadcast(int fd) FAST_FUNC;
int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC;
/* NB: returns port in host byte order */
unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) FAST_FUNC;
typedef struct len_and_sockaddr {
socklen_t len;
union {
struct sockaddr sa;
struct sockaddr_in sin;
#if ENABLE_FEATURE_IPV6
struct sockaddr_in6 sin6;
#endif
} u;
} len_and_sockaddr;
enum {
LSA_LEN_SIZE = offsetof(len_and_sockaddr, u),
LSA_SIZEOF_SA = sizeof(
union {
struct sockaddr sa;
struct sockaddr_in sin;
#if ENABLE_FEATURE_IPV6
struct sockaddr_in6 sin6;
#endif
}
)
};
/* Create stream socket, and allocate suitable lsa.
* (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6))
* af == AF_UNSPEC will result in trying to create IPv6 socket,
* and if kernel doesn't support it, fall back to IPv4.
* This is useful if you plan to bind to resulting local lsa.
*/
int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC;
int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC;
/* Create server socket bound to bindaddr:port. bindaddr can be NULL,
* numeric IP ("N.N.N.N") or numeric IPv6 address,
* and can have ":PORT" suffix (for IPv6 use "[X:X:...:X]:PORT").
* Only if there is no suffix, port argument is used */
/* NB: these set SO_REUSEADDR before bind */
int create_and_bind_stream_or_die(const char *bindaddr, int port) FAST_FUNC;
int create_and_bind_dgram_or_die(const char *bindaddr, int port) FAST_FUNC;
/* Create client TCP socket connected to peer:port. Peer cannot be NULL.
* Peer can be numeric IP ("N.N.N.N"), numeric IPv6 address or hostname,
* and can have ":PORT" suffix (for IPv6 use "[X:X:...:X]:PORT").
* If there is no suffix, port argument is used */
int create_and_connect_stream_or_die(const char *peer, int port) FAST_FUNC;
/* Connect to peer identified by lsa */
int xconnect_stream(const len_and_sockaddr *lsa) FAST_FUNC;
/* Get local address of bound or accepted socket */
len_and_sockaddr *get_sock_lsa(int fd) FAST_FUNC RETURNS_MALLOC;
/* Get remote address of connected or accepted socket */
len_and_sockaddr *get_peer_lsa(int fd) FAST_FUNC RETURNS_MALLOC;
/* Return malloc'ed len_and_sockaddr with socket address of host:port
* Currently will return IPv4 or IPv6 sockaddrs only
* (depending on host), but in theory nothing prevents e.g.
* UNIX socket address being returned, IPX sockaddr etc...
* On error does bb_error_msg and returns NULL */
len_and_sockaddr* host2sockaddr(const char *host, int port) FAST_FUNC RETURNS_MALLOC;
/* Version which dies on error */
len_and_sockaddr* xhost2sockaddr(const char *host, int port) FAST_FUNC RETURNS_MALLOC;
len_and_sockaddr* xdotted2sockaddr(const char *host, int port) FAST_FUNC RETURNS_MALLOC;
/* Same, useful if you want to force family (e.g. IPv6) */
#if !ENABLE_FEATURE_IPV6
#define host_and_af2sockaddr(host, port, af) host2sockaddr((host), (port))
#define xhost_and_af2sockaddr(host, port, af) xhost2sockaddr((host), (port))
#else
len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af) FAST_FUNC RETURNS_MALLOC;
len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af) FAST_FUNC RETURNS_MALLOC;
#endif
/* Assign sin[6]_port member if the socket is an AF_INET[6] one,
* otherwise no-op. Useful for ftp.
* NB: does NOT do htons() internally, just direct assignment. */
void set_nport(struct sockaddr *sa, unsigned port) FAST_FUNC;
/* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */
int get_nport(const struct sockaddr *sa) FAST_FUNC;
/* Reverse DNS. Returns NULL on failure. */
char* xmalloc_sockaddr2host(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
/* This one doesn't append :PORTNUM */
char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
/* This one also doesn't fall back to dotted IP (returns NULL) */
char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
/* inet_[ap]ton on steroids */
char* xmalloc_sockaddr2dotted(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
// "old" (ipv4 only) API
// users: traceroute.c hostname.c - use _list_ of all IPs
struct hostent *xgethostbyname(const char *name) FAST_FUNC;
// Also mount.c and inetd.c are using gethostbyname(),
// + inet_common.c has additional IPv4-only stuff
void socket_want_pktinfo(int fd) FAST_FUNC;
ssize_t send_to_from(int fd, void *buf, size_t len, int flags,
const struct sockaddr *to,
const struct sockaddr *from,
socklen_t tolen) FAST_FUNC;
ssize_t recv_from_to(int fd, void *buf, size_t len, int flags,
struct sockaddr *from,
struct sockaddr *to,
socklen_t sa_size) FAST_FUNC;
uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC;
char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC;
char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC;
void overlapping_strcpy(char *dst, const char *src) FAST_FUNC;
char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC;
char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC;
/* Guaranteed to NOT be a macro (smallest code). Saves nearly 2k on uclibc.
* But potentially slow, don't use in one-billion-times loops */
int bb_putchar(int ch) FAST_FUNC;
/* Note: does not use stdio, writes to fd 2 directly */
int bb_putchar_stderr(char ch) FAST_FUNC;
char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) FAST_FUNC RETURNS_MALLOC;
// gcc-4.1.1 still isn't good enough at optimizing it
// (+200 bytes compared to macro)
//static ALWAYS_INLINE
//int LONE_DASH(const char *s) { return s[0] == '-' && !s[1]; }
//static ALWAYS_INLINE
//int NOT_LONE_DASH(const char *s) { return s[0] != '-' || s[1]; }
#define LONE_DASH(s) ((s)[0] == '-' && !(s)[1])
#define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
#define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
#define NOT_LONE_CHAR(s,c) ((s)[0] != (c) || (s)[1])
#define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
typedef struct uni_stat_t {
unsigned byte_count;
unsigned unicode_count;
unsigned unicode_width;
} uni_stat_t;
/* Returns a string with unprintable chars replaced by '?' or
* SUBST_WCHAR. This function is unicode-aware. */
const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str);
/* Prints unprintable char ch as ^C or M-c to file
* (M-c is used only if ch is ORed with PRINTABLE_META),
* else it is printed as-is (except for ch = 0x9b) */
enum { PRINTABLE_META = 0x100 };
void fputc_printable(int ch, FILE *file) FAST_FUNC;
/* dmalloc will redefine these to it's own implementation. It is safe
* to have the prototypes here unconditionally. */
void *malloc_or_warn(size_t size) FAST_FUNC RETURNS_MALLOC;
void *xmalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
void *xzalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
void *xrealloc(void *old, size_t size) FAST_FUNC;
/* After v = xrealloc_vector(v, SHIFT, idx) it's ok to use
* at least v[idx] and v[idx+1], for all idx values.
* SHIFT specifies how many new elements are added (1:2, 2:4, ..., 8:256...)
* when all elements are used up. New elements are zeroed out.
* xrealloc_vector(v, SHIFT, idx) *MUST* be called with consecutive IDXs -
* skipping an index is a bad bug - it may miss a realloc!
*/
#define xrealloc_vector(vector, shift, idx) \
xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx))
void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) FAST_FUNC;
extern ssize_t safe_read(int fd, void *buf, size_t count) FAST_FUNC;
extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) FAST_FUNC;
// NB: will return short read on error, not -1,
// if some data was read before error occurred
extern ssize_t full_read(int fd, void *buf, size_t count) FAST_FUNC;
extern void xread(int fd, void *buf, size_t count) FAST_FUNC;
extern unsigned char xread_char(int fd) FAST_FUNC;
extern ssize_t read_close(int fd, void *buf, size_t maxsz) FAST_FUNC;
extern ssize_t open_read_close(const char *filename, void *buf, size_t maxsz) FAST_FUNC;
// Reads one line a-la fgets (but doesn't save terminating '\n').
// Reads byte-by-byte. Useful when it is important to not read ahead.
// Bytes are appended to pfx (which must be malloced, or NULL).
extern char *xmalloc_reads(int fd, size_t *maxsz_p) FAST_FUNC;
/* Reads block up to *maxsz_p (default: INT_MAX - 4095) */
extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
/* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */
extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
/* Never returns NULL */
extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
#define SEAMLESS_COMPRESSION (0 \
|| ENABLE_FEATURE_SEAMLESS_XZ \
|| ENABLE_FEATURE_SEAMLESS_LZMA \
|| ENABLE_FEATURE_SEAMLESS_BZ2 \
|| ENABLE_FEATURE_SEAMLESS_GZ \
|| ENABLE_FEATURE_SEAMLESS_Z)
#if SEAMLESS_COMPRESSION
/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */
extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC;
/* Autodetects .gz etc */
extern int open_zipped(const char *fname) FAST_FUNC;
#else
# define setup_unzip_on_fd(...) (0)
# define open_zipped(fname) open((fname), O_RDONLY);
#endif
extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC;
// NB: will return short write on error, not -1,
// if some data was written before error occurred
extern ssize_t full_write(int fd, const void *buf, size_t count) FAST_FUNC;
extern void xwrite(int fd, const void *buf, size_t count) FAST_FUNC;
extern void xwrite_str(int fd, const char *str) FAST_FUNC;
extern ssize_t full_write1_str(const char *str) FAST_FUNC;
extern ssize_t full_write2_str(const char *str) FAST_FUNC;
extern void xopen_xwrite_close(const char* file, const char *str) FAST_FUNC;
/* Close fd, but check for failures (some types of write errors) */
extern void xclose(int fd) FAST_FUNC;
/* Reads and prints to stdout till eof, then closes FILE. Exits on error: */
extern void xprint_and_close_file(FILE *file) FAST_FUNC;
/* Reads a line from a text file, up to a newline or NUL byte, inclusive.
* Returns malloc'ed char*. If end is NULL '\n' isn't considered
* end of line. If end isn't NULL, length of the chunk is stored in it.
* Returns NULL if EOF/error.
*/
extern char *bb_get_chunk_from_file(FILE *file, int *end) FAST_FUNC;
/* Reads up to (and including) TERMINATING_STRING: */
extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string) FAST_FUNC RETURNS_MALLOC;
/* Same, with limited max size, and returns the length (excluding NUL): */
extern char *xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
/* Chops off TERMINATING_STRING from the end: */
extern char *xmalloc_fgetline_str(FILE *file, const char *terminating_string) FAST_FUNC RETURNS_MALLOC;
/* Reads up to (and including) "\n" or NUL byte: */
extern char *xmalloc_fgets(FILE *file) FAST_FUNC RETURNS_MALLOC;
/* Chops off '\n' from the end, unlike fgets: */
extern char *xmalloc_fgetline(FILE *file) FAST_FUNC RETURNS_MALLOC;
/* Same, but doesn't try to conserve space (may have some slack after the end) */
/* extern char *xmalloc_fgetline_fast(FILE *file) FAST_FUNC RETURNS_MALLOC; */
void die_if_ferror(FILE *file, const char *msg) FAST_FUNC;
void die_if_ferror_stdout(void) FAST_FUNC;
int fflush_all(void) FAST_FUNC;
void fflush_stdout_and_exit(int retval) NORETURN FAST_FUNC;
int fclose_if_not_stdin(FILE *file) FAST_FUNC;
FILE* xfopen(const char *filename, const char *mode) FAST_FUNC;
/* Prints warning to stderr and returns NULL on failure: */
FILE* fopen_or_warn(const char *filename, const char *mode) FAST_FUNC;
/* "Opens" stdin if filename is special, else just opens file: */
FILE* xfopen_stdin(const char *filename) FAST_FUNC;
FILE* fopen_or_warn_stdin(const char *filename) FAST_FUNC;
FILE* fopen_for_read(const char *path) FAST_FUNC;
FILE* xfopen_for_read(const char *path) FAST_FUNC;
FILE* fopen_for_write(const char *path) FAST_FUNC;
FILE* xfopen_for_write(const char *path) FAST_FUNC;
FILE* xfdopen_for_read(int fd) FAST_FUNC;
FILE* xfdopen_for_write(int fd) FAST_FUNC;
int bb_pstrcmp(const void *a, const void *b) /* not FAST_FUNC! */;
void qsort_string_vector(char **sv, unsigned count) FAST_FUNC;
/* Wrapper which restarts poll on EINTR or ENOMEM.
* On other errors complains [perror("poll")] and returns.
* Warning! May take (much) longer than timeout_ms to return!
* If this is a problem, use bare poll and open-code EINTR/ENOMEM handling */
int safe_poll(struct pollfd *ufds, nfds_t nfds, int timeout_ms) FAST_FUNC;
char *safe_gethostname(void) FAST_FUNC;
/* Convert each alpha char in str to lower-case */
char* str_tolower(char *str) FAST_FUNC;
char *utoa(unsigned n) FAST_FUNC;
char *itoa(int n) FAST_FUNC;
/* Returns a pointer past the formatted number, does NOT null-terminate */
char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC;
/* Intelligent formatters of bignums */
void smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC;
void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC;
/* If block_size == 0, display size without fractional part,
* else display (size * block_size) with one decimal digit.
* If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...),
* else divide by display_unit and do not use suffix. */
#define HUMAN_READABLE_MAX_WIDTH 7 /* "1024.0G" */
#define HUMAN_READABLE_MAX_WIDTH_STR "7"
//TODO: provide pointer to buf (avoid statics)?
const char *make_human_readable_str(unsigned long long size,
unsigned long block_size, unsigned long display_unit) FAST_FUNC;
/* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */
char *bin2hex(char *dst, const char *src, int count) FAST_FUNC;
/* Reverse */
char* hex2bin(char *dst, const char *src, int count) FAST_FUNC;
/* Generate a UUID */
void generate_uuid(uint8_t *buf) FAST_FUNC;
/* Last element is marked by mult == 0 */
struct suffix_mult {
char suffix[4];
unsigned mult;
};
#include "xatonum.h"
/* Specialized: */
/* Using xatoi() instead of naive atoi() is not always convenient -
* in many places people want *non-negative* values, but store them
* in signed int. Therefore we need this one:
* dies if input is not in [0, INT_MAX] range. Also will reject '-0' etc.
* It should really be named xatoi_nonnegative (since it allows 0),
* but that would be too long.
*/
int xatoi_positive(const char *numstr) FAST_FUNC;
/* Useful for reading port numbers */
uint16_t xatou16(const char *numstr) FAST_FUNC;
/* These parse entries in /etc/passwd and /etc/group. This is desirable
* for BusyBox since we want to avoid using the glibc NSS stuff, which
* increases target size and is often not needed on embedded systems. */
long xuname2uid(const char *name) FAST_FUNC;
long xgroup2gid(const char *name) FAST_FUNC;
/* wrapper: allows string to contain numeric uid or gid */
unsigned long get_ug_id(const char *s, long FAST_FUNC (*xname2id)(const char *)) FAST_FUNC;
/* from chpst. Does not die, returns 0 on failure */
struct bb_uidgid_t {
uid_t uid;
gid_t gid;
};
/* always sets uid and gid */
int get_uidgid(struct bb_uidgid_t*, const char*, int numeric_ok) FAST_FUNC;
/* always sets uid and gid, allows numeric; exits on failure */
void xget_uidgid(struct bb_uidgid_t*, const char*) FAST_FUNC;
/* chown-like handling of "user[:[group]" */
void parse_chown_usergroup_or_die(struct bb_uidgid_t *u, char *user_group) FAST_FUNC;
struct passwd* xgetpwnam(const char *name) FAST_FUNC;
struct group* xgetgrnam(const char *name) FAST_FUNC;
struct passwd* xgetpwuid(uid_t uid) FAST_FUNC;
struct group* xgetgrgid(gid_t gid) FAST_FUNC;
char* xuid2uname(uid_t uid) FAST_FUNC;
char* xgid2group(gid_t gid) FAST_FUNC;
char* uid2uname(uid_t uid) FAST_FUNC;
char* gid2group(gid_t gid) FAST_FUNC;
char* uid2uname_utoa(uid_t uid) FAST_FUNC;
char* gid2group_utoa(gid_t gid) FAST_FUNC;
/* versions which cache results (useful for ps, ls etc) */
const char* get_cached_username(uid_t uid) FAST_FUNC;
const char* get_cached_groupname(gid_t gid) FAST_FUNC;
void clear_username_cache(void) FAST_FUNC;
/* internally usernames are saved in fixed-sized char[] buffers */
enum { USERNAME_MAX_SIZE = 32 - sizeof(uid_t) };
#if ENABLE_FEATURE_CHECK_NAMES
void die_if_bad_username(const char* name) FAST_FUNC;
#else
#define die_if_bad_username(name) ((void)(name))
#endif
#if ENABLE_FEATURE_UTMP
void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname);
void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname);
#else
# define write_new_utmp(pid, new_type, tty_name, username, hostname) ((void)0)
# define update_utmp(pid, new_type, tty_name, username, hostname) ((void)0)
#endif
int execable_file(const char *name) FAST_FUNC;
char *find_execable(const char *filename, char **PATHp) FAST_FUNC;
int exists_execable(const char *filename) FAST_FUNC;
/* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff),
* but it may exec busybox and call applet instead of searching PATH.
*/
#if ENABLE_FEATURE_PREFER_APPLETS
int BB_EXECVP(const char *file, char *const argv[]) FAST_FUNC;
#define BB_EXECLP(prog,cmd,...) \
do { \
if (find_applet_by_name(prog) >= 0) \
execlp(bb_busybox_exec_path, cmd, __VA_ARGS__); \
execlp(prog, cmd, __VA_ARGS__); \
} while (0)
#else
#define BB_EXECVP(prog,cmd) execvp(prog,cmd)
#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__)
#endif
int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
/* xvfork() can't be a _function_, return after vfork mangles stack
* in the parent. It must be a macro. */
#define xvfork() \
({ \
pid_t bb__xvfork_pid = vfork(); \
if (bb__xvfork_pid < 0) \
bb_perror_msg_and_die("vfork"); \
bb__xvfork_pid; \
})
#if BB_MMU
pid_t xfork(void) FAST_FUNC;
#endif
/* NOMMU friendy fork+exec: */
pid_t spawn(char **argv) FAST_FUNC;
pid_t xspawn(char **argv) FAST_FUNC;
pid_t safe_waitpid(pid_t pid, int *wstat, int options) FAST_FUNC;
pid_t wait_any_nohang(int *wstat) FAST_FUNC;
/* wait4pid: unlike waitpid, waits ONLY for one process.
* Returns sig + 0x180 if child is killed by signal.
* It's safe to pass negative 'pids' from failed [v]fork -
* wait4pid will return -1 (and will not clobber [v]fork's errno).
* IOW: rc = wait4pid(spawn(argv));
* if (rc < 0) bb_perror_msg("%s", argv[0]);
* if (rc > 0) bb_error_msg("exit code: %d", rc & 0xff);
*/
int wait4pid(pid_t pid) FAST_FUNC;
/* Same as wait4pid(spawn(argv)), but with NOFORK/NOEXEC if configured: */
int spawn_and_wait(char **argv) FAST_FUNC;
/* Does NOT check that applet is NOFORK, just blindly runs it */
int run_nofork_applet(int applet_no, char **argv) FAST_FUNC;
/* Helpers for daemonization.
*
* bb_daemonize(flags) = daemonize, does not compile on NOMMU
*
* bb_daemonize_or_rexec(flags, argv) = daemonizes on MMU (and ignores argv),
* rexec's itself on NOMMU with argv passed as command line.
* Thus bb_daemonize_or_rexec may cause your <applet>_main() to be re-executed
* from the start. (It will detect it and not reexec again second time).
* You have to audit carefully that you don't do something twice as a result
* (opening files/sockets, parsing config files etc...)!
*
* Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty
* (will do setsid()).
*
* fork_or_rexec(argv) = bare-bones fork on MMU,
* "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid().
* On MMU ignores argv.
*
* Helper for network daemons in foreground mode:
*
* bb_sanitize_stdio() = make sure that fd 0,1,2 are opened by opening them
* to /dev/null if they are not.
*/
enum {
DAEMON_CHDIR_ROOT = 1,
DAEMON_DEVNULL_STDIO = 2,
DAEMON_CLOSE_EXTRA_FDS = 4,
DAEMON_ONLY_SANITIZE = 8, /* internal use */
DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */
};
#if BB_MMU
enum { re_execed = 0 };
# define fork_or_rexec(argv) xfork()
# define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags)
# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
#else
extern bool re_execed;
/* Note: re_exec() and fork_or_rexec() do argv[0][0] |= 0x80 on NOMMU!
* _Parent_ needs to undo it if it doesn't want to have argv[0] mangled.
*/
void re_exec(char **argv) NORETURN FAST_FUNC;
pid_t fork_or_rexec(char **argv) FAST_FUNC;
int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC;
int BUG_daemon_is_unavailable_on_nommu(void) FAST_FUNC;
void BUG_bb_daemonize_is_unavailable_on_nommu(void) FAST_FUNC;
# define fork() BUG_fork_is_unavailable_on_nommu()