aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Config.in29
-rw-r--r--libbb/Kbuild117
-rw-r--r--libbb/README11
-rw-r--r--libbb/ask_confirmation.c36
-rw-r--r--libbb/bb_askpass.c75
-rw-r--r--libbb/bb_do_delay.c24
-rw-r--r--libbb/bb_pwd.c130
-rw-r--r--libbb/bb_strtonum.c155
-rw-r--r--libbb/change_identity.c51
-rw-r--r--libbb/chomp.c19
-rw-r--r--libbb/compare_string_array.c37
-rw-r--r--libbb/concat_path_file.c27
-rw-r--r--libbb/concat_subpath_file.c23
-rw-r--r--libbb/copy_file.c282
-rw-r--r--libbb/copyfd.c86
-rw-r--r--libbb/correct_password.c65
-rw-r--r--libbb/crc32.c39
-rw-r--r--libbb/create_icmp6_socket.c39
-rw-r--r--libbb/create_icmp_socket.c37
-rw-r--r--libbb/default_error_retval.c19
-rw-r--r--libbb/device_open.c33
-rw-r--r--libbb/dump.c803
-rw-r--r--libbb/error_msg.c23
-rw-r--r--libbb/error_msg_and_die.c28
-rw-r--r--libbb/execable.c61
-rw-r--r--libbb/fclose_nonstdin.c23
-rw-r--r--libbb/fflush_stdout_and_exit.c24
-rw-r--r--libbb/fgets_str.c53
-rw-r--r--libbb/find_mount_point.c53
-rw-r--r--libbb/find_pid_by_name.c55
-rw-r--r--libbb/find_root_device.c33
-rw-r--r--libbb/full_write.c38
-rw-r--r--libbb/get_console.c77
-rw-r--r--libbb/get_last_path_component.c32
-rw-r--r--libbb/get_line_from_file.c68
-rw-r--r--libbb/getopt32.c529
-rw-r--r--libbb/herror_msg.c22
-rw-r--r--libbb/herror_msg_and_die.c25
-rw-r--r--libbb/human_readable.c89
-rw-r--r--libbb/inet_common.c235
-rw-r--r--libbb/info_msg.c23
-rw-r--r--libbb/inode_hash.c88
-rw-r--r--libbb/isdirectory.c39
-rw-r--r--libbb/kernel_version.c37
-rw-r--r--libbb/last_char_is.c24
-rw-r--r--libbb/llist.c78
-rw-r--r--libbb/login.c105
-rw-r--r--libbb/loop.c149
-rw-r--r--libbb/make_directory.c104
-rw-r--r--libbb/makedev.c20
-rw-r--r--libbb/md5.c450
-rw-r--r--libbb/messages.c53
-rw-r--r--libbb/mode_string.c128
-rw-r--r--libbb/mtab.c52
-rw-r--r--libbb/mtab_file.c17
-rw-r--r--libbb/obscure.c170
-rw-r--r--libbb/parse_mode.c164
-rw-r--r--libbb/perror_msg.c23
-rw-r--r--libbb/perror_msg_and_die.c26
-rw-r--r--libbb/perror_nomsg.c16
-rw-r--r--libbb/perror_nomsg_and_die.c17
-rw-r--r--libbb/process_escape_sequence.c89
-rw-r--r--libbb/procps.c255
-rw-r--r--libbb/pw_encrypt.c29
-rw-r--r--libbb/read.c134
-rw-r--r--libbb/recursive_action.c126
-rw-r--r--libbb/remove_file.c111
-rw-r--r--libbb/restricted_shell.c57
-rw-r--r--libbb/run_shell.c101
-rw-r--r--libbb/safe_strncpy.c21
-rw-r--r--libbb/safe_write.c26
-rw-r--r--libbb/setup_environment.c83
-rw-r--r--libbb/sha1.c178
-rw-r--r--libbb/simplify_path.c50
-rw-r--r--libbb/skip_whitespace.c18
-rw-r--r--libbb/speed_table.c117
-rw-r--r--libbb/trim.c31
-rw-r--r--libbb/u_signal_names.c58
-rw-r--r--libbb/uuencode.c63
-rw-r--r--libbb/vdprintf.c25
-rw-r--r--libbb/verror_msg.c46
-rw-r--r--libbb/vfork_daemon_rexec.c67
-rw-r--r--libbb/vherror_msg.c15
-rw-r--r--libbb/vinfo_msg.c26
-rw-r--r--libbb/vperror_msg.c15
-rw-r--r--libbb/warn_ignoring_args.c17
-rw-r--r--libbb/wfopen.c20
-rw-r--r--libbb/wfopen_input.c31
-rw-r--r--libbb/xatonum.c69
-rw-r--r--libbb/xatonum_template.c185
-rw-r--r--libbb/xconnect.c153
-rw-r--r--libbb/xfuncs.c521
-rw-r--r--libbb/xgetcwd.c44
-rw-r--r--libbb/xgethostbyname.c19
-rw-r--r--libbb/xgethostbyname2.c22
-rw-r--r--libbb/xreadlink.c38
-rw-r--r--libbb/xregcomp.c26
97 files changed, 8274 insertions, 0 deletions
diff --git a/libbb/Config.in b/libbb/Config.in
new file mode 100644
index 000000000..92ee55cbc
--- /dev/null
+++ b/libbb/Config.in
@@ -0,0 +1,29 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Busybox Library Tuning"
7
8config PASSWORD_MINLEN
9 int "Minimum password length"
10 default 6
11 range 5 32
12 help
13 Minimum allowable password length.
14
15config MD5_SIZE_VS_SPEED
16 int " MD5: Trade Bytes for Speed"
17 default 2
18 range 0 3
19 help
20 Trade binary size versus speed for the md5sum algorithm.
21 Approximate values running uClibc and hashing
22 linux-2.4.4.tar.bz2 were:
23 user times (sec) text size (386)
24 0 (fastest) 1.1 6144
25 1 1.4 5392
26 2 3.0 5088
27 3 (smallest) 5.1 4912
28
29endmenu
diff --git a/libbb/Kbuild b/libbb/Kbuild
new file mode 100644
index 000000000..c15615302
--- /dev/null
+++ b/libbb/Kbuild
@@ -0,0 +1,117 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7lib-y:=
8
9lib-y += ask_confirmation.o
10lib-y += bb_askpass.o
11lib-y += bb_do_delay.o
12lib-y += bb_pwd.o
13lib-y += bb_strtonum.o
14lib-y += change_identity.o
15lib-y += chomp.o
16lib-y += compare_string_array.o
17lib-y += concat_path_file.o
18lib-y += concat_subpath_file.o
19lib-y += copy_file.o
20lib-y += copyfd.o
21lib-y += crc32.o
22lib-y += create_icmp6_socket.o
23lib-y += create_icmp_socket.o
24lib-y += default_error_retval.o
25lib-y += device_open.o
26lib-y += dump.o
27lib-y += error_msg.o
28lib-y += error_msg_and_die.o
29lib-y += execable.o
30lib-y += fclose_nonstdin.o
31lib-y += fflush_stdout_and_exit.o
32lib-y += fgets_str.o
33lib-y += find_pid_by_name.o
34lib-y += find_root_device.o
35lib-y += full_write.o
36lib-y += get_console.o
37lib-y += get_last_path_component.o
38lib-y += get_line_from_file.o
39lib-y += getopt32.o
40lib-y += herror_msg.o
41lib-y += herror_msg_and_die.o
42lib-y += human_readable.o
43lib-y += inet_common.o
44lib-y += info_msg.o
45lib-y += inode_hash.o
46lib-y += isdirectory.o
47lib-y += kernel_version.o
48lib-y += last_char_is.o
49lib-y += llist.o
50lib-y += login.o
51lib-y += make_directory.o
52lib-y += makedev.o
53lib-y += md5.o
54lib-y += messages.o
55lib-y += mode_string.o
56lib-y += mtab_file.o
57lib-y += obscure.o
58lib-y += parse_mode.o
59lib-y += perror_msg.o
60lib-y += perror_msg_and_die.o
61lib-y += perror_nomsg.o
62lib-y += perror_nomsg_and_die.o
63lib-y += process_escape_sequence.o
64lib-y += procps.o
65lib-y += read.o
66lib-y += recursive_action.o
67lib-y += remove_file.o
68lib-y += restricted_shell.o
69lib-y += run_shell.o
70lib-y += safe_strncpy.o
71lib-y += safe_write.o
72lib-y += setup_environment.o
73lib-y += sha1.o
74lib-y += simplify_path.o
75lib-y += skip_whitespace.o
76lib-y += speed_table.o
77lib-y += trim.o
78lib-y += u_signal_names.o
79lib-y += uuencode.o
80lib-y += vdprintf.o
81lib-y += verror_msg.o
82lib-y += vfork_daemon_rexec.o
83lib-y += vherror_msg.o
84lib-y += vinfo_msg.o
85lib-y += vperror_msg.o
86lib-y += warn_ignoring_args.o
87lib-y += wfopen.o
88lib-y += wfopen_input.o
89lib-y += xatonum.o
90lib-y += xconnect.o
91lib-y += xfuncs.o
92lib-y += xgetcwd.o
93lib-y += xgethostbyname.o
94lib-y += xgethostbyname2.o
95lib-y += xreadlink.o
96
97# conditionally compiled objects:
98lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o
99lib-$(CONFIG_LOSETUP) += loop.o
100lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
101lib-$(CONFIG_PASSWD) += pw_encrypt.o
102lib-$(CONFIG_SULOGIN) += pw_encrypt.o
103lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o
104lib-$(CONFIG_VLOCK) += correct_password.o
105lib-$(CONFIG_SU) += correct_password.o
106lib-$(CONFIG_LOGIN) += correct_password.o
107lib-$(CONFIG_DF) += find_mount_point.o
108lib-$(CONFIG_EJECT) += find_mount_point.o
109
110# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
111# require regex.h to be in the include dir even if we don't need it thereby
112# allowing us to build busybox even if uclibc regex support is disabled.
113
114lib-$(CONFIG_AWK) += xregcomp.o
115lib-$(CONFIG_SED) += xregcomp.o
116lib-$(CONFIG_LESS) += xregcomp.o
117lib-$(CONFIG_DEVFSD) += xregcomp.o
diff --git a/libbb/README b/libbb/README
new file mode 100644
index 000000000..4f28f7e34
--- /dev/null
+++ b/libbb/README
@@ -0,0 +1,11 @@
1Please see the LICENSE file for copyright information (GPLv2)
2
3libbb is BusyBox's utility library. All of this stuff used to be stuffed into
4a single file named utility.c. When I split utility.c to create libbb, some of
5the very oldest stuff ended up without their original copyright and licensing
6information (which is now lost in the mists of time). If you see something
7that you wrote that is mis-attributed, do let me know so we can fix that up.
8
9 Erik Andersen
10 <andersen@codepoet.org>
11
diff --git a/libbb/ask_confirmation.c b/libbb/ask_confirmation.c
new file mode 100644
index 000000000..4642fa036
--- /dev/null
+++ b/libbb/ask_confirmation.c
@@ -0,0 +1,36 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bb_ask_confirmation implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* Read a line from stdin. If the first non-whitespace char is 'y' or 'Y',
11 * return 1. Otherwise return 0.
12 */
13
14#include <stdio.h>
15#include <ctype.h>
16#include "libbb.h"
17
18int bb_ask_confirmation(void)
19{
20 int retval = 0;
21 int first = 1;
22 int c;
23
24 while (((c = getchar()) != EOF) && (c != '\n')) {
25 /* Make sure we get the actual function call for isspace,
26 * as speed is not critical here. */
27 if (first && !(isspace)(c)) {
28 --first;
29 if ((c == 'y') || (c == 'Y')) {
30 ++retval;
31 }
32 }
33 }
34
35 return retval;
36}
diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c
new file mode 100644
index 000000000..097a0a290
--- /dev/null
+++ b/libbb/bb_askpass.c
@@ -0,0 +1,75 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Ask for a password
4 * I use a static buffer in this function. Plan accordingly.
5 *
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include <stdio.h>
12#include <string.h>
13#include <unistd.h>
14#include <fcntl.h>
15#include <signal.h>
16#include <termios.h>
17#include <sys/ioctl.h>
18
19#include "libbb.h"
20
21/* do nothing signal handler */
22static void askpass_timeout(int ATTRIBUTE_UNUSED ignore)
23{
24}
25
26char *bb_askpass(int timeout, const char * prompt)
27{
28 static char passwd[64];
29
30 char *ret;
31 int i;
32 struct sigaction sa;
33 struct termios old, new;
34
35 tcgetattr(STDIN_FILENO, &old);
36 tcflush(STDIN_FILENO, TCIFLUSH);
37
38 memset(passwd, 0, sizeof(passwd));
39
40 fputs(prompt, stdout);
41 fflush(stdout);
42
43 tcgetattr(STDIN_FILENO, &new);
44 new.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
45 new.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
46 tcsetattr(STDIN_FILENO, TCSANOW, &new);
47
48 if (timeout) {
49 sa.sa_flags = 0;
50 sa.sa_handler = askpass_timeout;
51 sigaction(SIGALRM, &sa, NULL);
52 alarm(timeout);
53 }
54
55 ret = NULL;
56 if (read(STDIN_FILENO, passwd, sizeof(passwd)-1) > 0) {
57 ret = passwd;
58 i = 0;
59 /* Last byte is guaranteed to be 0
60 (read did not overwrite it) */
61 do {
62 if (passwd[i] == '\r' || passwd[i] == '\n')
63 passwd[i] = '\0';
64 } while (passwd[i++]);
65 }
66
67 if (timeout) {
68 alarm(0);
69 }
70
71 tcsetattr(STDIN_FILENO, TCSANOW, &old);
72 puts("");
73 fflush(stdout);
74 return ret;
75}
diff --git a/libbb/bb_do_delay.c b/libbb/bb_do_delay.c
new file mode 100644
index 000000000..e14b67a19
--- /dev/null
+++ b/libbb/bb_do_delay.c
@@ -0,0 +1,24 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Busybox utility routines.
4 *
5 * Copyright (C) 2005 by Tito Ragusa <tito-wolit@tiscali.it>
6 *
7 * Licensed under the GPL v2, see the file LICENSE in this tarball.
8 */
9
10#include <time.h>
11#include <unistd.h>
12#include "libbb.h"
13
14void bb_do_delay(int seconds)
15{
16 time_t start, now;
17
18 time(&start);
19 now = start;
20 while (difftime(now, start) < seconds) {
21 sleep(seconds);
22 time(&now);
23 }
24}
diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c
new file mode 100644
index 000000000..b5125b0f4
--- /dev/null
+++ b/libbb/bb_pwd.c
@@ -0,0 +1,130 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * password utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8 */
9
10#include <stdio.h>
11#include <string.h>
12#include <assert.h>
13#include "libbb.h"
14
15 /*
16 * if bufsize is > 0 char *buffer cannot be set to NULL.
17 * If idname is not NULL it is written on the static
18 * allocated buffer (and a pointer to it is returned).
19 * if idname is NULL, id as string is written to the static
20 * allocated buffer and NULL is returned.
21 * if bufsize is = 0 char *buffer can be set to NULL.
22 * If idname exists a pointer to it is returned,
23 * else NULL is returned.
24 * if bufsize is < 0 char *buffer can be set to NULL.
25 * If idname exists a pointer to it is returned,
26 * else an error message is printed and the program exits.
27 */
28
29/* internal function for bb_getpwuid and bb_getgrgid */
30static char * bb_getug(char *buffer, char *idname, long id, int bufsize, char prefix)
31{
32 if (bufsize > 0 ) {
33 assert(buffer!=NULL);
34 if(idname) {
35 return safe_strncpy(buffer, idname, bufsize);
36 }
37 snprintf(buffer, bufsize, "%ld", id);
38 } else if (bufsize < 0 && !idname) {
39 bb_error_msg_and_die("unknown %cid %ld", prefix, id);
40 }
41 return idname;
42}
43
44 /* Hacked by Tito Ragusa (c) 2004 <farmatito@tiscali.it> to make it more
45 * flexible :
46 *
47 * if bufsize is > 0 char *group cannot be set to NULL.
48 * On success groupname is written on static allocated buffer
49 * group (and a pointer to it is returned).
50 * On failure gid as string is written to static allocated
51 * buffer group and NULL is returned.
52 * if bufsize is = 0 char *group can be set to NULL.
53 * On success groupname is returned.
54 * On failure NULL is returned.
55 * if bufsize is < 0 char *group can be set to NULL.
56 * On success groupname is returned.
57 * On failure an error message is printed and
58 * the program exits.
59 */
60
61/* gets a groupname given a gid */
62char * bb_getgrgid(char *group, long gid, int bufsize)
63{
64 struct group *mygroup = getgrgid(gid);
65
66 return bb_getug(group, (mygroup) ?
67 mygroup->gr_name : (char *)mygroup, gid, bufsize, 'g');
68}
69
70/* returns a gid given a group name */
71long bb_xgetgrnam(const char *name)
72{
73 struct group *mygroup;
74
75 mygroup = getgrnam(name);
76 if (mygroup==NULL)
77 bb_error_msg_and_die("unknown group name: %s", name);
78
79 return mygroup->gr_gid;
80}
81
82/* returns a uid given a username */
83long bb_xgetpwnam(const char *name)
84{
85 struct passwd *myuser;
86
87 myuser = getpwnam(name);
88 if (myuser==NULL)
89 bb_error_msg_and_die("unknown user name: %s", name);
90
91 return myuser->pw_uid;
92}
93
94 /* Hacked by Tito Ragusa (c) 2004 <farmatito@tiscali.it> to make it more
95 * flexible :
96 *
97 * if bufsize is > 0 char *name cannot be set to NULL.
98 * On success username is written on the static allocated
99 * buffer name (and a pointer to it is returned).
100 * On failure uid as string is written to the static
101 * allocated buffer name and NULL is returned.
102 * if bufsize is = 0 char *name can be set to NULL.
103 * On success username is returned.
104 * On failure NULL is returned.
105 * if bufsize is < 0 char *name can be set to NULL
106 * On success username is returned.
107 * On failure an error message is printed and
108 * the program exits.
109 */
110
111/* gets a username given a uid */
112char * bb_getpwuid(char *name, long uid, int bufsize)
113{
114 struct passwd *myuser = getpwuid(uid);
115
116 return bb_getug(name, myuser ? myuser->pw_name : (char *)myuser,
117 uid, bufsize, 'u');
118}
119
120unsigned long get_ug_id(const char *s,
121 long (*__bb_getxxnam)(const char *))
122{
123 unsigned long r;
124
125 r = bb_strtoul(s, NULL, 10);
126 if (errno)
127 r = __bb_getxxnam(s);
128
129 return r;
130}
diff --git a/libbb/bb_strtonum.c b/libbb/bb_strtonum.c
new file mode 100644
index 000000000..6fbd1f87d
--- /dev/null
+++ b/libbb/bb_strtonum.c
@@ -0,0 +1,155 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12/* On exit: errno = 0 only if there was non-empty, '\0' terminated value
13 * errno = EINVAL if value was not '\0' terminated, but othervise ok
14 * Return value is still valid, caller should just check whether end[0]
15 * is a valid terminating char for particular case. OTOH, if caller
16 * requires '\0' terminated input, [s]he can just check errno == 0.
17 * errno = ERANGE if value had alphanumeric terminating char ("1234abcg").
18 * errno = ERANGE if value is out of range, missing, etc.
19 * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
20 */
21
22static unsigned long long ret_ERANGE(void)
23{
24 errno = ERANGE; /* this ain't as small as it looks (on glibc) */
25 return ULLONG_MAX;
26}
27
28static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr)
29{
30 if (endp) *endp = endptr;
31
32 /* Check for the weird "feature":
33 * a "-" string is apparently a valid "number" for strto[u]l[l]!
34 * It returns zero and errno is 0! :( */
35 if (endptr[-1] == '-')
36 return ret_ERANGE();
37
38 /* errno is already set to ERANGE by strtoXXX if value overflowed */
39 if (endptr[0]) {
40 /* "1234abcg" or out-of-range? */
41 if (isalnum(endptr[0]) || errno)
42 return ret_ERANGE();
43 /* good number, just suspicious terminator */
44 errno = EINVAL;
45 }
46 return v;
47}
48
49
50unsigned long long bb_strtoull(const char *arg, char **endp, int base)
51{
52 unsigned long long v;
53 char *endptr;
54
55 /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */
56 /* I don't think that this is right. Preventing this... */
57 if (!isalnum(arg[0])) return ret_ERANGE();
58
59 /* not 100% correct for lib func, but convenient for the caller */
60 errno = 0;
61 v = strtoull(arg, &endptr, base);
62 return handle_errors(v, endp, endptr);
63}
64
65long long bb_strtoll(const char *arg, char **endp, int base)
66{
67 unsigned long long v;
68 char *endptr;
69
70 if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
71 errno = 0;
72 v = strtoll(arg, &endptr, base);
73 return handle_errors(v, endp, endptr);
74}
75
76#if ULONG_MAX != ULLONG_MAX
77unsigned long bb_strtoul(const char *arg, char **endp, int base)
78{
79 unsigned long v;
80 char *endptr;
81
82 if (!isalnum(arg[0])) return ret_ERANGE();
83 errno = 0;
84 v = strtoul(arg, &endptr, base);
85 return handle_errors(v, endp, endptr);
86}
87
88long bb_strtol(const char *arg, char **endp, int base)
89{
90 long v;
91 char *endptr;
92
93 if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
94 errno = 0;
95 v = strtol(arg, &endptr, base);
96 return handle_errors(v, endp, endptr);
97}
98#endif
99
100#if UINT_MAX != ULONG_MAX
101unsigned bb_strtou(const char *arg, char **endp, int base)
102{
103 unsigned long v;
104 char *endptr;
105
106 if (!isalnum(arg[0])) return ret_ERANGE();
107 errno = 0;
108 v = strtoul(arg, &endptr, base);
109 if (v > UINT_MAX) return ret_ERANGE();
110 return handle_errors(v, endp, endptr);
111}
112
113int bb_strtoi(const char *arg, char **endp, int base)
114{
115 long v;
116 char *endptr;
117
118 if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
119 errno = 0;
120 v = strtol(arg, &endptr, base);
121 if (v > INT_MAX) return ret_ERANGE();
122 if (v < INT_MIN) return ret_ERANGE();
123 return handle_errors(v, endp, endptr);
124}
125#endif
126
127/* Floating point */
128
129#if 0
130
131#include <math.h> /* just for HUGE_VAL */
132#define NOT_DIGIT(a) (((unsigned char)(a-'0')) > 9)
133double bb_strtod(const char *arg, char **endp)
134{
135 double v;
136 char *endptr;
137
138 if (arg[0] != '-' && NOT_DIGIT(arg[0])) goto err;
139 errno = 0;
140 v = strtod(arg, &endptr);
141 if (endp) *endp = endptr;
142 if (endptr[0]) {
143 /* "1234abcg" or out-of-range? */
144 if (isalnum(endptr[0]) || errno) {
145 err:
146 errno = ERANGE;
147 return HUGE_VAL;
148 }
149 /* good number, just suspicious terminator */
150 errno = EINVAL;
151 }
152 return v;
153}
154
155#endif
diff --git a/libbb/change_identity.c b/libbb/change_identity.c
new file mode 100644
index 000000000..3f888f523
--- /dev/null
+++ b/libbb/change_identity.c
@@ -0,0 +1,51 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include "libbb.h"
32
33
34/* Become the user and group(s) specified by PW. */
35const char *change_identity_e2str(const struct passwd *pw)
36{
37 if (initgroups(pw->pw_name, pw->pw_gid) == -1)
38 return "cannot set groups";
39 endgrent(); /* ?? */
40 xsetgid(pw->pw_gid);
41 xsetuid(pw->pw_uid);
42 return NULL;
43}
44
45void change_identity(const struct passwd *pw)
46{
47 const char *err_msg = change_identity_e2str(pw);
48
49 if (err_msg)
50 bb_perror_msg_and_die("%s", err_msg);
51}
diff --git a/libbb/chomp.c b/libbb/chomp.c
new file mode 100644
index 000000000..eab770760
--- /dev/null
+++ b/libbb/chomp.c
@@ -0,0 +1,19 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people.
6 * If you wrote this, please acknowledge your work.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include "libbb.h"
12
13void chomp(char *s)
14{
15 char *lc = last_char_is(s, '\n');
16
17 if (lc)
18 *lc = 0;
19}
diff --git a/libbb/compare_string_array.c b/libbb/compare_string_array.c
new file mode 100644
index 000000000..d15578ca3
--- /dev/null
+++ b/libbb/compare_string_array.c
@@ -0,0 +1,37 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
4 */
5
6#include "libbb.h"
7
8/* returns the array index of the string */
9/* (index of first match is returned, or -1) */
10int index_in_str_array(const char * const string_array[], const char *key)
11{
12 int i;
13
14 for (i = 0; string_array[i] != 0; i++) {
15 if (strcmp(string_array[i], key) == 0) {
16 return i;
17 }
18 }
19 return -1;
20}
21
22/* returns the array index of the string, even if it matches only a beginning */
23/* (index of first match is returned, or -1) */
24int index_in_substr_array(const char * const string_array[], const char *key)
25{
26 int i;
27 int len = strlen(key);
28 if (!len)
29 return -1;
30
31 for (i = 0; string_array[i] != 0; i++) {
32 if (strncmp(string_array[i], key, len) == 0) {
33 return i;
34 }
35 }
36 return -1;
37}
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
new file mode 100644
index 000000000..9aae601a4
--- /dev/null
+++ b/libbb/concat_path_file.c
@@ -0,0 +1,27 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people.
6 * If you wrote this, please acknowledge your work.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11/* concatenate path and file name to new allocation buffer,
12 * not adding '/' if path name already has '/'
13*/
14
15#include "libbb.h"
16
17char *concat_path_file(const char *path, const char *filename)
18{
19 char *lc;
20
21 if (!path)
22 path = "";
23 lc = last_char_is(path, '/');
24 while (*filename == '/')
25 filename++;
26 return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
27}
diff --git a/libbb/concat_subpath_file.c b/libbb/concat_subpath_file.c
new file mode 100644
index 000000000..6ebc01bf5
--- /dev/null
+++ b/libbb/concat_subpath_file.c
@@ -0,0 +1,23 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/*
11 This function make special for recursive actions with usage
12 concat_path_file(path, filename)
13 and skiping "." and ".." directory entries
14*/
15
16#include "libbb.h"
17
18char *concat_subpath_file(const char *path, const char *f)
19{
20 if(f && *f == '.' && (!f[1] || (f[1] == '.' && !f[2])))
21 return NULL;
22 return concat_path_file(path, f);
23}
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
new file mode 100644
index 000000000..0135831fe
--- /dev/null
+++ b/libbb/copy_file.c
@@ -0,0 +1,282 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini copy_file implementation for busybox
4 *
5 * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 *
9 */
10
11#include "libbb.h"
12
13static int retry_overwrite(const char *dest, int flags)
14{
15 if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
16 fprintf(stderr, "'%s' exists\n", dest);
17 return -1;
18 }
19 if (flags & FILEUTILS_INTERACTIVE) {
20 fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
21 if (!bb_ask_confirmation())
22 return 0; // not allowed to overwrite
23 }
24 if (unlink(dest) < 0) {
25 bb_perror_msg("cannot remove '%s'", dest);
26 return -1; // error
27 }
28 return 1; // ok (to try again)
29}
30
31int copy_file(const char *source, const char *dest, int flags)
32{
33 struct stat source_stat;
34 struct stat dest_stat;
35 int status = 0;
36 signed char dest_exists = 0;
37 signed char ovr;
38
39#define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE)
40
41 if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
42 // This may be a dangling symlink.
43 // Making [sym]links to dangling symlinks works, so...
44 if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
45 goto make_links;
46 bb_perror_msg("cannot stat '%s'", source);
47 return -1;
48 }
49
50 if (lstat(dest, &dest_stat) < 0) {
51 if (errno != ENOENT) {
52 bb_perror_msg("cannot stat '%s'", dest);
53 return -1;
54 }
55 } else {
56 if (source_stat.st_dev == dest_stat.st_dev
57 && source_stat.st_ino == dest_stat.st_ino
58 ) {
59 bb_error_msg("'%s' and '%s' are the same file", source, dest);
60 return -1;
61 }
62 dest_exists = 1;
63 }
64
65 if (S_ISDIR(source_stat.st_mode)) {
66 DIR *dp;
67 struct dirent *d;
68 mode_t saved_umask = 0;
69
70 if (!(flags & FILEUTILS_RECUR)) {
71 bb_error_msg("omitting directory '%s'", source);
72 return -1;
73 }
74
75 /* Create DEST. */
76 if (dest_exists) {
77 if (!S_ISDIR(dest_stat.st_mode)) {
78 bb_error_msg("target '%s' is not a directory", dest);
79 return -1;
80 }
81 } else {
82 mode_t mode;
83 saved_umask = umask(0);
84
85 mode = source_stat.st_mode;
86 if (!(flags & FILEUTILS_PRESERVE_STATUS))
87 mode = source_stat.st_mode & ~saved_umask;
88 mode |= S_IRWXU;
89
90 if (mkdir(dest, mode) < 0) {
91 umask(saved_umask);
92 bb_perror_msg("cannot create directory '%s'", dest);
93 return -1;
94 }
95
96 umask(saved_umask);
97 }
98
99 /* Recursively copy files in SOURCE. */
100 dp = opendir(source);
101 if (dp == NULL) {
102 status = -1;
103 goto preserve_status;
104 }
105
106 while ((d = readdir(dp)) != NULL) {
107 char *new_source, *new_dest;
108
109 new_source = concat_subpath_file(source, d->d_name);
110 if (new_source == NULL)
111 continue;
112 new_dest = concat_path_file(dest, d->d_name);
113 if (copy_file(new_source, new_dest, flags) < 0)
114 status = -1;
115 free(new_source);
116 free(new_dest);
117 }
118 closedir(dp);
119
120 if (!dest_exists
121 && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
122 ) {
123 bb_perror_msg("cannot change permissions of '%s'", dest);
124 status = -1;
125 }
126
127 } else if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
128 int (*lf)(const char *oldpath, const char *newpath);
129 make_links:
130 // Hmm... maybe
131 // if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
132 // (but realpath returns NULL on dangling symlinks...)
133 lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
134 if (lf(source, dest) < 0) {
135 ovr = retry_overwrite(dest, flags);
136 if (ovr <= 0)
137 return ovr;
138 if (lf(source, dest) < 0) {
139 bb_perror_msg("cannot create link '%s'", dest);
140 return -1;
141 }
142 }
143 return 0;
144
145 } else if (S_ISREG(source_stat.st_mode)
146 // Huh? DEREF uses stat, which never returns links IIRC...
147 || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode))
148 ) {
149 int src_fd;
150 int dst_fd;
151 if (ENABLE_FEATURE_PRESERVE_HARDLINKS) {
152 char *link_name;
153
154 if (!FLAGS_DEREF
155 && is_in_ino_dev_hashtable(&source_stat, &link_name)
156 ) {
157 if (link(link_name, dest) < 0) {
158 ovr = retry_overwrite(dest, flags);
159 if (ovr <= 0)
160 return ovr;
161 if (link(link_name, dest) < 0) {
162 bb_perror_msg("cannot create link '%s'", dest);
163 return -1;
164 }
165 }
166 return 0;
167 }
168 // TODO: probably is_in_.. and add_to_...
169 // can be combined: find_or_add_...
170 add_to_ino_dev_hashtable(&source_stat, dest);
171 }
172
173 src_fd = open(source, O_RDONLY);
174 if (src_fd == -1) {
175 bb_perror_msg("cannot open '%s'", source);
176 return -1;
177 }
178
179 // POSIX: if exists and -i, ask (w/o -i assume yes).
180 // Then open w/o EXCL.
181 // If open still fails and -f, try unlink, then try open again.
182 // Result: a mess:
183 // If dest is a softlink, we overwrite softlink's destination!
184 // (or fail, if it points to dir/nonexistent location/etc).
185 // This is strange, but POSIX-correct.
186 // coreutils cp has --remove-destination to override this...
187 dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE)
188 ? O_WRONLY|O_CREAT|O_TRUNC|O_EXCL
189 : O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode);
190 if (dst_fd == -1) {
191 // We would not do POSIX insanity. -i asks,
192 // then _unlinks_ the offender. Presto.
193 // Or else we will end up having 3 open()s!
194 ovr = retry_overwrite(dest, flags);
195 if (ovr <= 0) {
196 close(src_fd);
197 return ovr;
198 }
199 dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode);
200 if (dst_fd == -1) {
201 bb_perror_msg("cannot open '%s'", dest);
202 close(src_fd);
203 return -1;
204 }
205 }
206
207 if (bb_copyfd_eof(src_fd, dst_fd) == -1)
208 status = -1;
209 if (close(dst_fd) < 0) {
210 bb_perror_msg("cannot close '%s'", dest);
211 status = -1;
212 }
213 if (close(src_fd) < 0) {
214 bb_perror_msg("cannot close '%s'", source);
215 status = -1;
216 }
217
218 } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
219 || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
220 || S_ISLNK(source_stat.st_mode)
221 ) {
222 // We are lazy here, a bit lax with races...
223 if (dest_exists) {
224 ovr = retry_overwrite(dest, flags);
225 if (ovr <= 0)
226 return ovr;
227 }
228 if (S_ISFIFO(source_stat.st_mode)) {
229 if (mkfifo(dest, source_stat.st_mode) < 0) {
230 bb_perror_msg("cannot create fifo '%s'", dest);
231 return -1;
232 }
233 } else if (S_ISLNK(source_stat.st_mode)) {
234 char *lpath;
235
236 lpath = xreadlink(source);
237 if (symlink(lpath, dest) < 0) {
238 bb_perror_msg("cannot create symlink '%s'", dest);
239 free(lpath);
240 return -1;
241 }
242 free(lpath);
243
244 if (flags & FILEUTILS_PRESERVE_STATUS)
245 if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
246 bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
247
248 return 0;
249
250 } else {
251 if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
252 bb_perror_msg("cannot create '%s'", dest);
253 return -1;
254 }
255 }
256 } else {
257 bb_error_msg("internal error: unrecognized file type");
258 return -1;
259 }
260
261 preserve_status:
262
263 if (flags & FILEUTILS_PRESERVE_STATUS
264 /* Cannot happen: */
265 /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
266 ) {
267 struct utimbuf times;
268
269 times.actime = source_stat.st_atime;
270 times.modtime = source_stat.st_mtime;
271 if (utime(dest, &times) < 0)
272 bb_perror_msg("cannot preserve %s of '%s'", "times", dest);
273 if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
274 source_stat.st_mode &= ~(S_ISUID | S_ISGID);
275 bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
276 }
277 if (chmod(dest, source_stat.st_mode) < 0)
278 bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
279 }
280
281 return status;
282}
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
new file mode 100644
index 000000000..c6b886647
--- /dev/null
+++ b/libbb/copyfd.c
@@ -0,0 +1,86 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <errno.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "libbb.h"
16
17
18#if BUFSIZ < 4096
19#undef BUFSIZ
20#define BUFSIZ 4096
21#endif
22
23
24static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
25{
26 int status = -1;
27 off_t total = 0;
28 RESERVE_CONFIG_BUFFER(buffer, BUFSIZ);
29
30 if (src_fd < 0) goto out;
31
32 if (!size) {
33 size = BUFSIZ;
34 status = 1; /* copy until eof */
35 }
36
37 while (1) {
38 ssize_t rd;
39
40 rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ : size);
41
42 if (!rd) { /* eof - all done. */
43 status = 0;
44 break;
45 }
46 if (rd < 0) {
47 bb_perror_msg(bb_msg_read_error);
48 break;
49 }
50 /* dst_fd == -1 is a fake, else... */
51 if (dst_fd >= 0) {
52 ssize_t wr = full_write(dst_fd, buffer, rd);
53 if (wr < rd) {
54 bb_perror_msg(bb_msg_write_error);
55 break;
56 }
57 }
58 total += rd;
59 if (status < 0) {
60 size -= rd;
61 if (!size) {
62 status = 0;
63 break;
64 }
65 }
66 }
67
68out:
69 RELEASE_CONFIG_BUFFER(buffer);
70
71 return status ? -1 : total;
72}
73
74
75off_t bb_copyfd_size(int fd1, int fd2, off_t size)
76{
77 if (size) {
78 return bb_full_fd_action(fd1, fd2, size);
79 }
80 return 0;
81}
82
83off_t bb_copyfd_eof(int fd1, int fd2)
84{
85 return bb_full_fd_action(fd1, fd2, 0);
86}
diff --git a/libbb/correct_password.c b/libbb/correct_password.c
new file mode 100644
index 000000000..fd7e0b56c
--- /dev/null
+++ b/libbb/correct_password.c
@@ -0,0 +1,65 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include "libbb.h"
32
33/* Ask the user for a password.
34 Return 1 if the user gives the correct password for entry PW,
35 0 if not. Return 1 without asking for a password if run by UID 0
36 or if PW has an empty password. */
37
38int correct_password(const struct passwd *pw)
39{
40 char *unencrypted, *encrypted, *correct;
41
42#ifdef CONFIG_FEATURE_SHADOWPASSWDS
43 if (!strcmp(pw->pw_passwd, "x") || !strcmp(pw->pw_passwd, "*")) {
44 struct spwd *sp = getspnam(pw->pw_name);
45
46 if (!sp)
47 bb_error_msg_and_die("no valid shadow password");
48
49 correct = sp->sp_pwdp;
50 }
51 else
52#endif
53 correct = pw->pw_passwd;
54
55 if (!correct || correct[0] == '\0')
56 return 1;
57
58 unencrypted = bb_askpass(0, "Password: ");
59 if (!unencrypted) {
60 return 0;
61 }
62 encrypted = crypt(unencrypted, correct);
63 memset(unencrypted, 0, strlen(unencrypted));
64 return (!strcmp(encrypted, correct)) ? 1 : 0;
65}
diff --git a/libbb/crc32.c b/libbb/crc32.c
new file mode 100644
index 000000000..1e4a57e8a
--- /dev/null
+++ b/libbb/crc32.c
@@ -0,0 +1,39 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * CRC32 table fill function
4 * Copyright (C) 2006 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
5 * (I can't really claim much credit however, as the algorithm is
6 * very well-known)
7 *
8 * The following function creates a CRC32 table depending on whether
9 * a big-endian (0x04c11db7) or little-endian (0xedb88320) CRC32 is
10 * required. Admittedly, there are other CRC32 polynomials floating
11 * around, but Busybox doesn't use them.
12 *
13 * endian = 1: big-endian
14 * endian = 0: little-endian
15 */
16
17#include "libbb.h"
18
19uint32_t *crc32_filltable(int endian)
20{
21
22 uint32_t *crc_table = xmalloc(256 * sizeof(uint32_t));
23 uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320;
24 uint32_t c;
25 int i, j;
26
27 for (i = 0; i < 256; i++) {
28 c = endian ? (i << 24) : i;
29 for (j = 8; j; j--) {
30 if (endian)
31 c = (c&0x80000000) ? ((c << 1) ^ polynomial) : (c << 1);
32 else
33 c = (c&1) ? ((c >> 1) ^ polynomial) : (c >> 1);
34 }
35 *crc_table++ = c;
36 }
37
38 return crc_table - 256;
39}
diff --git a/libbb/create_icmp6_socket.c b/libbb/create_icmp6_socket.c
new file mode 100644
index 000000000..c3d1b5578
--- /dev/null
+++ b/libbb/create_icmp6_socket.c
@@ -0,0 +1,39 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * create raw socket for icmp (IPv6 version) protocol test permission
6 * and drop root privileges if running setuid
7 *
8 */
9
10#include <sys/types.h>
11#include <netdb.h>
12#include <sys/socket.h>
13#include <errno.h>
14#include <unistd.h>
15#include "libbb.h"
16
17#ifdef CONFIG_FEATURE_IPV6
18int create_icmp6_socket(void)
19{
20 struct protoent *proto;
21 int sock;
22
23 proto = getprotobyname("ipv6-icmp");
24 /* if getprotobyname failed, just silently force
25 * proto->p_proto to have the correct value for "ipv6-icmp" */
26 if ((sock = socket(AF_INET6, SOCK_RAW,
27 (proto ? proto->p_proto : IPPROTO_ICMPV6))) < 0) {
28 if (errno == EPERM)
29 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
30 else
31 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
32 }
33
34 /* drop root privs if running setuid */
35 xsetuid(getuid());
36
37 return sock;
38}
39#endif
diff --git a/libbb/create_icmp_socket.c b/libbb/create_icmp_socket.c
new file mode 100644
index 000000000..431c4d8a7
--- /dev/null
+++ b/libbb/create_icmp_socket.c
@@ -0,0 +1,37 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * create raw socket for icmp protocol test permission
6 * and drop root privileges if running setuid
7 *
8 */
9
10#include <sys/types.h>
11#include <netdb.h>
12#include <sys/socket.h>
13#include <errno.h>
14#include <unistd.h>
15#include "libbb.h"
16
17int create_icmp_socket(void)
18{
19 struct protoent *proto;
20 int sock;
21
22 proto = getprotobyname("icmp");
23 /* if getprotobyname failed, just silently force
24 * proto->p_proto to have the correct value for "icmp" */
25 if ((sock = socket(AF_INET, SOCK_RAW,
26 (proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */
27 if (errno == EPERM)
28 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
29 else
30 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
31 }
32
33 /* drop root privs if running setuid */
34 xsetuid(getuid());
35
36 return sock;
37}
diff --git a/libbb/default_error_retval.c b/libbb/default_error_retval.c
new file mode 100644
index 000000000..f4e46a4b5
--- /dev/null
+++ b/libbb/default_error_retval.c
@@ -0,0 +1,19 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
6 */
7
8/* Seems silly to copyright a global variable. ;-) Oh well.
9 *
10 * At least one applet (cmp) returns a value different from the typical
11 * EXIT_FAILURE values (1) when an error occurs. So, make it configurable
12 * by the applet. I suppose we could use a wrapper function to set it, but
13 * that too seems silly.
14 */
15
16#include <stdlib.h>
17#include "libbb.h"
18
19int xfunc_error_retval = EXIT_FAILURE;
diff --git a/libbb/device_open.c b/libbb/device_open.c
new file mode 100644
index 000000000..c788b6982
--- /dev/null
+++ b/libbb/device_open.c
@@ -0,0 +1,33 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <fcntl.h>
12#include "libbb.h"
13
14
15/* try to open up the specified device */
16int device_open(const char *device, int mode)
17{
18 int m, f, fd = -1;
19
20 m = mode | O_NONBLOCK;
21
22 /* Retry up to 5 times */
23 /* TODO: explain why it can't be considered insane */
24 for (f = 0; f < 5; f++)
25 if ((fd = open(device, m, 0600)) >= 0)
26 break;
27 if (fd < 0)
28 return fd;
29 /* Reset original flags. */
30 if (m != mode)
31 fcntl(fd, F_SETFL, mode);
32 return fd;
33}
diff --git a/libbb/dump.c b/libbb/dump.c
new file mode 100644
index 000000000..10710894e
--- /dev/null
+++ b/libbb/dump.c
@@ -0,0 +1,803 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Support code for the hexdump and od applets,
4 * based on code from util-linux v 2.11l
5 *
6 * Copyright (c) 1989
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10 *
11 * Original copyright notice is retained at the end of this file.
12 */
13
14#include "libbb.h"
15#include "dump.h"
16
17enum _vflag bb_dump_vflag = FIRST;
18FS *bb_dump_fshead; /* head of format strings */
19static FU *endfu;
20static char **_argv;
21static off_t savaddress; /* saved address/offset in stream */
22static off_t eaddress; /* end address */
23static off_t address; /* address/offset in stream */
24off_t bb_dump_skip; /* bytes to skip */
25static int exitval; /* final exit value */
26int bb_dump_blocksize; /* data block size */
27int bb_dump_length = -1; /* max bytes to read */
28
29static const char index_str[] = ".#-+ 0123456789";
30
31static const char size_conv_str[] =
32"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
33
34static const char lcc[] = "diouxX";
35
36int bb_dump_size(FS * fs)
37{
38 FU *fu;
39 int bcnt, cur_size;
40 char *fmt;
41 const char *p;
42 int prec;
43
44 /* figure out the data block bb_dump_size needed for each format unit */
45 for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
46 if (fu->bcnt) {
47 cur_size += fu->bcnt * fu->reps;
48 continue;
49 }
50 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
51 if (*fmt != '%')
52 continue;
53 /*
54 * bb_dump_skip any special chars -- save precision in
55 * case it's a %s format.
56 */
57 while (strchr(index_str + 1, *++fmt));
58 if (*fmt == '.' && isdigit(*++fmt)) {
59 prec = atoi(fmt);
60 while (isdigit(*++fmt));
61 }
62 if (!(p = strchr(size_conv_str + 12, *fmt))) {
63 if (*fmt == 's') {
64 bcnt += prec;
65 } else if (*fmt == '_') {
66 ++fmt;
67 if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
68 bcnt += 1;
69 }
70 }
71 } else {
72 bcnt += size_conv_str[p - (size_conv_str + 12)];
73 }
74 }
75 cur_size += bcnt * fu->reps;
76 }
77 return cur_size;
78}
79
80static void rewrite(FS * fs)
81{
82 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
83 PR *pr, **nextpr = NULL;
84 FU *fu;
85 char *p1, *p2, *p3;
86 char savech, *fmtp;
87 const char *byte_count_str;
88 int nconv, prec = 0;
89
90 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
91 /*
92 * break each format unit into print units; each
93 * conversion character gets its own.
94 */
95 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
96 /* NOSTRICT */
97 /* DBU:[dvae@cray.com] calloc so that forward ptrs start out NULL*/
98 pr = xzalloc(sizeof(PR));
99 if (!fu->nextpr)
100 fu->nextpr = pr;
101 /* ignore nextpr -- its unused inside the loop and is
102 * uninitialized 1st time thru.
103 */
104
105 /* bb_dump_skip preceding text and up to the next % sign */
106 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
107
108 /* only text in the string */
109 if (!*p1) {
110 pr->fmt = fmtp;
111 pr->flags = F_TEXT;
112 break;
113 }
114
115 /*
116 * get precision for %s -- if have a byte count, don't
117 * need it.
118 */
119 if (fu->bcnt) {
120 sokay = USEBCNT;
121 /* bb_dump_skip to conversion character */
122 for (++p1; strchr(index_str, *p1); ++p1);
123 } else {
124 /* bb_dump_skip any special chars, field width */
125 while (strchr(index_str + 1, *++p1));
126 if (*p1 == '.' && isdigit(*++p1)) {
127 sokay = USEPREC;
128 prec = atoi(p1);
129 while (isdigit(*++p1));
130 } else
131 sokay = NOTOKAY;
132 }
133
134 p2 = p1 + 1; /* set end pointer */
135
136 /*
137 * figure out the byte count for each conversion;
138 * rewrite the format as necessary, set up blank-
139 * pbb_dump_adding for end of data.
140 */
141
142 if (*p1 == 'c') {
143 pr->flags = F_CHAR;
144 DO_BYTE_COUNT_1:
145 byte_count_str = "\001";
146 DO_BYTE_COUNT:
147 if (fu->bcnt) {
148 do {
149 if (fu->bcnt == *byte_count_str) {
150 break;
151 }
152 } while (*++byte_count_str);
153 }
154 /* Unlike the original, output the remainder of the format string. */
155 if (!*byte_count_str) {
156 bb_error_msg_and_die("bad byte count for conversion character %s", p1);
157 }
158 pr->bcnt = *byte_count_str;
159 } else if (*p1 == 'l') {
160 ++p2;
161 ++p1;
162 DO_INT_CONV:
163 {
164 const char *e;
165 if (!(e = strchr(lcc, *p1))) {
166 goto DO_BAD_CONV_CHAR;
167 }
168 pr->flags = F_INT;
169 if (e > lcc + 1) {
170 pr->flags = F_UINT;
171 }
172 byte_count_str = "\004\002\001";
173 goto DO_BYTE_COUNT;
174 }
175 /* NOTREACHED */
176 } else if (strchr(lcc, *p1)) {
177 goto DO_INT_CONV;
178 } else if (strchr("eEfgG", *p1)) {
179 pr->flags = F_DBL;
180 byte_count_str = "\010\004";
181 goto DO_BYTE_COUNT;
182 } else if (*p1 == 's') {
183 pr->flags = F_STR;
184 if (sokay == USEBCNT) {
185 pr->bcnt = fu->bcnt;
186 } else if (sokay == USEPREC) {
187 pr->bcnt = prec;
188 } else { /* NOTOKAY */
189 bb_error_msg_and_die("%%s requires a precision or a byte count");
190 }
191 } else if (*p1 == '_') {
192 ++p2;
193 switch (p1[1]) {
194 case 'A':
195 endfu = fu;
196 fu->flags |= F_IGNORE;
197 /* FALLTHROUGH */
198 case 'a':
199 pr->flags = F_ADDRESS;
200 ++p2;
201 if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
202 goto DO_BAD_CONV_CHAR;
203 }
204 *p1 = p1[2];
205 break;
206 case 'c':
207 pr->flags = F_C;
208 /* *p1 = 'c'; set in conv_c */
209 goto DO_BYTE_COUNT_1;
210 case 'p':
211 pr->flags = F_P;
212 *p1 = 'c';
213 goto DO_BYTE_COUNT_1;
214 case 'u':
215 pr->flags = F_U;
216 /* *p1 = 'c'; set in conv_u */
217 goto DO_BYTE_COUNT_1;
218 default:
219 goto DO_BAD_CONV_CHAR;
220 }
221 } else {
222 DO_BAD_CONV_CHAR:
223 bb_error_msg_and_die("bad conversion character %%%s", p1);
224 }
225
226 /*
227 * copy to PR format string, set conversion character
228 * pointer, update original.
229 */
230 savech = *p2;
231 p1[1] = '\0';
232 pr->fmt = xstrdup(fmtp);
233 *p2 = savech;
234 pr->cchar = pr->fmt + (p1 - fmtp);
235
236 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
237 * Skip subsequent text and up to the next % sign and tack the
238 * additional text onto fmt: eg. if fmt is "%x is a HEX number",
239 * we lose the " is a HEX number" part of fmt.
240 */
241 for (p3 = p2; *p3 && *p3 != '%'; p3++);
242 if (p3 > p2)
243 {
244 savech = *p3;
245 *p3 = '\0';
246 pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1);
247 strcat(pr->fmt, p2);
248 *p3 = savech;
249 p2 = p3;
250 }
251
252 fmtp = p2;
253
254 /* only one conversion character if byte count */
255 if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
256 bb_error_msg_and_die("byte count with multiple conversion characters");
257 }
258 }
259 /*
260 * if format unit byte count not specified, figure it out
261 * so can adjust rep count later.
262 */
263 if (!fu->bcnt)
264 for (pr = fu->nextpr; pr; pr = pr->nextpr)
265 fu->bcnt += pr->bcnt;
266 }
267 /*
268 * if the format string interprets any data at all, and it's
269 * not the same as the bb_dump_blocksize, and its last format unit
270 * interprets any data at all, and has no iteration count,
271 * repeat it as necessary.
272 *
273 * if, rep count is greater than 1, no trailing whitespace
274 * gets output from the last iteration of the format unit.
275 */
276 for (fu = fs->nextfu;; fu = fu->nextfu) {
277 if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
278 !(fu->flags & F_SETREP) && fu->bcnt)
279 fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
280 if (fu->reps > 1) {
281 for (pr = fu->nextpr;; pr = pr->nextpr)
282 if (!pr->nextpr)
283 break;
284 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
285 p2 = isspace(*p1) ? p1 : NULL;
286 if (p2)
287 pr->nospace = p2;
288 }
289 if (!fu->nextfu)
290 break;
291 }
292}
293
294static void do_skip(char *fname, int statok)
295{
296 struct stat sbuf;
297
298 if (statok) {
299 if (fstat(STDIN_FILENO, &sbuf)) {
300 bb_perror_msg_and_die("%s", fname);
301 }
302 if ((!(S_ISCHR(sbuf.st_mode) ||
303 S_ISBLK(sbuf.st_mode) ||
304 S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
305 /* If bb_dump_size valid and bb_dump_skip >= size */
306 bb_dump_skip -= sbuf.st_size;
307 address += sbuf.st_size;
308 return;
309 }
310 }
311 if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
312 bb_perror_msg_and_die("%s", fname);
313 }
314 savaddress = address += bb_dump_skip;
315 bb_dump_skip = 0;
316}
317
318static int next(char **argv)
319{
320 static int done;
321 int statok;
322
323 if (argv) {
324 _argv = argv;
325 return 1;
326 }
327 for (;;) {
328 if (*_argv) {
329 if (!(freopen(*_argv, "r", stdin))) {
330 bb_perror_msg("%s", *_argv);
331 exitval = 1;
332 ++_argv;
333 continue;
334 }
335 statok = done = 1;
336 } else {
337 if (done++)
338 return 0;
339 statok = 0;
340 }
341 if (bb_dump_skip)
342 do_skip(statok ? *_argv : "stdin", statok);
343 if (*_argv)
344 ++_argv;
345 if (!bb_dump_skip)
346 return 1;
347 }
348 /* NOTREACHED */
349}
350
351static unsigned char *get(void)
352{
353 static int ateof = 1;
354 static unsigned char *curp=NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
355 int n;
356 int need, nread;
357 unsigned char *tmpp;
358
359 if (!curp) {
360 address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
361 curp = (unsigned char *) xmalloc(bb_dump_blocksize);
362 savp = (unsigned char *) xmalloc(bb_dump_blocksize);
363 } else {
364 tmpp = curp;
365 curp = savp;
366 savp = tmpp;
367 address = savaddress += bb_dump_blocksize;
368 }
369 for (need = bb_dump_blocksize, nread = 0;;) {
370 /*
371 * if read the right number of bytes, or at EOF for one file,
372 * and no other files are available, zero-pad the rest of the
373 * block and set the end flag.
374 */
375 if (!bb_dump_length || (ateof && !next((char **) NULL))) {
376 if (need == bb_dump_blocksize) {
377 return NULL;
378 }
379 if (bb_dump_vflag != ALL && !memcmp(curp, savp, nread)) {
380 if (bb_dump_vflag != DUP) {
381 puts("*");
382 }
383 return NULL;
384 }
385 memset((char *) curp + nread, 0, need);
386 eaddress = address + nread;
387 return curp;
388 }
389 n = fread((char *) curp + nread, sizeof(unsigned char),
390 bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
391 if (!n) {
392 if (ferror(stdin)) {
393 bb_perror_msg("%s", _argv[-1]);
394 }
395 ateof = 1;
396 continue;
397 }
398 ateof = 0;
399 if (bb_dump_length != -1) {
400 bb_dump_length -= n;
401 }
402 if (!(need -= n)) {
403 if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
404 || memcmp(curp, savp, bb_dump_blocksize)) {
405 if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
406 bb_dump_vflag = WAIT;
407 }
408 return curp;
409 }
410 if (bb_dump_vflag == WAIT) {
411 puts("*");
412 }
413 bb_dump_vflag = DUP;
414 address = savaddress += bb_dump_blocksize;
415 need = bb_dump_blocksize;
416 nread = 0;
417 } else {
418 nread += n;
419 }
420 }
421}
422
423static void bpad(PR * pr)
424{
425 char *p1, *p2;
426
427 /*
428 * remove all conversion flags; '-' is the only one valid
429 * with %s, and it's not useful here.
430 */
431 pr->flags = F_BPAD;
432 *pr->cchar = 's';
433 for (p1 = pr->fmt; *p1 != '%'; ++p1);
434 for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
435 if (pr->nospace) pr->nospace--;
436 while ((*p2++ = *p1++) != 0);
437}
438
439static const char conv_str[] =
440 "\0\\0\0"
441 "\007\\a\0" /* \a */
442 "\b\\b\0"
443 "\f\\b\0"
444 "\n\\n\0"
445 "\r\\r\0"
446 "\t\\t\0"
447 "\v\\v\0"
448 "\0";
449
450
451static void conv_c(PR * pr, unsigned char * p)
452{
453 const char *str = conv_str;
454 char buf[10];
455
456 do {
457 if (*p == *str) {
458 ++str;
459 goto strpr;
460 }
461 str += 4;
462 } while (*str);
463
464 if (isprint(*p)) {
465 *pr->cchar = 'c';
466 (void) printf(pr->fmt, *p);
467 } else {
468 sprintf(buf, "%03o", (int) *p);
469 str = buf;
470 strpr:
471 *pr->cchar = 's';
472 printf(pr->fmt, str);
473 }
474}
475
476static void conv_u(PR * pr, unsigned char * p)
477{
478 static const char list[] =
479 "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
480 "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
481 "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
482 "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
483
484 /* od used nl, not lf */
485 if (*p <= 0x1f) {
486 *pr->cchar = 's';
487 printf(pr->fmt, list + (4 * (int)*p));
488 } else if (*p == 0x7f) {
489 *pr->cchar = 's';
490 printf(pr->fmt, "del");
491 } else if (isprint(*p)) {
492 *pr->cchar = 'c';
493 printf(pr->fmt, *p);
494 } else {
495 *pr->cchar = 'x';
496 printf(pr->fmt, (int) *p);
497 }
498}
499
500static void display(void)
501{
502/* extern FU *endfu; */
503 FS *fs;
504 FU *fu;
505 PR *pr;
506 int cnt;
507 unsigned char *bp;
508
509 off_t saveaddress;
510 unsigned char savech = 0, *savebp;
511
512 while ((bp = get()) != NULL) {
513 for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
514 fs = fs->nextfs, bp = savebp, address = saveaddress) {
515 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
516 if (fu->flags & F_IGNORE) {
517 break;
518 }
519 for (cnt = fu->reps; cnt; --cnt) {
520 for (pr = fu->nextpr; pr; address += pr->bcnt,
521 bp += pr->bcnt, pr = pr->nextpr) {
522 if (eaddress && address >= eaddress &&
523 !(pr->flags & (F_TEXT | F_BPAD))) {
524 bpad(pr);
525 }
526 if (cnt == 1 && pr->nospace) {
527 savech = *pr->nospace;
528 *pr->nospace = '\0';
529 }
530/* PRINT; */
531 switch (pr->flags) {
532 case F_ADDRESS:
533 printf(pr->fmt, (unsigned int) address);
534 break;
535 case F_BPAD:
536 printf(pr->fmt, "");
537 break;
538 case F_C:
539 conv_c(pr, bp);
540 break;
541 case F_CHAR:
542 printf(pr->fmt, *bp);
543 break;
544 case F_DBL:{
545 double dval;
546 float fval;
547
548 switch (pr->bcnt) {
549 case 4:
550 memmove((char *) &fval, (char *) bp,
551 sizeof(fval));
552 printf(pr->fmt, fval);
553 break;
554 case 8:
555 memmove((char *) &dval, (char *) bp,
556 sizeof(dval));
557 printf(pr->fmt, dval);
558 break;
559 }
560 break;
561 }
562 case F_INT:{
563 int ival;
564 short sval;
565
566 switch (pr->bcnt) {
567 case 1:
568 printf(pr->fmt, (int) *bp);
569 break;
570 case 2:
571 memmove((char *) &sval, (char *) bp,
572 sizeof(sval));
573 printf(pr->fmt, (int) sval);
574 break;
575 case 4:
576 memmove((char *) &ival, (char *) bp,
577 sizeof(ival));
578 printf(pr->fmt, ival);
579 break;
580 }
581 break;
582 }
583 case F_P:
584 printf(pr->fmt, isprint(*bp) ? *bp : '.');
585 break;
586 case F_STR:
587 printf(pr->fmt, (char *) bp);
588 break;
589 case F_TEXT:
590 printf(pr->fmt);
591 break;
592 case F_U:
593 conv_u(pr, bp);
594 break;
595 case F_UINT:{
596 unsigned int ival;
597 unsigned short sval;
598
599 switch (pr->bcnt) {
600 case 1:
601 printf(pr->fmt, (unsigned int) * bp);
602 break;
603 case 2:
604 memmove((char *) &sval, (char *) bp,
605 sizeof(sval));
606 printf(pr->fmt, (unsigned int) sval);
607 break;
608 case 4:
609 memmove((char *) &ival, (char *) bp,
610 sizeof(ival));
611 printf(pr->fmt, ival);
612 break;
613 }
614 break;
615 }
616 }
617 if (cnt == 1 && pr->nospace) {
618 *pr->nospace = savech;
619 }
620 }
621 }
622 }
623 }
624 }
625 if (endfu) {
626 /*
627 * if eaddress not set, error or file bb_dump_size was multiple of
628 * bb_dump_blocksize, and no partial block ever found.
629 */
630 if (!eaddress) {
631 if (!address) {
632 return;
633 }
634 eaddress = address;
635 }
636 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
637 switch (pr->flags) {
638 case F_ADDRESS:
639 (void) printf(pr->fmt, (unsigned int) eaddress);
640 break;
641 case F_TEXT:
642 (void) printf(pr->fmt);
643 break;
644 }
645 }
646 }
647}
648
649int bb_dump_dump(char **argv)
650{
651 FS *tfs;
652
653 /* figure out the data block bb_dump_size */
654 for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
655 tfs->bcnt = bb_dump_size(tfs);
656 if (bb_dump_blocksize < tfs->bcnt) {
657 bb_dump_blocksize = tfs->bcnt;
658 }
659 }
660 /* rewrite the rules, do syntax checking */
661 for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
662 rewrite(tfs);
663 }
664
665 next(argv);
666 display();
667
668 return exitval;
669}
670
671void bb_dump_add(const char *fmt)
672{
673 const char *p;
674 char *p1;
675 char *p2;
676 static FS **nextfs;
677 FS *tfs;
678 FU *tfu, **nextfu;
679 const char *savep;
680
681 /* start new linked list of format units */
682 tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
683 if (!bb_dump_fshead) {
684 bb_dump_fshead = tfs;
685 } else {
686 *nextfs = tfs;
687 }
688 nextfs = &tfs->nextfs;
689 nextfu = &tfs->nextfu;
690
691 /* take the format string and break it up into format units */
692 for (p = fmt;;) {
693 /* bb_dump_skip leading white space */
694 p = skip_whitespace(p);
695 if (!*p) {
696 break;
697 }
698
699 /* allocate a new format unit and link it in */
700 /* NOSTRICT */
701 /* DBU:[dave@cray.com] calloc so that forward pointers start out NULL */
702 tfu = xzalloc(sizeof(FU));
703 *nextfu = tfu;
704 nextfu = &tfu->nextfu;
705 tfu->reps = 1;
706
707 /* if leading digit, repetition count */
708 if (isdigit(*p)) {
709 for (savep = p; isdigit(*p); ++p);
710 if (!isspace(*p) && *p != '/') {
711 bb_error_msg_and_die("bad format {%s}", fmt);
712 }
713 /* may overwrite either white space or slash */
714 tfu->reps = atoi(savep);
715 tfu->flags = F_SETREP;
716 /* bb_dump_skip trailing white space */
717 p = skip_whitespace(++p);
718 }
719
720 /* bb_dump_skip slash and trailing white space */
721 if (*p == '/') {
722 p = skip_whitespace(++p);
723 }
724
725 /* byte count */
726 if (isdigit(*p)) {
727 for (savep = p; isdigit(*p); ++p);
728 if (!isspace(*p)) {
729 bb_error_msg_and_die("bad format {%s}", fmt);
730 }
731 tfu->bcnt = atoi(savep);
732 /* bb_dump_skip trailing white space */
733 p = skip_whitespace(++p);
734 }
735
736 /* format */
737 if (*p != '"') {
738 bb_error_msg_and_die("bad format {%s}", fmt);
739 }
740 for (savep = ++p; *p != '"';) {
741 if (*p++ == 0) {
742 bb_error_msg_and_die("bad format {%s}", fmt);
743 }
744 }
745 tfu->fmt = xmalloc(p - savep + 1);
746 strncpy(tfu->fmt, savep, p - savep);
747 tfu->fmt[p - savep] = '\0';
748/* escape(tfu->fmt); */
749
750 p1 = tfu->fmt;
751
752 /* alphabetic escape sequences have to be done in place */
753 for (p2 = p1;; ++p1, ++p2) {
754 if (!*p1) {
755 *p2 = *p1;
756 break;
757 }
758 if (*p1 == '\\') {
759 const char *cs = conv_str + 4;
760 ++p1;
761 *p2 = *p1;
762 do {
763 if (*p1 == cs[2]) {
764 *p2 = cs[0];
765 break;
766 }
767 cs += 4;
768 } while (*cs);
769 }
770 }
771
772 p++;
773 }
774}
775
776/*
777 * Copyright (c) 1989 The Regents of the University of California.
778 * All rights reserved.
779 *
780 * Redistribution and use in source and binary forms, with or without
781 * modification, are permitted provided that the following conditions
782 * are met:
783 * 1. Redistributions of source code must retain the above copyright
784 * notice, this list of conditions and the following disclaimer.
785 * 2. Redistributions in binary form must reproduce the above copyright
786 * notice, this list of conditions and the following disclaimer in the
787 * documentation and/or other materials provided with the distribution.
788 * 3. Neither the name of the University nor the names of its contributors
789 * may be used to endorse or promote products derived from this software
790 * without specific prior written permission.
791 *
792 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
793 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
794 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
795 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
796 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
797 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
798 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
799 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
800 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
801 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
802 * SUCH DAMAGE.
803 */
diff --git a/libbb/error_msg.c b/libbb/error_msg.c
new file mode 100644
index 000000000..b2141f3a2
--- /dev/null
+++ b/libbb/error_msg.c
@@ -0,0 +1,23 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <errno.h>
12#include <string.h>
13#include <stdlib.h>
14#include "libbb.h"
15
16void bb_error_msg(const char *s, ...)
17{
18 va_list p;
19
20 va_start(p, s);
21 bb_verror_msg(s, p, NULL);
22 va_end(p);
23}
diff --git a/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c
new file mode 100644
index 000000000..10d953513
--- /dev/null
+++ b/libbb/error_msg_and_die.c
@@ -0,0 +1,28 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <errno.h>
12#include <string.h>
13#include <stdlib.h>
14#include "libbb.h"
15
16int die_sleep;
17
18void bb_error_msg_and_die(const char *s, ...)
19{
20 va_list p;
21
22 va_start(p, s);
23 bb_verror_msg(s, p, NULL);
24 va_end(p);
25 if (die_sleep)
26 sleep(die_sleep);
27 exit(xfunc_error_retval);
28}
diff --git a/libbb/execable.c b/libbb/execable.c
new file mode 100644
index 000000000..817c06736
--- /dev/null
+++ b/libbb/execable.c
@@ -0,0 +1,61 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12/* check if path points to an executable file;
13 * return 1 if found;
14 * return 0 otherwise;
15 */
16int execable_file(const char *name)
17{
18 struct stat s;
19 return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
20}
21
22/* search $PATH for an executable file;
23 * return allocated string containing full path if found;
24 * return NULL otherwise;
25 */
26char *find_execable(const char *filename)
27{
28 char *path, *p, *n;
29
30 p = path = xstrdup(getenv("PATH"));
31 while (p) {
32 n = strchr(p, ':');
33 if (n)
34 *n++ = '\0';
35 if (*p != '\0') { /* it's not a PATH="foo::bar" situation */
36 p = concat_path_file(p, filename);
37 if (execable_file(p)) {
38 free(path);
39 return p;
40 }
41 free(p);
42 }
43 p = n;
44 }
45 free(path);
46 return NULL;
47}
48
49/* search $PATH for an executable file;
50 * return 1 if found;
51 * return 0 otherwise;
52 */
53int exists_execable(const char *filename)
54{
55 char *ret = find_execable(filename);
56 if (ret) {
57 free(ret);
58 return 1;
59 }
60 return 0;
61}
diff --git a/libbb/fclose_nonstdin.c b/libbb/fclose_nonstdin.c
new file mode 100644
index 000000000..88e8474f2
--- /dev/null
+++ b/libbb/fclose_nonstdin.c
@@ -0,0 +1,23 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fclose_nonstdin implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* A number of standard utilities can accept multiple command line args
11 * of '-' for stdin, according to SUSv3. So we encapsulate the check
12 * here to save a little space.
13 */
14
15#include "libbb.h"
16
17int fclose_if_not_stdin(FILE *f)
18{
19 if (f != stdin) {
20 return fclose(f);
21 }
22 return 0;
23}
diff --git a/libbb/fflush_stdout_and_exit.c b/libbb/fflush_stdout_and_exit.c
new file mode 100644
index 000000000..456ce9513
--- /dev/null
+++ b/libbb/fflush_stdout_and_exit.c
@@ -0,0 +1,24 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fflush_stdout_and_exit implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* Attempt to fflush(stdout), and exit with an error code if stdout is
11 * in an error state.
12 */
13
14#include "libbb.h"
15
16void fflush_stdout_and_exit(int retval)
17{
18 if (fflush(stdout)) {
19 retval = xfunc_error_retval;
20 }
21 if (die_sleep)
22 sleep(die_sleep);
23 exit(retval);
24}
diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c
new file mode 100644
index 000000000..1bc6c3b1c
--- /dev/null
+++ b/libbb/fgets_str.c
@@ -0,0 +1,53 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people.
6 * If you wrote this, please acknowledge your work.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include "libbb.h"
12
13/* Read up to (and including) TERMINATING_STRING from FILE and return it.
14 * Return NULL on EOF. */
15
16char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
17{
18 char *linebuf = NULL;
19 const int term_length = strlen(terminating_string);
20 int end_string_offset;
21 int linebufsz = 0;
22 int idx = 0;
23 int ch;
24
25 while (1) {
26 ch = fgetc(file);
27 if (ch == EOF) {
28 free(linebuf);
29 return NULL;
30 }
31
32 /* grow the line buffer as necessary */
33 while (idx > linebufsz - 2) {
34 linebufsz += 200;
35 linebuf = xrealloc(linebuf, linebufsz);
36 }
37
38 linebuf[idx] = ch;
39 idx++;
40
41 /* Check for terminating string */
42 end_string_offset = idx - term_length;
43 if (end_string_offset > 0
44 && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
45 ) {
46 idx -= term_length;
47 break;
48 }
49 }
50 linebuf = xrealloc(linebuf, idx + 1);
51 linebuf[idx] = '\0';
52 return linebuf;
53}
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
new file mode 100644
index 000000000..cb00b9806
--- /dev/null
+++ b/libbb/find_mount_point.c
@@ -0,0 +1,53 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include <mntent.h>
12
13/*
14 * Given a block device, find the mount table entry if that block device
15 * is mounted.
16 *
17 * Given any other file (or directory), find the mount table entry for its
18 * filesystem.
19 */
20struct mntent *find_mount_point(const char *name, const char *table)
21{
22 struct stat s;
23 dev_t mountDevice;
24 FILE *mountTable;
25 struct mntent *mountEntry;
26
27 if (stat(name, &s) != 0)
28 return 0;
29
30 if ((s.st_mode & S_IFMT) == S_IFBLK)
31 mountDevice = s.st_rdev;
32 else
33 mountDevice = s.st_dev;
34
35
36 mountTable = setmntent(table ? table : bb_path_mtab_file, "r");
37 if (!mountTable)
38 return 0;
39
40 while ((mountEntry = getmntent(mountTable)) != 0) {
41 if (strcmp(name, mountEntry->mnt_dir) == 0
42 || strcmp(name, mountEntry->mnt_fsname) == 0
43 ) { /* String match. */
44 break;
45 }
46 if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
47 break;
48 if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
49 break;
50 }
51 endmntent(mountTable);
52 return mountEntry;
53}
diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c
new file mode 100644
index 000000000..e98616940
--- /dev/null
+++ b/libbb/find_pid_by_name.c
@@ -0,0 +1,55 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8 */
9
10#include "libbb.h"
11
12/* find_pid_by_name()
13 *
14 * Modified by Vladimir Oleynik for use with libbb/procps.c
15 * This finds the pid of the specified process.
16 * Currently, it's implemented by rummaging through
17 * the proc filesystem.
18 *
19 * Returns a list of all matching PIDs
20 * It is the caller's duty to free the returned pidlist.
21 */
22pid_t* find_pid_by_name(const char* procName)
23{
24 pid_t* pidList;
25 int i = 0;
26 procps_status_t* p = NULL;
27
28 pidList = xmalloc(sizeof(*pidList));
29 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM))) {
30 if (strncmp(p->comm, procName, sizeof(p->comm)-1) == 0) {
31 pidList = xrealloc(pidList, sizeof(*pidList) * (i+2));
32 pidList[i++] = p->pid;
33 }
34 }
35
36 pidList[i] = 0;
37 return pidList;
38}
39
40pid_t *pidlist_reverse(pid_t *pidList)
41{
42 int i = 0;
43 while (pidList[i])
44 i++;
45 if (--i >= 0) {
46 pid_t k;
47 int j;
48 for (j = 0; i > j; i--, j++) {
49 k = pidList[i];
50 pidList[i] = pidList[j];
51 pidList[j] = k;
52 }
53 }
54 return pidList;
55}
diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c
new file mode 100644
index 000000000..71b79b8d0
--- /dev/null
+++ b/libbb/find_root_device.c
@@ -0,0 +1,33 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12char *find_block_device(char *path)
13{
14 DIR *dir;
15 struct dirent *entry;
16 struct stat st;
17 dev_t dev;
18 char *retpath=NULL;
19
20 if(stat(path, &st) || !(dir = opendir("/dev"))) return NULL;
21 dev = (st.st_mode & S_IFMT) == S_IFBLK ? st.st_rdev : st.st_dev;
22 while((entry = readdir(dir)) != NULL) {
23 char devpath[PATH_MAX];
24 sprintf(devpath,"/dev/%s", entry->d_name);
25 if(!stat(devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) {
26 retpath = xstrdup(devpath);
27 break;
28 }
29 }
30 closedir(dir);
31
32 return retpath;
33}
diff --git a/libbb/full_write.c b/libbb/full_write.c
new file mode 100644
index 000000000..bceac6de5
--- /dev/null
+++ b/libbb/full_write.c
@@ -0,0 +1,38 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <unistd.h>
12#include "libbb.h"
13
14/*
15 * Write all of the supplied buffer out to a file.
16 * This does multiple writes as necessary.
17 * Returns the amount written, or -1 on an error.
18 */
19ssize_t full_write(int fd, const void *buf, size_t len)
20{
21 ssize_t cc;
22 ssize_t total;
23
24 total = 0;
25
26 while (len) {
27 cc = safe_write(fd, buf, len);
28
29 if (cc < 0)
30 return cc; /* write() returns -1 on failure. */
31
32 total += cc;
33 buf = ((const char *)buf) + cc;
34 len -= cc;
35 }
36
37 return total;
38}
diff --git a/libbb/get_console.c b/libbb/get_console.c
new file mode 100644
index 000000000..52ae3d215
--- /dev/null
+++ b/libbb/get_console.c
@@ -0,0 +1,77 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people. If you wrote this, please
6 * acknowledge your work.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include <stdio.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <unistd.h>
15#include <sys/ioctl.h>
16#include "libbb.h"
17
18
19
20/* From <linux/kd.h> */
21enum { KDGKBTYPE = 0x4B33 }; /* get keyboard type */
22
23
24static int open_a_console(const char *fnam)
25{
26 int fd;
27
28 /* try read-write */
29 fd = open(fnam, O_RDWR);
30
31 /* if failed, try read-only */
32 if (fd < 0 && errno == EACCES)
33 fd = open(fnam, O_RDONLY);
34
35 /* if failed, try write-only */
36 if (fd < 0 && errno == EACCES)
37 fd = open(fnam, O_WRONLY);
38
39 return fd;
40}
41
42/*
43 * Get an fd for use with kbd/console ioctls.
44 * We try several things because opening /dev/console will fail
45 * if someone else used X (which does a chown on /dev/console).
46 */
47
48int get_console_fd(void)
49{
50 int fd;
51
52 static const char * const choise_console_names[] = {
53 CONSOLE_DEV, CURRENT_VC, CURRENT_TTY
54 };
55
56 for (fd = 2; fd >= 0; fd--) {
57 int fd4name;
58 int choise_fd;
59 char arg;
60
61 fd4name = open_a_console(choise_console_names[fd]);
62 chk_std:
63 choise_fd = fd4name >= 0 ? fd4name : fd;
64
65 arg = 0;
66 if (ioctl(choise_fd, KDGKBTYPE, &arg) == 0)
67 return choise_fd;
68 if(fd4name >= 0) {
69 close(fd4name);
70 fd4name = -1;
71 goto chk_std;
72 }
73 }
74
75 bb_error_msg("cannot get file descriptor referring to console");
76 return fd; /* total failure */
77}
diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c
new file mode 100644
index 000000000..311909726
--- /dev/null
+++ b/libbb/get_last_path_component.c
@@ -0,0 +1,32 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bb_get_last_path_component implementation for busybox
4 *
5 * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12char *bb_get_last_path_component(char *path)
13{
14 char *first = path;
15 char *last;
16
17 last = path - 1;
18
19 while (*path) {
20 if ((*path != '/') && (path > ++last)) {
21 last = first = path;
22 }
23 ++path;
24 }
25
26 if (*first == '/') {
27 last = first;
28 }
29 last[1] = 0;
30
31 return first;
32}
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
new file mode 100644
index 000000000..3f2c6096e
--- /dev/null
+++ b/libbb/get_line_from_file.c
@@ -0,0 +1,68 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2005, 2006 Rob Landley <rob@landley.net>
6 * Copyright (C) 2004 Erik Andersen <andersen@codepoet.org>
7 * Copyright (C) 2001 Matt Krai
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10 */
11
12#include "libbb.h"
13
14/* This function reads an entire line from a text file, up to a newline
15 * or NUL byte, inclusive. It returns a malloc'ed char * which must be
16 * stored and free'ed by the caller. If end is null '\n' isn't considered
17 * end of line. If end isn't null, length of the chunk read is stored in it. */
18
19char *bb_get_chunk_from_file(FILE * file, int *end)
20{
21 int ch;
22 int idx = 0;
23 char *linebuf = NULL;
24 int linebufsz = 0;
25
26 while ((ch = getc(file)) != EOF) {
27 /* grow the line buffer as necessary */
28 if (idx >= linebufsz) {
29 linebuf = xrealloc(linebuf, linebufsz += 80);
30 }
31 linebuf[idx++] = (char) ch;
32 if (!ch || (end && ch == '\n'))
33 break;
34 }
35 if (end)
36 *end = idx;
37 if (linebuf) {
38 // huh, does fgets discard prior data on error like this?
39 // I don't think so....
40 //if (ferror(file)) {
41 // free(linebuf);
42 // return NULL;
43 //}
44 linebuf = xrealloc(linebuf, idx+1);
45 linebuf[idx] = '\0';
46 }
47 return linebuf;
48}
49
50/* Get line, including trailing \n if any */
51char *xmalloc_fgets(FILE * file)
52{
53 int i;
54
55 return bb_get_chunk_from_file(file, &i);
56}
57
58/* Get line. Remove trailing \n */
59char *xmalloc_getline(FILE * file)
60{
61 int i;
62 char *c = bb_get_chunk_from_file(file, &i);
63
64 if (i && c[--i] == '\n')
65 c[i] = 0;
66
67 return c;
68}
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
new file mode 100644
index 000000000..dddf8121a
--- /dev/null
+++ b/libbb/getopt32.c
@@ -0,0 +1,529 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * universal getopt32 implementation for busybox
4 *
5 * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include <getopt.h>
12
13/* Documentation
14
15uint32_t
16getopt32(int argc, char **argv, const char *applet_opts, ...)
17
18 The command line options must be declared in const char
19 *applet_opts as a string of chars, for example:
20
21 flags = getopt32(argc, argv, "rnug");
22
23 If one of the given options is found, a flag value is added to
24 the return value (an unsigned long).
25
26 The flag value is determined by the position of the char in
27 applet_opts string. For example, in the above case:
28
29 flags = getopt32(argc, argv, "rnug");
30
31 "r" will add 1 (bit 0)
32 "n" will add 2 (bit 1)
33 "u will add 4 (bit 2)
34 "g" will add 8 (bit 3)
35
36 and so on. You can also look at the return value as a bit
37 field and each option sets one bit.
38
39 On exit, global variable optind is set so that if you
40 will do argc -= optind; argv += optind; then
41 argc will be equal to number of remaining non-option
42 arguments, first one would be in argv[0], next in argv[1] and so on
43 (options and their parameters will be moved into argv[]
44 positions prior to argv[optind]).
45
46 ":" If one of the options requires an argument, then add a ":"
47 after the char in applet_opts and provide a pointer to store
48 the argument. For example:
49
50 char *pointer_to_arg_for_a;
51 char *pointer_to_arg_for_b;
52 char *pointer_to_arg_for_c;
53 char *pointer_to_arg_for_d;
54
55 flags = getopt32(argc, argv, "a:b:c:d:",
56 &pointer_to_arg_for_a, &pointer_to_arg_for_b,
57 &pointer_to_arg_for_c, &pointer_to_arg_for_d);
58
59 The type of the pointer (char* or llist_t*) may be controlled
60 by the "::" special separator that is set in the external string
61 opt_complementary (see below for more info).
62
63 "::" If option can have an *optional* argument, then add a "::"
64 after its char in applet_opts and provide a pointer to store
65 the argument. Note that optional arguments _must_
66 immediately follow the option: -oparam, not -o param.
67
68 "+" If the first character in the applet_opts string is a plus,
69 then option processing will stop as soon as a non-option is
70 encountered in the argv array. Useful for applets like env
71 which should not process arguments to subprograms:
72 env -i ls -d /
73 Here we want env to process just the '-i', not the '-d'.
74
75const struct option *applet_long_options
76
77 This struct allows you to define long options. The syntax for
78 declaring the array is just like that of getopt's longopts.
79 (see getopt(3))
80
81 static const struct option applet_long_options[] = {
82 //name,has_arg,flag,val
83 { "verbose", 0, 0, 'v' },
84 { 0, 0, 0, 0 }
85 };
86 applet_long_options = applet_long_options;
87
88 The last member of struct option (val) typically is set to
89 matching short option from applet_opts. If there is no matching
90 char in applet_opts, then:
91 - return bit have next position after short options
92 - if has_arg is not "no_argument", use ptr for arg also
93 - opt_complementary affects it too
94
95 Note: a good applet will make long options configurable via the
96 config process and not a required feature. The current standard
97 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
98
99const char *opt_complementary
100
101 ":" The colon (":") is used to separate groups of two or more chars
102 and/or groups of chars and special characters (stating some
103 conditions to be checked).
104
105 "abc" If groups of two or more chars are specified, the first char
106 is the main option and the other chars are secondary options.
107 Their flags will be turned on if the main option is found even
108 if they are not specifed on the command line. For example:
109
110 opt_complementary = "abc";
111 flags = getopt32(argc, argv, "abcd")
112
113 If getopt() finds "-a" on the command line, then
114 getopt32's return value will be as if "-a -b -c" were
115 found.
116
117 "ww" Adjacent double options have a counter associated which indicates
118 the number of occurences of the option.
119 For example the ps applet needs:
120 if w is given once, GNU ps sets the width to 132,
121 if w is given more than once, it is "unlimited"
122
123 int w_counter = 0;
124 opt_complementary = "ww";
125 getopt32(argc, argv, "w", &w_counter);
126 if (w_counter)
127 width = (w_counter == 1) ? 132 : INT_MAX;
128 else
129 get_terminal_width(...&width...);
130
131 w_counter is a pointer to an integer. It has to be passed to
132 getopt32() after all other option argument sinks.
133
134 For example: accept multiple -v to indicate the level of verbosity
135 and for each -b optarg, add optarg to my_b. Finally, if b is given,
136 turn off c and vice versa:
137
138 llist_t *my_b = NULL;
139 int verbose_level = 0;
140 opt_complementary = "vv:b::b-c:c-b";
141 f = getopt32(argc, argv, "vb:c", &my_b, &verbose_level);
142 if (f & 2) // -c after -b unsets -b flag
143 while (my_b) { dosomething_with(my_b->data); my_b = my_b->link; }
144 if (my_b) // but llist is stored if -b is specified
145 free_llist(my_b);
146 if (verbose_level) printf("verbose level is %d\n", verbose_level);
147
148Special characters:
149
150 "-" A dash as the first char in a opt_complementary group forces
151 all arguments to be treated as options, even if they have
152 no leading dashes. Next char in this case can't be a digit (0-9),
153 use ':' or end of line. For example:
154
155 opt_complementary = "-:w-x:x-w";
156 getopt32(argc, argv, "wx");
157
158 Allows any arguments to be given without a dash (./program w x)
159 as well as with a dash (./program -x).
160
161 "--" A double dash at the beginning of opt_complementary means the
162 argv[1] string should always be treated as options, even if it isn't
163 prefixed with a "-". This is useful for special syntax in applets
164 such as "ar" and "tar":
165 tar xvf foo.tar
166
167 "-N" A dash as the first char in a opt_complementary group followed
168 by a single digit (0-9) means that at least N non-option
169 arguments must be present on the command line
170
171 "=N" An equal sign as the first char in a opt_complementary group followed
172 by a single digit (0-9) means that exactly N non-option
173 arguments must be present on the command line
174
175 "?N" A "?" as the first char in a opt_complementary group followed
176 by a single digit (0-9) means that at most N arguments must be present
177 on the command line.
178
179 "V-" An option with dash before colon or end-of-line results in
180 bb_show_usage being called if this option is encountered.
181 This is typically used to implement "print verbose usage message
182 and exit" option.
183
184 "-" A dash between two options causes the second of the two
185 to be unset (and ignored) if it is given on the command line.
186
187 [FIXME: what if they are the same? like "x-x"? Is it ever useful?]
188
189 For example:
190 The du applet has the options "-s" and "-d depth". If
191 getopt32 finds -s, then -d is unset or if it finds -d
192 then -s is unset. (Note: busybox implements the GNU
193 "--max-depth" option as "-d".) To obtain this behavior, you
194 set opt_complementary = "s-d:d-s". Only one flag value is
195 added to getopt32's return value depending on the
196 position of the options on the command line. If one of the
197 two options requires an argument pointer (":" in applet_opts
198 as in "d:") optarg is set accordingly.
199
200 char *smax_print_depth;
201
202 opt_complementary = "s-d:d-s:x-x";
203 opt = getopt32(argc, argv, "sd:x", &smax_print_depth);
204
205 if (opt & 2)
206 max_print_depth = atoi(smax_print_depth);
207 if (opt & 4)
208 printf("Detected odd -x usage\n");
209
210 "--" A double dash between two options, or between an option and a group
211 of options, means that they are mutually exclusive. Unlike
212 the "-" case above, an error will be forced if the options
213 are used together.
214
215 For example:
216 The cut applet must have only one type of list specified, so
217 -b, -c and -f are mutally exclusive and should raise an error
218 if specified together. In this case you must set
219 opt_complementary = "b--cf:c--bf:f--bc". If two of the
220 mutually exclusive options are found, getopt32's
221 return value will have the error flag set (BB_GETOPT_ERROR) so
222 that we can check for it:
223
224 if (flags & BB_GETOPT_ERROR)
225 bb_show_usage();
226
227 "x--x" Variation of the above, it means that -x option should occur
228 at most once.
229
230 "?" A "?" as the first char in a opt_complementary group means:
231 if BB_GETOPT_ERROR is detected, don't return, call bb_show_usage
232 and exit instead. Next char after '?' can't be a digit.
233
234 "::" A double colon after a char in opt_complementary means that the
235 option can occur multiple times. Each occurrence will be saved as
236 a llist_t element instead of char*.
237
238 For example:
239 The grep applet can have one or more "-e pattern" arguments.
240 In this case you should use getopt32() as follows:
241
242 llist_t *patterns = NULL;
243
244 (this pointer must be initializated to NULL if the list is empty
245 as required by *llist_add_to(llist_t *old_head, char *new_item).)
246
247 opt_complementary = "e::";
248
249 getopt32(argc, argv, "e:", &patterns);
250 $ grep -e user -e root /etc/passwd
251 root:x:0:0:root:/root:/bin/bash
252 user:x:500:500::/home/user:/bin/bash
253
254 "?" An "?" between an option and a group of options means that
255 at least one of them is required to occur if the first option
256 occurs in preceding command line arguments.
257
258 For example from "id" applet:
259
260 // Don't allow -n -r -rn -ug -rug -nug -rnug
261 opt_complementary = "r?ug:n?ug:?u--g:g--u";
262 flags = getopt32(argc, argv, "rnug");
263
264 This example allowed only:
265 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
266
267 "X" A opt_complementary group with just a single letter means
268 that this option is required. If more than one such group exists,
269 at least one option is required to occur (not all of them).
270 For example from "start-stop-daemon" applet:
271
272 // Don't allow -KS -SK, but -S or -K is required
273 opt_complementary = "K:S:?K--S:S--K";
274 flags = getopt32(argc, argv, "KS...);
275
276
277 Don't forget to use ':'. For example, "?322-22-23X-x-a"
278 is interpreted as "?3:22:-2:2-2:2-3Xa:2--x" -
279 max 3 args; count uses of '-2'; min 2 args; if there is
280 a '-2' option then unset '-3', '-X' and '-a'; if there is
281 a '-2' and after it a '-x' then error out.
282*/
283
284/* Code here assumes that 'unsigned' is at least 32 bits wide */
285
286const char *opt_complementary;
287
288typedef struct {
289 int opt;
290 int list_flg;
291 unsigned switch_on;
292 unsigned switch_off;
293 unsigned incongruously;
294 unsigned requires;
295 void **optarg; /* char **optarg or llist_t **optarg */
296 int *counter;
297} t_complementary;
298
299/* You can set applet_long_options for parse called long options */
300#if ENABLE_GETOPT_LONG
301static const struct option bb_default_long_options[] = {
302/* { "help", 0, NULL, '?' }, */
303 { 0, 0, 0, 0 }
304};
305
306const struct option *applet_long_options = bb_default_long_options;
307#endif
308
309uint32_t option_mask32;
310
311uint32_t
312getopt32(int argc, char **argv, const char *applet_opts, ...)
313{
314 unsigned flags = 0;
315 unsigned requires = 0;
316 t_complementary complementary[33];
317 int c;
318 const unsigned char *s;
319 t_complementary *on_off;
320 va_list p;
321#if ENABLE_GETOPT_LONG
322 const struct option *l_o;
323#endif
324 unsigned trigger;
325 char **pargv = NULL;
326 int min_arg = 0;
327 int max_arg = -1;
328
329#define SHOW_USAGE_IF_ERROR 1
330#define ALL_ARGV_IS_OPTS 2
331#define FIRST_ARGV_IS_OPT 4
332#define FREE_FIRST_ARGV_IS_OPT 8
333 int spec_flgs = 0;
334
335 va_start(p, applet_opts);
336
337 c = 0;
338 on_off = complementary;
339 memset(on_off, 0, sizeof(complementary));
340
341 /* skip GNU extension */
342 s = (const unsigned char *)applet_opts;
343 if (*s == '+' || *s == '-')
344 s++;
345 while (*s) {
346 if (c >= 32) break;
347 on_off->opt = *s;
348 on_off->switch_on = (1 << c);
349 if (*++s == ':') {
350 on_off->optarg = va_arg(p, void **);
351 while (*++s == ':') /* skip */;
352 }
353 on_off++;
354 c++;
355 }
356
357#if ENABLE_GETOPT_LONG
358 for (l_o = applet_long_options; l_o->name; l_o++) {
359 if (l_o->flag)
360 continue;
361 for (on_off = complementary; on_off->opt != 0; on_off++)
362 if (on_off->opt == l_o->val)
363 goto next_long;
364 if (c >= 32) break;
365 on_off->opt = l_o->val;
366 on_off->switch_on = (1 << c);
367 if (l_o->has_arg != no_argument)
368 on_off->optarg = va_arg(p, void **);
369 c++;
370 next_long: ;
371 }
372#endif /* ENABLE_GETOPT_LONG */
373 for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
374 t_complementary *pair;
375 unsigned *pair_switch;
376
377 if (*s == ':')
378 continue;
379 c = s[1];
380 if (*s == '?') {
381 if (c < '0' || c > '9') {
382 spec_flgs |= SHOW_USAGE_IF_ERROR;
383 } else {
384 max_arg = c - '0';
385 s++;
386 }
387 continue;
388 }
389 if (*s == '-') {
390 if (c < '0' || c > '9') {
391 if (c == '-') {
392 spec_flgs |= FIRST_ARGV_IS_OPT;
393 s++;
394 } else
395 spec_flgs |= ALL_ARGV_IS_OPTS;
396 } else {
397 min_arg = c - '0';
398 s++;
399 }
400 continue;
401 }
402 if (*s == '=') {
403 min_arg = max_arg = c - '0';
404 s++;
405 continue;
406 }
407 for (on_off = complementary; on_off->opt; on_off++)
408 if (on_off->opt == *s)
409 break;
410 if (c == ':' && s[2] == ':') {
411 on_off->list_flg++;
412 continue;
413 }
414 if (c == ':' || c == '\0') {
415 requires |= on_off->switch_on;
416 continue;
417 }
418 if (c == '-' && (s[2] == ':' || s[2] == '\0')) {
419 flags |= on_off->switch_on;
420 on_off->incongruously |= on_off->switch_on;
421 s++;
422 continue;
423 }
424 if (c == *s) {
425 on_off->counter = va_arg(p, int *);
426 s++;
427 }
428 pair = on_off;
429 pair_switch = &(pair->switch_on);
430 for (s++; *s && *s != ':'; s++) {
431 if (*s == '?') {
432 pair_switch = &(pair->requires);
433 } else if (*s == '-') {
434 if (pair_switch == &(pair->switch_off))
435 pair_switch = &(pair->incongruously);
436 else
437 pair_switch = &(pair->switch_off);
438 } else {
439 for (on_off = complementary; on_off->opt; on_off++)
440 if (on_off->opt == *s) {
441 *pair_switch |= on_off->switch_on;
442 break;
443 }
444 }
445 }
446 s--;
447 }
448 va_end (p);
449
450#if ENABLE_AR || ENABLE_TAR
451 if (spec_flgs & FIRST_ARGV_IS_OPT) {
452 if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
453 argv[1] = xasprintf("-%s", argv[1]);
454 if (ENABLE_FEATURE_CLEAN_UP)
455 spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
456 }
457 }
458#endif
459 /* Note: just "getopt() <= 0" will not work good for
460 * "fake" short options, like this one:
461 * wget $'-\203' "Test: test" http://kernel.org/
462 * (supposed to act as --header, but doesn't) */
463#if ENABLE_GETOPT_LONG
464 while ((c = getopt_long(argc, argv, applet_opts,
465 applet_long_options, NULL)) != -1) {
466#else
467 while ((c = getopt(argc, argv, applet_opts)) != -1) {
468#endif /* ENABLE_GETOPT_LONG */
469 c &= 0xff; /* fight libc's sign extends */
470loop_arg_is_opt:
471 for (on_off = complementary; on_off->opt != c; on_off++) {
472 /* c==0 if long opt have non NULL flag */
473 if (on_off->opt == 0 && c != 0)
474 bb_show_usage();
475 }
476 if (flags & on_off->incongruously) {
477 if ((spec_flgs & SHOW_USAGE_IF_ERROR))
478 bb_show_usage();
479 flags |= BB_GETOPT_ERROR;
480 }
481 trigger = on_off->switch_on & on_off->switch_off;
482 flags &= ~(on_off->switch_off ^ trigger);
483 flags |= on_off->switch_on ^ trigger;
484 flags ^= trigger;
485 if (on_off->counter)
486 (*(on_off->counter))++;
487 if (on_off->list_flg) {
488 llist_add_to((llist_t **)(on_off->optarg), optarg);
489 } else if (on_off->optarg) {
490 *(char **)(on_off->optarg) = optarg;
491 }
492 if (pargv != NULL)
493 break;
494 }
495
496 if (spec_flgs & ALL_ARGV_IS_OPTS) {
497 /* process argv is option, for example "ps" applet */
498 if (pargv == NULL)
499 pargv = argv + optind;
500 while (*pargv) {
501 c = **pargv;
502 if (c == '\0') {
503 pargv++;
504 } else {
505 (*pargv)++;
506 goto loop_arg_is_opt;
507 }
508 }
509 }
510
511#if (ENABLE_AR || ENABLE_TAR) && ENABLE_FEATURE_CLEAN_UP
512 if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)
513 free(argv[1]);
514#endif
515 /* check depending requires for given options */
516 for (on_off = complementary; on_off->opt; on_off++) {
517 if (on_off->requires && (flags & on_off->switch_on) &&
518 (flags & on_off->requires) == 0)
519 bb_show_usage();
520 }
521 if (requires && (flags & requires) == 0)
522 bb_show_usage();
523 argc -= optind;
524 if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
525 bb_show_usage();
526
527 option_mask32 = flags;
528 return flags;
529}
diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c
new file mode 100644
index 000000000..1e6908d82
--- /dev/null
+++ b/libbb/herror_msg.c
@@ -0,0 +1,22 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdarg.h>
11#include <stdlib.h>
12
13#include "libbb.h"
14
15void bb_herror_msg(const char *s, ...)
16{
17 va_list p;
18
19 va_start(p, s);
20 bb_vherror_msg(s, p);
21 va_end(p);
22}
diff --git a/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c
new file mode 100644
index 000000000..f62ddd2ea
--- /dev/null
+++ b/libbb/herror_msg_and_die.c
@@ -0,0 +1,25 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdarg.h>
11#include <stdlib.h>
12
13#include "libbb.h"
14
15void bb_herror_msg_and_die(const char *s, ...)
16{
17 va_list p;
18
19 va_start(p, s);
20 bb_vherror_msg(s, p);
21 va_end(p);
22 if (die_sleep)
23 sleep(die_sleep);
24 exit(xfunc_error_retval);
25}
diff --git a/libbb/human_readable.c b/libbb/human_readable.c
new file mode 100644
index 000000000..ff1b55141
--- /dev/null
+++ b/libbb/human_readable.c
@@ -0,0 +1,89 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * June 30, 2001 Manuel Novoa III
4 *
5 * All-integer version (hey, not everyone has floating point) of
6 * make_human_readable_str, modified from similar code I had written
7 * for busybox several months ago.
8 *
9 * Notes:
10 * 1) I'm using an unsigned long long to hold the product size * block_size,
11 * as df (which calls this routine) could request a representation of a
12 * partition size in bytes > max of unsigned long. If long longs aren't
13 * available, it would be possible to do what's needed using polynomial
14 * representations (say, powers of 1024) and manipulating coefficients.
15 * The base ten "bytes" output could be handled similarly.
16 *
17 * 2) This routine always outputs a decimal point and a tenths digit when
18 * display_unit != 0. Hence, it isn't uncommon for the returned string
19 * to have a length of 5 or 6.
20 *
21 * It might be nice to add a flag to indicate no decimal digits in
22 * that case. This could be either an additional parameter, or a
23 * special value of display_unit. Such a flag would also be nice for du.
24 *
25 * Some code to omit the decimal point and tenths digit is sketched out
26 * and "#if 0"'d below.
27 */
28
29#include <stdio.h>
30#include "libbb.h"
31
32const char *make_human_readable_str(unsigned long long size,
33 unsigned long block_size, unsigned long display_unit)
34{
35 /* The code will adjust for additional (appended) units. */
36 static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' };
37 static const char fmt[] = "%llu";
38 static const char fmt_tenths[] = "%llu.%d%c";
39
40 static char str[21]; /* Sufficient for 64 bit unsigned integers. */
41
42 unsigned long long val;
43 int frac;
44 const char *u;
45 const char *f;
46
47 u = zero_and_units;
48 f = fmt;
49 frac = 0;
50
51 val = size * block_size;
52 if (val == 0) {
53 return u;
54 }
55
56 if (display_unit) {
57 val += display_unit/2; /* Deal with rounding. */
58 val /= display_unit; /* Don't combine with the line above!!! */
59 } else {
60 ++u;
61 while ((val >= 1024)
62 && (u < zero_and_units + sizeof(zero_and_units) - 1)
63 ) {
64 f = fmt_tenths;
65 ++u;
66 frac = (((int)(val % 1024)) * 10 + 1024/2) / 1024;
67 val /= 1024;
68 }
69 if (frac >= 10) { /* We need to round up here. */
70 ++val;
71 frac = 0;
72 }
73#if 0
74 /* Sample code to omit decimal point and tenths digit. */
75 if ( /* no_tenths */ 1 ) {
76 if ( frac >= 5 ) {
77 ++val;
78 }
79 f = "%llu%*c" /* fmt_no_tenths */ ;
80 frac = 1;
81 }
82#endif
83 }
84
85 /* If f==fmt then 'frac' and 'u' are ignored. */
86 snprintf(str, sizeof(str), f, val, frac, *u);
87
88 return str;
89}
diff --git a/libbb/inet_common.c b/libbb/inet_common.c
new file mode 100644
index 000000000..d8e00353e
--- /dev/null
+++ b/libbb/inet_common.c
@@ -0,0 +1,235 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * stolen from net-tools-1.59 and stripped down for busybox by
4 * Erik Andersen <andersen@codepoet.org>
5 *
6 * Heavily modified by Manuel Novoa III Mar 12, 2001
7 *
8 * Version: $Id: inet_common.c,v 1.8 2004/03/10 07:42:38 mjn3 Exp $
9 *
10 */
11
12#include "libbb.h"
13#include "inet_common.h"
14
15int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)
16{
17 struct hostent *hp;
18 struct netent *np;
19
20 /* Grmpf. -FvK */
21 s_in->sin_family = AF_INET;
22 s_in->sin_port = 0;
23
24 /* Default is special, meaning 0.0.0.0. */
25 if (!strcmp(name, bb_str_default)) {
26 s_in->sin_addr.s_addr = INADDR_ANY;
27 return 1;
28 }
29 /* Look to see if it's a dotted quad. */
30 if (inet_aton(name, &s_in->sin_addr)) {
31 return 0;
32 }
33 /* If we expect this to be a hostname, try hostname database first */
34#ifdef DEBUG
35 if (hostfirst) {
36 bb_error_msg("gethostbyname (%s)", name);
37 }
38#endif
39 if (hostfirst && (hp = gethostbyname(name)) != (struct hostent *) NULL) {
40 memcpy((char *) &s_in->sin_addr, (char *) hp->h_addr_list[0],
41 sizeof(struct in_addr));
42 return 0;
43 }
44 /* Try the NETWORKS database to see if this is a known network. */
45#ifdef DEBUG
46 bb_error_msg("getnetbyname (%s)", name);
47#endif
48 if ((np = getnetbyname(name)) != (struct netent *) NULL) {
49 s_in->sin_addr.s_addr = htonl(np->n_net);
50 return 1;
51 }
52 if (hostfirst) {
53 /* Don't try again */
54 return -1;
55 }
56#ifdef DEBUG
57 res_init();
58 _res.options |= RES_DEBUG;
59#endif
60
61#ifdef DEBUG
62 bb_error_msg("gethostbyname (%s)", name);
63#endif
64 if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
65 return -1;
66 }
67 memcpy((char *) &s_in->sin_addr, (char *) hp->h_addr_list[0],
68 sizeof(struct in_addr));
69
70 return 0;
71}
72
73/* cache */
74struct addr {
75 struct sockaddr_in addr;
76 char *name;
77 int host;
78 struct addr *next;
79};
80
81static struct addr *INET_nn = NULL; /* addr-to-name cache */
82
83/* numeric: & 0x8000: default instead of *,
84 * & 0x4000: host instead of net,
85 * & 0x0fff: don't resolve
86 */
87int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in,
88 int numeric, unsigned int netmask)
89{
90 struct hostent *ent;
91 struct netent *np;
92 struct addr *pn;
93 unsigned long ad, host_ad;
94 int host = 0;
95
96 /* Grmpf. -FvK */
97 if (s_in->sin_family != AF_INET) {
98#ifdef DEBUG
99 bb_error_msg("rresolve: unsupport address family %d !",
100 s_in->sin_family);
101#endif
102 errno = EAFNOSUPPORT;
103 return -1;
104 }
105 ad = (unsigned long) s_in->sin_addr.s_addr;
106#ifdef DEBUG
107 bb_error_msg("rresolve: %08lx, mask %08x, num %08x", ad, netmask, numeric);
108#endif
109 if (ad == INADDR_ANY) {
110 if ((numeric & 0x0FFF) == 0) {
111 if (numeric & 0x8000)
112 safe_strncpy(name, bb_str_default, len);
113 else
114 safe_strncpy(name, "*", len);
115 return 0;
116 }
117 }
118 if (numeric & 0x0FFF) {
119 safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
120 return 0;
121 }
122
123 if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
124 host = 1;
125 pn = INET_nn;
126 while (pn != NULL) {
127 if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
128 safe_strncpy(name, pn->name, len);
129#ifdef DEBUG
130 bb_error_msg("rresolve: found %s %08lx in cache",
131 (host ? "host" : "net"), ad);
132#endif
133 return 0;
134 }
135 pn = pn->next;
136 }
137
138 host_ad = ntohl(ad);
139 np = NULL;
140 ent = NULL;
141 if (host) {
142#ifdef DEBUG
143 bb_error_msg("gethostbyaddr (%08lx)", ad);
144#endif
145 ent = gethostbyaddr((char *) &ad, 4, AF_INET);
146 if (ent != NULL) {
147 safe_strncpy(name, ent->h_name, len);
148 }
149 } else {
150#ifdef DEBUG
151 bb_error_msg("getnetbyaddr (%08lx)", host_ad);
152#endif
153 np = getnetbyaddr(host_ad, AF_INET);
154 if (np != NULL) {
155 safe_strncpy(name, np->n_name, len);
156 }
157 }
158 if ((ent == NULL) && (np == NULL)) {
159 safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
160 }
161 pn = (struct addr *) xmalloc(sizeof(struct addr));
162 pn->addr = *s_in;
163 pn->next = INET_nn;
164 pn->host = host;
165 pn->name = xstrdup(name);
166 INET_nn = pn;
167
168 return 0;
169}
170
171#ifdef CONFIG_FEATURE_IPV6
172
173int INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
174{
175 struct addrinfo req, *ai;
176 int s;
177
178 memset(&req, '\0', sizeof req);
179 req.ai_family = AF_INET6;
180 s = getaddrinfo(name, NULL, &req, &ai);
181 if (s) {
182 bb_error_msg("getaddrinfo: %s: %d", name, s);
183 return -1;
184 }
185 memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));
186
187 freeaddrinfo(ai);
188
189 return 0;
190}
191
192#ifndef IN6_IS_ADDR_UNSPECIFIED
193# define IN6_IS_ADDR_UNSPECIFIED(a) \
194 (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \
195 ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0)
196#endif
197
198
199int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6,
200 int numeric)
201{
202 int s;
203
204 /* Grmpf. -FvK */
205 if (sin6->sin6_family != AF_INET6) {
206#ifdef DEBUG
207 bb_error_msg("rresolve: unsupport address family %d!",
208 sin6->sin6_family);
209#endif
210 errno = EAFNOSUPPORT;
211 return -1;
212 }
213 if (numeric & 0x7FFF) {
214 inet_ntop(AF_INET6, &sin6->sin6_addr, name, len);
215 return 0;
216 }
217 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
218 if (numeric & 0x8000) {
219 strcpy(name, bb_str_default);
220 } else {
221 name[0] = '*';
222 name[1] = '\0';
223 }
224 return 0;
225 }
226
227 s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), name, len, NULL, 0, 0);
228 if (s) {
229 bb_error_msg("getnameinfo failed");
230 return -1;
231 }
232 return 0;
233}
234
235#endif /* CONFIG_FEATURE_IPV6 */
diff --git a/libbb/info_msg.c b/libbb/info_msg.c
new file mode 100644
index 000000000..78d5c8f32
--- /dev/null
+++ b/libbb/info_msg.c
@@ -0,0 +1,23 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <errno.h>
12#include <string.h>
13#include <stdlib.h>
14#include "libbb.h"
15
16void bb_info_msg(const char *s, ...)
17{
18 va_list p;
19
20 va_start(p, s);
21 bb_vinfo_msg(s, p);
22 va_end(p);
23}
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
new file mode 100644
index 000000000..2ac1623f4
--- /dev/null
+++ b/libbb/inode_hash.c
@@ -0,0 +1,88 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people.
6 * If you wrote this, please acknowledge your work.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include "libbb.h"
15
16#define HASH_SIZE 311 /* Should be prime */
17#define hash_inode(i) ((i) % HASH_SIZE)
18
19typedef struct ino_dev_hash_bucket_struct {
20 struct ino_dev_hash_bucket_struct *next;
21 ino_t ino;
22 dev_t dev;
23 char name[1];
24} ino_dev_hashtable_bucket_t;
25
26static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
27
28/*
29 * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
30 * `ino_dev_hashtable', else return 0
31 *
32 * If NAME is a non-NULL pointer to a character pointer, and there is
33 * a match, then set *NAME to the value of the name slot in that
34 * bucket.
35 */
36int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
37{
38 ino_dev_hashtable_bucket_t *bucket;
39
40 bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
41 while (bucket != NULL) {
42 if ((bucket->ino == statbuf->st_ino) &&
43 (bucket->dev == statbuf->st_dev))
44 {
45 if (name) *name = bucket->name;
46 return 1;
47 }
48 bucket = bucket->next;
49 }
50 return 0;
51}
52
53/* Add statbuf to statbuf hash table */
54void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
55{
56 int i;
57 size_t s;
58 ino_dev_hashtable_bucket_t *bucket;
59
60 i = hash_inode(statbuf->st_ino);
61 s = name ? strlen(name) : 0;
62 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
63 bucket->ino = statbuf->st_ino;
64 bucket->dev = statbuf->st_dev;
65 if (name)
66 strcpy(bucket->name, name);
67 else
68 bucket->name[0] = '\0';
69 bucket->next = ino_dev_hashtable[i];
70 ino_dev_hashtable[i] = bucket;
71}
72
73#ifdef CONFIG_FEATURE_CLEAN_UP
74/* Clear statbuf hash table */
75void reset_ino_dev_hashtable(void)
76{
77 int i;
78 ino_dev_hashtable_bucket_t *bucket;
79
80 for (i = 0; i < HASH_SIZE; i++) {
81 while (ino_dev_hashtable[i] != NULL) {
82 bucket = ino_dev_hashtable[i]->next;
83 free(ino_dev_hashtable[i]);
84 ino_dev_hashtable[i] = bucket;
85 }
86 }
87}
88#endif
diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c
new file mode 100644
index 000000000..b35919869
--- /dev/null
+++ b/libbb/isdirectory.c
@@ -0,0 +1,39 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
6 * Permission has been granted to redistribute this code under the GPL.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include <sys/stat.h>
12#include "libbb.h"
13
14/*
15 * Return TRUE if a fileName is a directory.
16 * Nonexistent files return FALSE.
17 */
18int is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
19{
20 int status;
21 struct stat astatBuf;
22
23 if (statBuf == NULL) {
24 /* set from auto stack buffer */
25 statBuf = &astatBuf;
26 }
27
28 if (followLinks)
29 status = stat(fileName, statBuf);
30 else
31 status = lstat(fileName, statBuf);
32
33 if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
34 status = FALSE;
35 }
36 else status = TRUE;
37
38 return status;
39}
diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c
new file mode 100644
index 000000000..50b82ae18
--- /dev/null
+++ b/libbb/kernel_version.c
@@ -0,0 +1,37 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <sys/utsname.h> /* for uname(2) */
11
12#include "libbb.h"
13
14/* Returns current kernel version encoded as major*65536 + minor*256 + patch,
15 * so, for example, to check if the kernel is greater than 2.2.11:
16 *
17 * if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { <stuff> }
18 */
19int get_linux_version_code(void)
20{
21 struct utsname name;
22 char *s;
23 int i, r;
24
25 if (uname(&name) == -1) {
26 bb_perror_msg("cannot get system information");
27 return 0;
28 }
29
30 s = name.release;
31 r = 0;
32 for (i = 0; i < 3; i++) {
33 r = r * 256 + atoi(strtok(s, "."));
34 s = NULL;
35 }
36 return r;
37}
diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c
new file mode 100644
index 000000000..3616d5916
--- /dev/null
+++ b/libbb/last_char_is.c
@@ -0,0 +1,24 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * busybox library eXtended function
4 *
5 * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12/* Find out if the last character of a string matches the one given Don't
13 * underrun the buffer if the string length is 0. Also avoids a possible
14 * space-hogging inline of strlen() per usage.
15 */
16char* last_char_is(const char *s, int c)
17{
18 if (s) {
19 s = strrchr(s, c);
20 if (s && !s[1])
21 return (char*)s;
22 }
23 return NULL;
24}
diff --git a/libbb/llist.c b/libbb/llist.c
new file mode 100644
index 000000000..8a74832ee
--- /dev/null
+++ b/libbb/llist.c
@@ -0,0 +1,78 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * linked list helper functions.
4 *
5 * Copyright (C) 2003 Glenn McGrath
6 * Copyright (C) 2005 Vladimir Oleynik
7 * Copyright (C) 2005 Bernhard Fischer
8 * Copyright (C) 2006 Rob Landley <rob@landley.net>
9 *
10 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
11 */
12
13#include <stdlib.h>
14#include "libbb.h"
15
16/* Add data to the start of the linked list. */
17void llist_add_to(llist_t **old_head, void *data)
18{
19 llist_t *new_head = xmalloc(sizeof(llist_t));
20 new_head->data = data;
21 new_head->link = *old_head;
22 *old_head = new_head;
23}
24
25/* Add data to the end of the linked list. */
26void llist_add_to_end(llist_t **list_head, void *data)
27{
28 llist_t *new_item = xmalloc(sizeof(llist_t));
29 new_item->data = data;
30 new_item->link = NULL;
31
32 if (!*list_head) *list_head = new_item;
33 else {
34 llist_t *tail = *list_head;
35 while (tail->link) tail = tail->link;
36 tail->link = new_item;
37 }
38}
39
40/* Remove first element from the list and return it */
41void *llist_pop(llist_t **head)
42{
43 void *data;
44
45 if(!*head) data = *head;
46 else {
47 void *next = (*head)->link;
48 data = (*head)->data;
49 free(*head);
50 *head = next;
51 }
52
53 return data;
54}
55
56/* Recursively free all elements in the linked list. If freeit != NULL
57 * call it on each datum in the list */
58void llist_free(llist_t *elm, void (*freeit)(void *data))
59{
60 while (elm) {
61 void *data = llist_pop(&elm);
62 if (freeit) freeit(data);
63 }
64}
65
66/* Reverse list order. Useful since getopt32 saves option params
67 * in reverse order */
68llist_t* rev_llist(llist_t *list)
69{
70 llist_t *new = NULL;
71 while (list) {
72 llist_t *next = list->link;
73 list->link = new;
74 new = list;
75 list = next;
76 }
77 return new;
78}
diff --git a/libbb/login.c b/libbb/login.c
new file mode 100644
index 000000000..6ebb9a6a0
--- /dev/null
+++ b/libbb/login.c
@@ -0,0 +1,105 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * issue.c: issue printing code
4 *
5 * Copyright (C) 2003 Bastian Blank <waldi@tuxbox.org>
6 *
7 * Optimize and correcting OCRNL by Vladimir Oleynik <dzo@simtreas.ru>
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10 */
11
12#include <sys/param.h> /* MAXHOSTNAMELEN */
13#include <stdio.h>
14#include <unistd.h>
15#include "libbb.h"
16
17#include <sys/utsname.h>
18#include <time.h>
19
20#define LOGIN " login: "
21
22static const char fmtstr_d[] = "%A, %d %B %Y";
23static const char fmtstr_t[] = "%H:%M:%S";
24
25void print_login_issue(const char *issue_file, const char *tty)
26{
27 FILE *fd;
28 int c;
29 char buf[256+1];
30 const char *outbuf;
31 time_t t;
32 struct utsname uts;
33
34 time(&t);
35 uname(&uts);
36
37 puts("\r"); /* start a new line */
38
39 fd = fopen(issue_file, "r");
40 if (!fd)
41 return;
42 while ((c = fgetc(fd)) != EOF) {
43 outbuf = buf;
44 buf[0] = c;
45 buf[1] = '\0';
46 if(c == '\n') {
47 buf[1] = '\r';
48 buf[2] = '\0';
49 }
50 if (c == '\\' || c == '%') {
51 c = fgetc(fd);
52 switch (c) {
53 case 's':
54 outbuf = uts.sysname;
55 break;
56 case 'n':
57 outbuf = uts.nodename;
58 break;
59 case 'r':
60 outbuf = uts.release;
61 break;
62 case 'v':
63 outbuf = uts.version;
64 break;
65 case 'm':
66 outbuf = uts.machine;
67 break;
68 case 'D':
69 case 'o':
70 c = getdomainname(buf, sizeof(buf) - 1);
71 buf[c >= 0 ? c : 0] = '\0';
72 break;
73 case 'd':
74 strftime(buf, sizeof(buf), fmtstr_d, localtime(&t));
75 break;
76 case 't':
77 strftime(buf, sizeof(buf), fmtstr_t, localtime(&t));
78 break;
79 case 'h':
80 gethostname(buf, sizeof(buf) - 1);
81 buf[sizeof(buf) - 1] = '\0';
82 break;
83 case 'l':
84 outbuf = tty;
85 break;
86 default:
87 buf[0] = c;
88 }
89 }
90 fputs(outbuf, stdout);
91 }
92 fclose(fd);
93 fflush(stdout);
94}
95
96void print_login_prompt(void)
97{
98 char buf[MAXHOSTNAMELEN+1];
99
100 if (gethostname(buf, MAXHOSTNAMELEN) == 0)
101 fputs(buf, stdout);
102
103 fputs(LOGIN, stdout);
104 fflush(stdout);
105}
diff --git a/libbb/loop.c b/libbb/loop.c
new file mode 100644
index 000000000..14835ec24
--- /dev/null
+++ b/libbb/loop.c
@@ -0,0 +1,149 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
7 *
8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
9 */
10
11#include "libbb.h"
12
13/* For 2.6, use the cleaned up header to get the 64 bit API. */
14#include <linux/version.h>
15#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
16#include <linux/loop.h>
17typedef struct loop_info64 bb_loop_info;
18#define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
19#define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
20
21/* For 2.4 and earlier, use the 32 bit API (and don't trust the headers) */
22#else
23/* Stuff stolen from linux/loop.h for 2.4 and earlier kernels*/
24#include <linux/posix_types.h>
25#define LO_NAME_SIZE 64
26#define LO_KEY_SIZE 32
27#define LOOP_SET_FD 0x4C00
28#define LOOP_CLR_FD 0x4C01
29#define BB_LOOP_SET_STATUS 0x4C02
30#define BB_LOOP_GET_STATUS 0x4C03
31typedef struct {
32 int lo_number;
33 __kernel_dev_t lo_device;
34 unsigned long lo_inode;
35 __kernel_dev_t lo_rdevice;
36 int lo_offset;
37 int lo_encrypt_type;
38 int lo_encrypt_key_size;
39 int lo_flags;
40 char lo_file_name[LO_NAME_SIZE];
41 unsigned char lo_encrypt_key[LO_KEY_SIZE];
42 unsigned long lo_init[2];
43 char reserved[4];
44} bb_loop_info;
45#endif
46
47char *query_loop(const char *device)
48{
49 int fd;
50 bb_loop_info loopinfo;
51 char *dev = 0;
52
53 fd = open(device, O_RDONLY);
54 if (fd < 0) return 0;
55 if (!ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo))
56 dev = xasprintf("%ld %s", (long) loopinfo.lo_offset,
57 (char *)loopinfo.lo_file_name);
58 close(fd);
59
60 return dev;
61}
62
63
64int del_loop(const char *device)
65{
66 int fd, rc;
67
68 fd = open(device, O_RDONLY);
69 if (fd < 0) return 1;
70 rc = ioctl(fd, LOOP_CLR_FD, 0);
71 close(fd);
72
73 return rc;
74}
75
76/* Returns 0 if mounted RW, 1 if mounted read-only, <0 for error.
77 *device is loop device to use, or if *device==NULL finds a loop device to
78 mount it on and sets *device to a strdup of that loop device name. This
79 search will re-use an existing loop device already bound to that
80 file/offset if it finds one.
81 */
82int set_loop(char **device, const char *file, unsigned long long offset)
83{
84 char dev[20], *try;
85 bb_loop_info loopinfo;
86 struct stat statbuf;
87 int i, dfd, ffd, mode, rc=-1;
88
89 /* Open the file. Barf if this doesn't work. */
90 mode = O_RDWR;
91 ffd = open(file, mode);
92 if (ffd < 0) {
93 mode = O_RDONLY;
94 ffd = open(file, mode);
95 if (ffd < 0)
96 return -errno;
97 }
98
99 /* Find a loop device. */
100 try = *device ? : dev;
101 for (i=0;rc;i++) {
102 sprintf(dev, LOOP_FORMAT, i);
103
104 /* Ran out of block devices, return failure. */
105 if (stat(try, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
106 rc=-ENOENT;
107 break;
108 }
109 /* Open the sucker and check its loopiness. */
110 dfd = open(try, mode);
111 if (dfd < 0 && errno == EROFS) {
112 mode = O_RDONLY;
113 dfd = open(try, mode);
114 }
115 if (dfd < 0) goto try_again;
116
117 rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
118
119 /* If device free, claim it. */
120 if (rc && errno == ENXIO) {
121 memset(&loopinfo, 0, sizeof(loopinfo));
122 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
123 loopinfo.lo_offset = offset;
124 /* Associate free loop device with file. */
125 if (!ioctl(dfd, LOOP_SET_FD, ffd)) {
126 if (!ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo)) rc = 0;
127 else ioctl(dfd, LOOP_CLR_FD, 0);
128 }
129
130 /* If this block device already set up right, re-use it.
131 (Yes this is racy, but associating two loop devices with the same
132 file isn't pretty either. In general, mounting the same file twice
133 without using losetup manually is problematic.)
134 */
135 } else if (strcmp(file,(char *)loopinfo.lo_file_name)
136 || offset != loopinfo.lo_offset) {
137 rc = -1;
138 }
139 close(dfd);
140try_again:
141 if (*device) break;
142 }
143 close(ffd);
144 if (!rc) {
145 if (!*device) *device = strdup(dev);
146 return mode==O_RDONLY ? 1 : 0;
147 }
148 return rc;
149}
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
new file mode 100644
index 000000000..fbec4e20e
--- /dev/null
+++ b/libbb/make_directory.c
@@ -0,0 +1,104 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * parse_mode implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* Mar 5, 2003 Manuel Novoa III
11 *
12 * This is the main work function for the 'mkdir' applet. As such, it
13 * strives to be SUSv3 compliant in it's behaviour when recursively
14 * making missing parent dirs, and in it's mode setting of the final
15 * directory 'path'.
16 *
17 * To recursively build all missing intermediate directories, make
18 * sure that (flags & FILEUTILS_RECUR) is non-zero. Newly created
19 * intermediate directories will have at least u+wx perms.
20 *
21 * To set specific permissions on 'path', pass the appropriate 'mode'
22 * val. Otherwise, pass -1 to get default permissions.
23 */
24
25#include <errno.h>
26#include <unistd.h>
27#include <sys/stat.h>
28#include "libbb.h"
29
30int bb_make_directory (char *path, long mode, int flags)
31{
32 mode_t mask;
33 const char *fail_msg;
34 char *s = path;
35 char c;
36 struct stat st;
37
38 mask = umask(0);
39 if (mode == -1) {
40 umask(mask);
41 mode = (S_IXUSR | S_IXGRP | S_IXOTH |
42 S_IWUSR | S_IWGRP | S_IWOTH |
43 S_IRUSR | S_IRGRP | S_IROTH) & ~mask;
44 } else {
45 umask(mask & ~0300);
46 }
47
48 do {
49 c = 0;
50
51 if (flags & FILEUTILS_RECUR) { /* Get the parent. */
52 /* Bypass leading non-'/'s and then subsequent '/'s. */
53 while (*s) {
54 if (*s == '/') {
55 do {
56 ++s;
57 } while (*s == '/');
58 c = *s; /* Save the current char */
59 *s = 0; /* and replace it with nul. */
60 break;
61 }
62 ++s;
63 }
64 }
65
66 if (mkdir(path, 0777) < 0) {
67 /* If we failed for any other reason than the directory
68 * already exists, output a diagnostic and return -1.*/
69 if (errno != EEXIST
70 || !(flags & FILEUTILS_RECUR)
71 || (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
72 fail_msg = "create";
73 umask(mask);
74 break;
75 }
76 /* Since the directory exists, don't attempt to change
77 * permissions if it was the full target. Note that
78 * this is not an error conditon. */
79 if (!c) {
80 umask(mask);
81 return 0;
82 }
83 }
84
85 if (!c) {
86 /* Done. If necessary, updated perms on the newly
87 * created directory. Failure to update here _is_
88 * an error.*/
89 umask(mask);
90 if ((mode != -1) && (chmod(path, mode) < 0)){
91 fail_msg = "set permissions of";
92 break;
93 }
94 return 0;
95 }
96
97 /* Remove any inserted nul from the path (recursive mode). */
98 *s = c;
99
100 } while (1);
101
102 bb_perror_msg ("cannot %s directory '%s'", fail_msg, path);
103 return -1;
104}
diff --git a/libbb/makedev.c b/libbb/makedev.c
new file mode 100644
index 000000000..4903e4783
--- /dev/null
+++ b/libbb/makedev.c
@@ -0,0 +1,20 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 2006 Denis Vlasenko
5 *
6 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
7 */
8
9/* We do not include libbb.h - #define makedev() is there! */
10#include <features.h>
11#include <sys/sysmacros.h>
12
13#ifdef __GLIBC__
14/* At least glibc has horrendously large inline for this, so wrap it */
15/* uclibc people please check - do we need "&& !__UCLIBC__" above? */
16unsigned long long bb_makedev(unsigned int major, unsigned int minor)
17{
18 return makedev(major, minor);
19}
20#endif
diff --git a/libbb/md5.c b/libbb/md5.c
new file mode 100644
index 000000000..e672559cf
--- /dev/null
+++ b/libbb/md5.c
@@ -0,0 +1,450 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * md5.c - Compute MD5 checksum of strings according to the
4 * definition of MD5 in RFC 1321 from April 1992.
5 *
6 * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
7 *
8 * Copyright (C) 1995-1999 Free Software Foundation, Inc.
9 * Copyright (C) 2001 Manuel Novoa III
10 * Copyright (C) 2003 Glenn L. McGrath
11 * Copyright (C) 2003 Erik Andersen
12 *
13 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
14 */
15
16#include "libbb.h"
17
18#if CONFIG_MD5_SIZE_VS_SPEED < 0 || CONFIG_MD5_SIZE_VS_SPEED > 3
19# define MD5_SIZE_VS_SPEED 2
20#else
21# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED
22#endif
23
24/* Initialize structure containing state of computation.
25 * (RFC 1321, 3.3: Step 3)
26 */
27void md5_begin(md5_ctx_t *ctx)
28{
29 ctx->A = 0x67452301;
30 ctx->B = 0xefcdab89;
31 ctx->C = 0x98badcfe;
32 ctx->D = 0x10325476;
33
34 ctx->total = 0;
35 ctx->buflen = 0;
36}
37
38/* These are the four functions used in the four steps of the MD5 algorithm
39 * and defined in the RFC 1321. The first function is a little bit optimized
40 * (as found in Colin Plumbs public domain implementation).
41 * #define FF(b, c, d) ((b & c) | (~b & d))
42 */
43# define FF(b, c, d) (d ^ (b & (c ^ d)))
44# define FG(b, c, d) FF (d, b, c)
45# define FH(b, c, d) (b ^ c ^ d)
46# define FI(b, c, d) (c ^ (b | ~d))
47
48/* Hash a single block, 64 bytes long and 4-byte aligned. */
49static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
50{
51 uint32_t correct_words[16];
52 const uint32_t *words = buffer;
53
54# if MD5_SIZE_VS_SPEED > 0
55 static const uint32_t C_array[] = {
56 /* round 1 */
57 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
58 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
59 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
60 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
61 /* round 2 */
62 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
63 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
64 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
65 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
66 /* round 3 */
67 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
68 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
69 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
70 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
71 /* round 4 */
72 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
73 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
74 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
75 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
76 };
77
78 static const char P_array[] = {
79# if MD5_SIZE_VS_SPEED > 1
80 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
81# endif /* MD5_SIZE_VS_SPEED > 1 */
82 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
83 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
84 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
85 };
86
87# if MD5_SIZE_VS_SPEED > 1
88 static const char S_array[] = {
89 7, 12, 17, 22,
90 5, 9, 14, 20,
91 4, 11, 16, 23,
92 6, 10, 15, 21
93 };
94# endif /* MD5_SIZE_VS_SPEED > 1 */
95# endif
96
97 uint32_t A = ctx->A;
98 uint32_t B = ctx->B;
99 uint32_t C = ctx->C;
100 uint32_t D = ctx->D;
101
102 /* Process all bytes in the buffer with 64 bytes in each round of
103 the loop. */
104 uint32_t *cwp = correct_words;
105 uint32_t A_save = A;
106 uint32_t B_save = B;
107 uint32_t C_save = C;
108 uint32_t D_save = D;
109
110# if MD5_SIZE_VS_SPEED > 1
111# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
112
113 const uint32_t *pc;
114 const char *pp;
115 const char *ps;
116 int i;
117 uint32_t temp;
118
119 for (i = 0; i < 16; i++) {
120 cwp[i] = SWAP_LE32(words[i]);
121 }
122 words += 16;
123
124# if MD5_SIZE_VS_SPEED > 2
125 pc = C_array;
126 pp = P_array;
127 ps = S_array - 4;
128
129 for (i = 0; i < 64; i++) {
130 if ((i & 0x0f) == 0)
131 ps += 4;
132 temp = A;
133 switch (i >> 4) {
134 case 0:
135 temp += FF(B, C, D);
136 break;
137 case 1:
138 temp += FG(B, C, D);
139 break;
140 case 2:
141 temp += FH(B, C, D);
142 break;
143 case 3:
144 temp += FI(B, C, D);
145 }
146 temp += cwp[(int) (*pp++)] + *pc++;
147 CYCLIC(temp, ps[i & 3]);
148 temp += B;
149 A = D;
150 D = C;
151 C = B;
152 B = temp;
153 }
154# else
155 pc = C_array;
156 pp = P_array;
157 ps = S_array;
158
159 for (i = 0; i < 16; i++) {
160 temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++;
161 CYCLIC(temp, ps[i & 3]);
162 temp += B;
163 A = D;
164 D = C;
165 C = B;
166 B = temp;
167 }
168
169 ps += 4;
170 for (i = 0; i < 16; i++) {
171 temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++;
172 CYCLIC(temp, ps[i & 3]);
173 temp += B;
174 A = D;
175 D = C;
176 C = B;
177 B = temp;
178 }
179 ps += 4;
180 for (i = 0; i < 16; i++) {
181 temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++;
182 CYCLIC(temp, ps[i & 3]);
183 temp += B;
184 A = D;
185 D = C;
186 C = B;
187 B = temp;
188 }
189 ps += 4;
190 for (i = 0; i < 16; i++) {
191 temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++;
192 CYCLIC(temp, ps[i & 3]);
193 temp += B;
194 A = D;
195 D = C;
196 C = B;
197 B = temp;
198 }
199
200# endif /* MD5_SIZE_VS_SPEED > 2 */
201# else
202 /* First round: using the given function, the context and a constant
203 the next context is computed. Because the algorithms processing
204 unit is a 32-bit word and it is determined to work on words in
205 little endian byte order we perhaps have to change the byte order
206 before the computation. To reduce the work for the next steps
207 we store the swapped words in the array CORRECT_WORDS. */
208
209# define OP(a, b, c, d, s, T) \
210 do \
211 { \
212 a += FF (b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \
213 ++words; \
214 CYCLIC (a, s); \
215 a += b; \
216 } \
217 while (0)
218
219 /* It is unfortunate that C does not provide an operator for
220 cyclic rotation. Hope the C compiler is smart enough. */
221 /* gcc 2.95.4 seems to be --aaronl */
222# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
223
224 /* Before we start, one word to the strange constants.
225 They are defined in RFC 1321 as
226
227 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
228 */
229
230# if MD5_SIZE_VS_SPEED == 1
231 const uint32_t *pc;
232 const char *pp;
233 int i;
234# endif /* MD5_SIZE_VS_SPEED */
235
236 /* Round 1. */
237# if MD5_SIZE_VS_SPEED == 1
238 pc = C_array;
239 for (i = 0; i < 4; i++) {
240 OP(A, B, C, D, 7, *pc++);
241 OP(D, A, B, C, 12, *pc++);
242 OP(C, D, A, B, 17, *pc++);
243 OP(B, C, D, A, 22, *pc++);
244 }
245# else
246 OP(A, B, C, D, 7, 0xd76aa478);
247 OP(D, A, B, C, 12, 0xe8c7b756);
248 OP(C, D, A, B, 17, 0x242070db);
249 OP(B, C, D, A, 22, 0xc1bdceee);
250 OP(A, B, C, D, 7, 0xf57c0faf);
251 OP(D, A, B, C, 12, 0x4787c62a);
252 OP(C, D, A, B, 17, 0xa8304613);
253 OP(B, C, D, A, 22, 0xfd469501);
254 OP(A, B, C, D, 7, 0x698098d8);
255 OP(D, A, B, C, 12, 0x8b44f7af);
256 OP(C, D, A, B, 17, 0xffff5bb1);
257 OP(B, C, D, A, 22, 0x895cd7be);
258 OP(A, B, C, D, 7, 0x6b901122);
259 OP(D, A, B, C, 12, 0xfd987193);
260 OP(C, D, A, B, 17, 0xa679438e);
261 OP(B, C, D, A, 22, 0x49b40821);
262# endif /* MD5_SIZE_VS_SPEED == 1 */
263
264 /* For the second to fourth round we have the possibly swapped words
265 in CORRECT_WORDS. Redefine the macro to take an additional first
266 argument specifying the function to use. */
267# undef OP
268# define OP(f, a, b, c, d, k, s, T) \
269 do \
270 { \
271 a += f (b, c, d) + correct_words[k] + T; \
272 CYCLIC (a, s); \
273 a += b; \
274 } \
275 while (0)
276
277 /* Round 2. */
278# if MD5_SIZE_VS_SPEED == 1
279 pp = P_array;
280 for (i = 0; i < 4; i++) {
281 OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
282 OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++);
283 OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++);
284 OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++);
285 }
286# else
287 OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
288 OP(FG, D, A, B, C, 6, 9, 0xc040b340);
289 OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
290 OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
291 OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
292 OP(FG, D, A, B, C, 10, 9, 0x02441453);
293 OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
294 OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
295 OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
296 OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
297 OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
298 OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
299 OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
300 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
301 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
302 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
303# endif /* MD5_SIZE_VS_SPEED == 1 */
304
305 /* Round 3. */
306# if MD5_SIZE_VS_SPEED == 1
307 for (i = 0; i < 4; i++) {
308 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
309 OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
310 OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++);
311 OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++);
312 }
313# else
314 OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
315 OP(FH, D, A, B, C, 8, 11, 0x8771f681);
316 OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
317 OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
318 OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
319 OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
320 OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
321 OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
322 OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
323 OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
324 OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
325 OP(FH, B, C, D, A, 6, 23, 0x04881d05);
326 OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
327 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
328 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
329 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
330# endif /* MD5_SIZE_VS_SPEED == 1 */
331
332 /* Round 4. */
333# if MD5_SIZE_VS_SPEED == 1
334 for (i = 0; i < 4; i++) {
335 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
336 OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
337 OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++);
338 OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++);
339 }
340# else
341 OP(FI, A, B, C, D, 0, 6, 0xf4292244);
342 OP(FI, D, A, B, C, 7, 10, 0x432aff97);
343 OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
344 OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
345 OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
346 OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
347 OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
348 OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
349 OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
350 OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
351 OP(FI, C, D, A, B, 6, 15, 0xa3014314);
352 OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
353 OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
354 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
355 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
356 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
357# endif /* MD5_SIZE_VS_SPEED == 1 */
358# endif /* MD5_SIZE_VS_SPEED > 1 */
359
360 /* Add the starting values of the context. */
361 A += A_save;
362 B += B_save;
363 C += C_save;
364 D += D_save;
365
366 /* Put checksum in context given as argument. */
367 ctx->A = A;
368 ctx->B = B;
369 ctx->C = C;
370 ctx->D = D;
371}
372
373/* Feed data through a temporary buffer to call md5_hash_aligned_block()
374 * with chunks of data that are 4-byte aligned and a multiple of 64 bytes.
375 * This function's internal buffer remembers previous data until it has 64
376 * bytes worth to pass on. Call md5_end() to flush this buffer. */
377
378void md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx)
379{
380 char *buf=(char *)buffer;
381
382 /* RFC 1321 specifies the possible length of the file up to 2^64 bits,
383 * Here we only track the number of bytes. */
384
385 ctx->total += len;
386
387 // Process all input.
388
389 while (len) {
390 int i = 64 - ctx->buflen;
391
392 // Copy data into aligned buffer.
393
394 if (i > len) i = len;
395 memcpy(ctx->buffer + ctx->buflen, buf, i);
396 len -= i;
397 ctx->buflen += i;
398 buf += i;
399
400 // When buffer fills up, process it.
401
402 if (ctx->buflen == 64) {
403 md5_hash_block(ctx->buffer, ctx);
404 ctx->buflen = 0;
405 }
406 }
407}
408
409/* Process the remaining bytes in the buffer and put result from CTX
410 * in first 16 bytes following RESBUF. The result is always in little
411 * endian byte order, so that a byte-wise output yields to the wanted
412 * ASCII representation of the message digest.
413 *
414 * IMPORTANT: On some systems it is required that RESBUF is correctly
415 * aligned for a 32 bits value.
416 */
417void *md5_end(void *resbuf, md5_ctx_t *ctx)
418{
419 char *buf = ctx->buffer;
420 int i;
421
422 /* Pad data to block size. */
423
424 buf[ctx->buflen++] = 0x80;
425 memset(buf + ctx->buflen, 0, 128 - ctx->buflen);
426
427 /* Put the 64-bit file length in *bits* at the end of the buffer. */
428 ctx->total <<= 3;
429 if (ctx->buflen > 56) buf += 64;
430 for (i = 0; i < 8; i++) buf[56 + i] = ctx->total >> (i*8);
431
432 /* Process last bytes. */
433 if (buf != ctx->buffer) md5_hash_block(ctx->buffer, ctx);
434 md5_hash_block(buf, ctx);
435
436 /* Put result from CTX in first 16 bytes following RESBUF. The result is
437 * always in little endian byte order, so that a byte-wise output yields
438 * to the wanted ASCII representation of the message digest.
439 *
440 * IMPORTANT: On some systems it is required that RESBUF is correctly
441 * aligned for a 32 bits value.
442 */
443 ((uint32_t *) resbuf)[0] = SWAP_LE32(ctx->A);
444 ((uint32_t *) resbuf)[1] = SWAP_LE32(ctx->B);
445 ((uint32_t *) resbuf)[2] = SWAP_LE32(ctx->C);
446 ((uint32_t *) resbuf)[3] = SWAP_LE32(ctx->D);
447
448 return resbuf;
449}
450
diff --git a/libbb/messages.c b/libbb/messages.c
new file mode 100644
index 000000000..c640faf5b
--- /dev/null
+++ b/libbb/messages.c
@@ -0,0 +1,53 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
6 */
7
8#include "libbb.h"
9
10#ifndef BB_EXTRA_VERSION
11#define BANNER "BusyBox v" BB_VER " (" BB_BT ")"
12#else
13#define BANNER "BusyBox v" BB_VER " (" BB_EXTRA_VERSION ")"
14#endif
15const char BB_BANNER[] = BANNER;
16const char bb_msg_full_version[] = BANNER " multi-call binary";
17
18const char bb_msg_memory_exhausted[] = "memory exhausted";
19const char bb_msg_invalid_date[] = "invalid date '%s'";
20const char bb_msg_write_error[] = "write error";
21const char bb_msg_read_error[] = "read error";
22const char bb_msg_unknown[] = "(unknown)";
23const char bb_msg_can_not_create_raw_socket[] = "can't create raw socket";
24const char bb_msg_perm_denied_are_you_root[] = "permission denied. (are you root?)";
25const char bb_msg_requires_arg[] = "%s requires an argument";
26const char bb_msg_invalid_arg[] = "invalid argument '%s' to '%s'";
27const char bb_msg_standard_input[] = "standard input";
28const char bb_msg_standard_output[] = "standard output";
29
30const char bb_str_default[] = "default";
31
32const char bb_path_passwd_file[] = "/etc/passwd";
33const char bb_path_shadow_file[] = "/etc/shadow";
34const char bb_path_group_file[] = "/etc/group";
35const char bb_path_gshadow_file[] = "/etc/gshadow";
36const char bb_path_nologin_file[] = "/etc/nologin";
37const char bb_path_securetty_file[] = "/etc/securetty";
38const char bb_path_motd_file[] = "/etc/motd";
39const char bb_default_login_shell[] = LIBBB_DEFAULT_LOGIN_SHELL;
40const char bb_dev_null[] = "/dev/null";
41
42#include <utmp.h>
43/* This is usually something like "/var/adm/wtmp" or "/var/log/wtmp" */
44const char bb_path_wtmp_file[] =
45#if defined _PATH_WTMP
46_PATH_WTMP;
47#elif defined WTMP_FILE
48WTMP_FILE;
49#else
50# error unknown path to wtmp file
51#endif
52
53char bb_common_bufsiz1[BUFSIZ+1];
diff --git a/libbb/mode_string.c b/libbb/mode_string.c
new file mode 100644
index 000000000..01029bfee
--- /dev/null
+++ b/libbb/mode_string.c
@@ -0,0 +1,128 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mode_string implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* Aug 13, 2003
11 * Fix a bug reported by junkio@cox.net involving the mode_chars index.
12 */
13
14
15#include <assert.h>
16#include <sys/stat.h>
17
18#include "libbb.h"
19
20#if ( S_ISUID != 04000 ) || ( S_ISGID != 02000 ) || ( S_ISVTX != 01000 ) \
21 || ( S_IRUSR != 00400 ) || ( S_IWUSR != 00200 ) || ( S_IXUSR != 00100 ) \
22 || ( S_IRGRP != 00040 ) || ( S_IWGRP != 00020 ) || ( S_IXGRP != 00010 ) \
23 || ( S_IROTH != 00004 ) || ( S_IWOTH != 00002 ) || ( S_IXOTH != 00001 )
24#error permission bitflag value assumption(s) violated!
25#endif
26
27#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \
28 || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 ) \
29 || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \
30 || ( S_IFIFO != 0010000 )
31#warning mode type bitflag value assumption(s) violated! falling back to larger version
32
33#if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777
34#undef mode_t
35#define mode_t unsigned short
36#endif
37
38static const mode_t mode_flags[] = {
39 S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID,
40 S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID,
41 S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX
42};
43
44/* The static const char arrays below are duplicated for the two cases
45 * because moving them ahead of the mode_flags declaration cause a text
46 * size increase with the gcc version I'm using. */
47
48/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
49 * and 'B' types don't appear to be available on linux. So I removed them. */
50static const char type_chars[16] = "?pc?d?b?-?l?s???";
51/* 0123456789abcdef */
52static const char mode_chars[7] = "rwxSTst";
53
54const char *bb_mode_string(int mode)
55{
56 static char buf[12];
57 char *p = buf;
58
59 int i, j, k;
60
61 *p = type_chars[ (mode >> 12) & 0xf ];
62 i = 0;
63 do {
64 j = k = 0;
65 do {
66 *++p = '-';
67 if (mode & mode_flags[i+j]) {
68 *p = mode_chars[j];
69 k = j;
70 }
71 } while (++j < 3);
72 if (mode & mode_flags[i+j]) {
73 *p = mode_chars[3 + (k & 2) + ((i&8) >> 3)];
74 }
75 i += 4;
76 } while (i < 12);
77
78 /* Note: We don't bother with nul termination because bss initialization
79 * should have taken care of that for us. If the user scribbled in buf
80 * memory, they deserve whatever happens. But we'll at least assert. */
81 assert(buf[10] == 0);
82
83 return buf;
84}
85
86#else
87
88/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
89 * and 'B' types don't appear to be available on linux. So I removed them. */
90static const char type_chars[16] = "?pc?d?b?-?l?s???";
91/* 0123456789abcdef */
92static const char mode_chars[7] = "rwxSTst";
93
94const char *bb_mode_string(int mode)
95{
96 static char buf[12];
97 char *p = buf;
98
99 int i, j, k, m;
100
101 *p = type_chars[ (mode >> 12) & 0xf ];
102 i = 0;
103 m = 0400;
104 do {
105 j = k = 0;
106 do {
107 *++p = '-';
108 if (mode & m) {
109 *p = mode_chars[j];
110 k = j;
111 }
112 m >>= 1;
113 } while (++j < 3);
114 ++i;
115 if (mode & (010000 >> i)) {
116 *p = mode_chars[3 + (k & 2) + (i == 3)];
117 }
118 } while (i < 3);
119
120 /* Note: We don't bother with nul termination because bss initialization
121 * should have taken care of that for us. If the user scribbled in buf
122 * memory, they deserve whatever happens. But we'll at least assert. */
123 assert(buf[10] == 0);
124
125 return buf;
126}
127
128#endif
diff --git a/libbb/mtab.c b/libbb/mtab.c
new file mode 100644
index 000000000..18386efb5
--- /dev/null
+++ b/libbb/mtab.c
@@ -0,0 +1,52 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <mntent.h>
11#include "libbb.h"
12
13#if ENABLE_FEATURE_MTAB_SUPPORT
14void erase_mtab(const char *name)
15{
16 struct mntent *entries = NULL;
17 int i, count = 0;
18 FILE *mountTable;
19 struct mntent *m;
20
21 mountTable = setmntent(bb_path_mtab_file, "r");
22 /* Bummer. Fall back on trying the /proc filesystem */
23 if (!mountTable) mountTable = setmntent("/proc/mounts", "r");
24 if (!mountTable) {
25 bb_perror_msg(bb_path_mtab_file);
26 return;
27 }
28
29 while ((m = getmntent(mountTable)) != 0) {
30 i = count++;
31 entries = xrealloc(entries, count * sizeof(entries[0]));
32 entries[i].mnt_fsname = xstrdup(m->mnt_fsname);
33 entries[i].mnt_dir = xstrdup(m->mnt_dir);
34 entries[i].mnt_type = xstrdup(m->mnt_type);
35 entries[i].mnt_opts = xstrdup(m->mnt_opts);
36 entries[i].mnt_freq = m->mnt_freq;
37 entries[i].mnt_passno = m->mnt_passno;
38 }
39 endmntent(mountTable);
40
41 mountTable = setmntent(bb_path_mtab_file, "w");
42 if (mountTable) {
43 for (i = 0; i < count; i++) {
44 if (strcmp(entries[i].mnt_fsname, name) != 0
45 && strcmp(entries[i].mnt_dir, name) != 0)
46 addmntent(mountTable, &entries[i]);
47 }
48 endmntent(mountTable);
49 } else if (errno != EROFS)
50 bb_perror_msg(bb_path_mtab_file);
51}
52#endif
diff --git a/libbb/mtab_file.c b/libbb/mtab_file.c
new file mode 100644
index 000000000..67367e3d7
--- /dev/null
+++ b/libbb/mtab_file.c
@@ -0,0 +1,17 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include "libbb.h"
12
13
14/* Busybox mount uses either /proc/mounts or /etc/mtab to
15 * get the list of currently mounted filesystems */
16const char bb_path_mtab_file[] =
17USE_FEATURE_MTAB_SUPPORT("/etc/mtab")SKIP_FEATURE_MTAB_SUPPORT("/proc/mounts");
diff --git a/libbb/obscure.c b/libbb/obscure.c
new file mode 100644
index 000000000..2599095df
--- /dev/null
+++ b/libbb/obscure.c
@@ -0,0 +1,170 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini weak password checker implementation for busybox
4 *
5 * Copyright (C) 2006 Tito Ragusa <farmatito@tiscali.it>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* A good password:
11 1) should contain at least six characters (man passwd);
12 2) empty passwords are not permitted;
13 3) should contain a mix of four different types of characters
14 upper case letters,
15 lower case letters,
16 numbers,
17 special characters such as !@#$%^&*,;".
18 This password types should not be permitted:
19 a) pure numbers: birthdates, social security number, license plate, phone numbers;
20 b) words and all letters only passwords (uppercase, lowercase or mixed)
21 as palindromes, consecutive or repetitive letters
22 or adjacent letters on your keyboard;
23 c) username, real name, company name or (e-mail?) address
24 in any form (as-is, reversed, capitalized, doubled, etc.).
25 (we can check only against username, gecos and hostname)
26 d) common and obvious letter-number replacements
27 (e.g. replace the letter O with number 0)
28 such as "M1cr0$0ft" or "P@ssw0rd" (CAVEAT: we cannot check for them
29 without the use of a dictionary).
30
31 For each missing type of characters an increase of password length is
32 requested.
33
34 If user is root we warn only.
35
36 CAVEAT: some older versions of crypt() truncates passwords to 8 chars,
37 so that aaaaaaaa1Q$ is equal to aaaaaaaa making it possible to fool
38 some of our checks. We don't test for this special case as newer versions
39 of crypt do not truncate passwords.
40*/
41
42#include "libbb.h"
43
44static int string_checker_helper(const char *p1, const char *p2) __attribute__ ((__pure__));
45
46static int string_checker_helper(const char *p1, const char *p2)
47{
48 /* as-is or capitalized */
49 if (strcasecmp(p1, p2) == 0
50 /* as sub-string */
51 || strcasestr(p2, p1) != NULL
52 /* invert in case haystack is shorter than needle */
53 || strcasestr(p1, p2) != NULL)
54 return 1;
55 return 0;
56}
57
58static int string_checker(const char *p1, const char *p2)
59{
60 int size;
61 /* check string */
62 int ret = string_checker_helper(p1, p2);
63 /* Make our own copy */
64 char *p = xstrdup(p1);
65 /* reverse string */
66 size = strlen(p);
67
68 while (size--) {
69 *p = p1[size];
70 p++;
71 }
72 /* restore pointer */
73 p -= strlen(p1);
74 /* check reversed string */
75 ret |= string_checker_helper(p, p2);
76 /* clean up */
77 memset(p, 0, strlen(p1));
78 free(p);
79 return ret;
80}
81
82#define LOWERCASE 1
83#define UPPERCASE 2
84#define NUMBERS 4
85#define SPECIAL 8
86
87static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw)
88{
89 int i;
90 int c;
91 int length;
92 int mixed = 0;
93 /* Add 2 for each type of characters to the minlen of password */
94 int size = CONFIG_PASSWORD_MINLEN + 8;
95 const char *p;
96 char hostname[255];
97
98 /* size */
99 if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
100 return "too short";
101
102 /* no username as-is, as sub-string, reversed, capitalized, doubled */
103 if (string_checker(new_p, pw->pw_name)) {
104 return "similar to username";
105 }
106 /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
107 if (*pw->pw_gecos && string_checker(new_p, pw->pw_gecos)) {
108 return "similar to gecos";
109 }
110 /* hostname as-is, as sub-string, reversed, capitalized, doubled */
111 if (gethostname(hostname, 255) == 0) {
112 hostname[254] = '\0';
113 if (string_checker(new_p, hostname)) {
114 return "similar to hostname";
115 }
116 }
117
118 /* Should / Must contain a mix of: */
119 for (i = 0; i < length; i++) {
120 if (islower(new_p[i])) { /* a-z */
121 mixed |= LOWERCASE;
122 } else if (isupper(new_p[i])) { /* A-Z */
123 mixed |= UPPERCASE;
124 } else if (isdigit(new_p[i])) { /* 0-9 */
125 mixed |= NUMBERS;
126 } else { /* special characters */
127 mixed |= SPECIAL;
128 }
129 /* More than 50% similar characters ? */
130 c = 0;
131 p = new_p;
132 while (1) {
133 if ((p = strchr(p, new_p[i])) == NULL) {
134 break;
135 }
136 c++;
137 if (!++p) {
138 break; /* move past the matched char if possible */
139 }
140 }
141
142 if (c >= (length / 2)) {
143 return "too many similar characters";
144 }
145 }
146 for (i=0; i<4; i++)
147 if (mixed & (1<<i)) size -= 2;
148 if (length < size)
149 return "too weak";
150
151 if (old_p && old_p[0] != '\0') {
152 /* check vs. old password */
153 if (string_checker(new_p, old_p)) {
154 return "similar to old password";
155 }
156 }
157 return NULL;
158}
159
160int obscure(const char *old, const char *newval, const struct passwd *pw)
161{
162 const char *msg;
163
164 msg = obscure_msg(old, newval, pw);
165 if (msg) {
166 printf("Bad password: %s\n", msg);
167 return 1;
168 }
169 return 0;
170}
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c
new file mode 100644
index 000000000..356d95db6
--- /dev/null
+++ b/libbb/parse_mode.c
@@ -0,0 +1,164 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * parse_mode implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
11
12#include <stdlib.h>
13#include <assert.h>
14#include <sys/stat.h>
15#include "libbb.h"
16
17#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
18
19int bb_parse_mode(const char *s, mode_t *current_mode)
20{
21 static const mode_t who_mask[] = {
22 S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
23 S_ISUID | S_IRWXU, /* u */
24 S_ISGID | S_IRWXG, /* g */
25 S_IRWXO /* o */
26 };
27
28 static const mode_t perm_mask[] = {
29 S_IRUSR | S_IRGRP | S_IROTH, /* r */
30 S_IWUSR | S_IWGRP | S_IWOTH, /* w */
31 S_IXUSR | S_IXGRP | S_IXOTH, /* x */
32 S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
33 S_ISUID | S_ISGID, /* s */
34 S_ISVTX /* t */
35 };
36
37 static const char who_chars[] = "augo";
38 static const char perm_chars[] = "rwxXst";
39
40 const char *p;
41
42 mode_t wholist;
43 mode_t permlist;
44 mode_t mask;
45 mode_t new_mode;
46 char op;
47
48 assert(s);
49
50 if (((unsigned int)(*s - '0')) < 8) {
51 unsigned long tmp;
52 char *e;
53
54 tmp = strtol(s, &e, 8);
55 if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
56 return 0;
57 }
58 *current_mode = tmp;
59 return 1;
60 }
61
62 mask = umask(0);
63 umask(mask);
64
65 new_mode = *current_mode;
66
67 /* Note: We allow empty clauses, and hence empty modes.
68 * We treat an empty mode as no change to perms. */
69
70 while (*s) { /* Process clauses. */
71
72 if (*s == ',') { /* We allow empty clauses. */
73 ++s;
74 continue;
75 }
76
77 /* Get a wholist. */
78 wholist = 0;
79
80 WHO_LIST:
81 p = who_chars;
82 do {
83 if (*p == *s) {
84 wholist |= who_mask[(int)(p-who_chars)];
85 if (!*++s) {
86 return 0;
87 }
88 goto WHO_LIST;
89 }
90 } while (*++p);
91
92 do { /* Process action list. */
93 if ((*s != '+') && (*s != '-')) {
94 if (*s != '=') {
95 return 0;
96 }
97 /* Since op is '=', clear all bits corresponding to the
98 * wholist, of all file bits if wholist is empty. */
99 permlist = ~FILEMODEBITS;
100 if (wholist) {
101 permlist = ~wholist;
102 }
103 new_mode &= permlist;
104 }
105 op = *s++;
106
107 /* Check for permcopy. */
108 p = who_chars + 1; /* Skip 'a' entry. */
109 do {
110 if (*p == *s) {
111 int i = 0;
112 permlist = who_mask[(int)(p-who_chars)]
113 & (S_IRWXU | S_IRWXG | S_IRWXO)
114 & new_mode;
115 do {
116 if (permlist & perm_mask[i]) {
117 permlist |= perm_mask[i];
118 }
119 } while (++i < 3);
120 ++s;
121 goto GOT_ACTION;
122 }
123 } while (*++p);
124
125 /* It was not a permcopy, so get a permlist. */
126 permlist = 0;
127
128 PERM_LIST:
129 p = perm_chars;
130 do {
131 if (*p == *s) {
132 if ((*p != 'X')
133 || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
134 ) {
135 permlist |= perm_mask[(int)(p-perm_chars)];
136 }
137 if (!*++s) {
138 break;
139 }
140 goto PERM_LIST;
141 }
142 } while (*++p);
143
144 GOT_ACTION:
145 if (permlist) { /* The permlist was nonempty. */
146 mode_t tmp = ~mask;
147 if (wholist) {
148 tmp = wholist;
149 }
150 permlist &= tmp;
151
152 if (op == '-') {
153 new_mode &= ~permlist;
154 } else {
155 new_mode |= permlist;
156 }
157 }
158 } while (*s && (*s != ','));
159 }
160
161 *current_mode = new_mode;
162
163 return 1;
164}
diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c
new file mode 100644
index 000000000..7fb0830be
--- /dev/null
+++ b/libbb/perror_msg.c
@@ -0,0 +1,23 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <errno.h>
12#include <string.h>
13#include <stdlib.h>
14#include "libbb.h"
15
16void bb_perror_msg(const char *s, ...)
17{
18 va_list p;
19
20 va_start(p, s);
21 bb_vperror_msg(s, p);
22 va_end(p);
23}
diff --git a/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c
new file mode 100644
index 000000000..2303ba211
--- /dev/null
+++ b/libbb/perror_msg_and_die.c
@@ -0,0 +1,26 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <errno.h>
12#include <string.h>
13#include <stdlib.h>
14#include "libbb.h"
15
16void bb_perror_msg_and_die(const char *s, ...)
17{
18 va_list p;
19
20 va_start(p, s);
21 bb_vperror_msg(s, p);
22 va_end(p);
23 if (die_sleep)
24 sleep(die_sleep);
25 exit(xfunc_error_retval);
26}
diff --git a/libbb/perror_nomsg.c b/libbb/perror_nomsg.c
new file mode 100644
index 000000000..3aefd5301
--- /dev/null
+++ b/libbb/perror_nomsg.c
@@ -0,0 +1,16 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bb_perror_nomsg implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12void bb_perror_nomsg(void)
13{
14 /* Ignore the gcc warning about a null format string. */
15 bb_perror_msg(NULL);
16}
diff --git a/libbb/perror_nomsg_and_die.c b/libbb/perror_nomsg_and_die.c
new file mode 100644
index 000000000..e5623c2a9
--- /dev/null
+++ b/libbb/perror_nomsg_and_die.c
@@ -0,0 +1,17 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bb_perror_nomsg_and_die implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stddef.h>
11#include "libbb.h"
12
13void bb_perror_nomsg_and_die(void)
14{
15 /* Ignore the gcc warning about a null format string. */
16 bb_perror_msg_and_die(NULL);
17}
diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c
new file mode 100644
index 000000000..138e751f5
--- /dev/null
+++ b/libbb/process_escape_sequence.c
@@ -0,0 +1,89 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) Manuel Novoa III <mjn3@codepoet.org>
6 * and Vladimir Oleynik <dzo@simtreas.ru>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include <stdio.h>
12#include <limits.h>
13#include <ctype.h>
14#include "libbb.h"
15
16#define WANT_HEX_ESCAPES 1
17
18/* Usual "this only works for ascii compatible encodings" disclaimer. */
19#undef _tolower
20#define _tolower(X) ((X)|((char) 0x20))
21
22char bb_process_escape_sequence(const char **ptr)
23{
24 static const char charmap[] = {
25 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0,
26 '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
27
28 const char *p;
29 const char *q;
30 unsigned int num_digits;
31 unsigned int r;
32 unsigned int n;
33 unsigned int d;
34 unsigned int base;
35
36 num_digits = n = 0;
37 base = 8;
38 q = *ptr;
39
40#ifdef WANT_HEX_ESCAPES
41 if (*q == 'x') {
42 ++q;
43 base = 16;
44 ++num_digits;
45 }
46#endif
47
48 do {
49 d = (unsigned int)(*q - '0');
50#ifdef WANT_HEX_ESCAPES
51 if (d >= 10) {
52 d = ((unsigned int)(_tolower(*q) - 'a')) + 10;
53 }
54#endif
55
56 if (d >= base) {
57#ifdef WANT_HEX_ESCAPES
58 if ((base == 16) && (!--num_digits)) {
59/* return '\\'; */
60 --q;
61 }
62#endif
63 break;
64 }
65
66 r = n * base + d;
67 if (r > UCHAR_MAX) {
68 break;
69 }
70
71 n = r;
72 ++q;
73 } while (++num_digits < 3);
74
75 if (num_digits == 0) { /* mnemonic escape sequence? */
76 p = charmap;
77 do {
78 if (*p == *q) {
79 q++;
80 break;
81 }
82 } while (*++p);
83 n = *(p+(sizeof(charmap)/2));
84 }
85
86 *ptr = q;
87
88 return (char) n;
89}
diff --git a/libbb/procps.c b/libbb/procps.c
new file mode 100644
index 000000000..017710ff4
--- /dev/null
+++ b/libbb/procps.c
@@ -0,0 +1,255 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright 1998 by Albert Cahalan; all rights reserved.
6 * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include "libbb.h"
12
13
14typedef struct unsigned_to_name_map_t {
15 unsigned id;
16 char name[12];
17} unsigned_to_name_map_t;
18
19typedef struct cache_t {
20 unsigned_to_name_map_t *cache;
21 int size;
22} cache_t;
23
24static cache_t username, groupname;
25
26static void clear_cache(cache_t *cp)
27{
28 free(cp->cache);
29 cp->cache = NULL;
30 cp->size = 0;
31}
32void clear_username_cache(void)
33{
34 clear_cache(&username);
35 clear_cache(&groupname);
36}
37
38#if 0 /* more generic, but we don't need that yet */
39/* Returns -N-1 if not found. */
40/* cp->cache[N] is allocated and must be filled in this case */
41static int get_cached(cache_t *cp, unsigned id)
42{
43 int i;
44 for (i = 0; i < cp->size; i++)
45 if (cp->cache[i].id == id)
46 return i;
47 i = cp->size++;
48 cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
49 cp->cache[i++].id = id;
50 return -i;
51}
52#endif
53
54typedef char* ug_func(char *name, long uid, int bufsize);
55static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)
56{
57 int i;
58 for (i = 0; i < cp->size; i++)
59 if (cp->cache[i].id == id)
60 return cp->cache[i].name;
61 i = cp->size++;
62 cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
63 cp->cache[i].id = id;
64 fp(cp->cache[i].name, id, sizeof(cp->cache[i].name));
65 return cp->cache[i].name;
66}
67const char* get_cached_username(uid_t uid)
68{
69 return get_cached(&username, uid, bb_getpwuid);
70}
71const char* get_cached_groupname(gid_t gid)
72{
73 return get_cached(&groupname, gid, bb_getgrgid);
74}
75
76
77#define PROCPS_BUFSIZE 1024
78
79static int read_to_buf(const char *filename, void *buf)
80{
81 ssize_t ret;
82 ret = open_read_close(filename, buf, PROCPS_BUFSIZE-1);
83 ((char *)buf)[ret > 0 ? ret : 0] = '\0';
84 return ret;
85}
86
87procps_status_t* alloc_procps_scan(int flags)
88{
89 procps_status_t* sp = xzalloc(sizeof(procps_status_t));
90 sp->dir = xopendir("/proc");
91 return sp;
92}
93
94void free_procps_scan(procps_status_t* sp)
95{
96 closedir(sp->dir);
97 free(sp->cmd);
98 free(sp);
99}
100
101void BUG_comm_size(void);
102procps_status_t* procps_scan(procps_status_t* sp, int flags)
103{
104 struct dirent *entry;
105 char buf[PROCPS_BUFSIZE];
106 char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
107 char *filename_tail;
108 long tasknice;
109 unsigned pid;
110 int n;
111 struct stat sb;
112
113 if (!sp)
114 sp = alloc_procps_scan(flags);
115
116 for (;;) {
117 entry = readdir(sp->dir);
118 if (entry == NULL) {
119 free_procps_scan(sp);
120 return NULL;
121 }
122 pid = bb_strtou(entry->d_name, NULL, 10);
123 if (errno)
124 continue;
125
126 /* After this point we have to break, not continue
127 * ("continue" would mean that current /proc/NNN
128 * is not a valid process info) */
129
130 memset(&sp->rss, 0, sizeof(*sp) - offsetof(procps_status_t, rss));
131
132 sp->pid = pid;
133 if (!(flags & ~PSSCAN_PID)) break;
134
135 filename_tail = filename + sprintf(filename, "/proc/%d", pid);
136
137 if (flags & PSSCAN_UIDGID) {
138 if (stat(filename, &sb))
139 break;
140 /* Need comment - is this effective or read UID/GID? */
141 sp->uid = sb.st_uid;
142 sp->gid = sb.st_gid;
143 }
144
145 if (flags & PSSCAN_STAT) {
146 char *cp;
147 /* see proc(5) for some details on this */
148 strcpy(filename_tail, "/stat");
149 n = read_to_buf(filename, buf);
150 if (n < 0)
151 break;
152 cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
153 if (!cp || cp[1] != ' ')
154 break;
155 cp[0] = '\0';
156 if (sizeof(sp->comm) < 16)
157 BUG_comm_size();
158 sscanf(buf, "%*s (%15c", sp->comm);
159 n = sscanf(cp+2,
160 "%c %u " /* state, ppid */
161 "%u %u %*s %*s " /* pgid, sid, tty, tpgid */
162 "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
163 "%lu %lu " /* utime, stime */
164 "%*s %*s %*s " /* cutime, cstime, priority */
165 "%ld " /* nice */
166 "%*s %*s %*s " /* timeout, it_real_value, start_time */
167 "%*s " /* vsize */
168 "%lu", /* rss */
169 sp->state, &sp->ppid,
170 &sp->pgid, &sp->sid,
171 &sp->utime, &sp->stime,
172 &tasknice,
173 &sp->rss);
174 if (n != 8)
175 break;
176
177 if (sp->rss == 0 && sp->state[0] != 'Z')
178 sp->state[1] = 'W';
179 else
180 sp->state[1] = ' ';
181 if (tasknice < 0)
182 sp->state[2] = '<';
183 else if (tasknice > 0)
184 sp->state[2] = 'N';
185 else
186 sp->state[2] = ' ';
187
188#ifdef PAGE_SHIFT
189 sp->rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */
190#else
191 sp->rss *= (getpagesize() >> 10); /* 2**10 = 1kb */
192#endif
193 }
194
195 if (flags & PSSCAN_CMD) {
196 free(sp->cmd);
197 sp->cmd = NULL;
198 strcpy(filename_tail, "/cmdline");
199 n = read_to_buf(filename, buf);
200 if (n <= 0)
201 break;
202 if (buf[n-1] == '\n') {
203 if (!--n)
204 break;
205 buf[n] = '\0';
206 }
207 do {
208 n--;
209 if ((unsigned char)(buf[n]) < ' ')
210 buf[n] = ' ';
211 } while (n);
212 sp->cmd = strdup(buf);
213 }
214 break;
215 }
216 return sp;
217}
218/* from kernel:
219 // pid comm S ppid pgid sid tty_nr tty_pgrp flg
220 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
221%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
222%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
223 task->pid,
224 tcomm,
225 state,
226 ppid,
227 pgid,
228 sid,
229 tty_nr,
230 tty_pgrp,
231 task->flags,
232 min_flt,
233
234 cmin_flt,
235 maj_flt,
236 cmaj_flt,
237 cputime_to_clock_t(utime),
238 cputime_to_clock_t(stime),
239 cputime_to_clock_t(cutime),
240 cputime_to_clock_t(cstime),
241 priority,
242 nice,
243 num_threads,
244 // 0,
245 start_time,
246 vsize,
247 mm ? get_mm_rss(mm) : 0,
248 rsslim,
249 mm ? mm->start_code : 0,
250 mm ? mm->end_code : 0,
251 mm ? mm->start_stack : 0,
252 esp,
253 eip,
254the rest is some obsolete cruft
255*/
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
new file mode 100644
index 000000000..d546bc883
--- /dev/null
+++ b/libbb/pw_encrypt.c
@@ -0,0 +1,29 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routine.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include <crypt.h>
12
13char *pw_encrypt(const char *clear, const char *salt)
14{
15 static char cipher[128];
16 char *cp;
17
18#if 0 /* was CONFIG_FEATURE_SHA1_PASSWORDS, but there is no such thing??? */
19 if (strncmp(salt, "$2$", 3) == 0) {
20 return sha1_crypt(clear);
21 }
22#endif
23 cp = (char *) crypt(clear, salt);
24 /* if crypt (a nonstandard crypt) returns a string too large,
25 truncate it so we don't overrun buffers and hope there is
26 enough security in what's left */
27 safe_strncpy(cipher, cp, sizeof(cipher));
28 return cipher;
29}
diff --git a/libbb/read.c b/libbb/read.c
new file mode 100644
index 000000000..b3648b4d7
--- /dev/null
+++ b/libbb/read.c
@@ -0,0 +1,134 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12ssize_t safe_read(int fd, void *buf, size_t count)
13{
14 ssize_t n;
15
16 do {
17 n = read(fd, buf, count);
18 } while (n < 0 && errno == EINTR);
19
20 return n;
21}
22
23/*
24 * Read all of the supplied buffer from a file.
25 * This does multiple reads as necessary.
26 * Returns the amount read, or -1 on an error.
27 * A short read is returned on an end of file.
28 */
29ssize_t full_read(int fd, void *buf, size_t len)
30{
31 ssize_t cc;
32 ssize_t total;
33
34 total = 0;
35
36 while (len) {
37 cc = safe_read(fd, buf, len);
38
39 if (cc < 0)
40 return cc; /* read() returns -1 on failure. */
41
42 if (cc == 0)
43 break;
44
45 buf = ((char *)buf) + cc;
46 total += cc;
47 len -= cc;
48 }
49
50 return total;
51}
52
53// Die with an error message if we can't read the entire buffer.
54void xread(int fd, void *buf, size_t count)
55{
56 if (count) {
57 ssize_t size = full_read(fd, buf, count);
58 if (size != count)
59 bb_error_msg_and_die("short read");
60 }
61}
62
63// Die with an error message if we can't read one character.
64unsigned char xread_char(int fd)
65{
66 char tmp;
67
68 xread(fd, &tmp, 1);
69
70 return tmp;
71}
72
73// Read one line a-la fgets. Works only on seekable streams
74char *reads(int fd, char *buffer, size_t size)
75{
76 char *p;
77
78 if (size < 2)
79 return NULL;
80 size = full_read(fd, buffer, size-1);
81 if ((ssize_t)size <= 0)
82 return NULL;
83
84 buffer[size] = '\0';
85 p = strchr(buffer, '\n');
86 if (p) {
87 off_t offset;
88 *p++ = '\0';
89 // avoid incorrect (unsigned) widening
90 offset = (off_t)(p-buffer) - (off_t)size;
91 // set fd position the right after the \n
92 if (offset && lseek(fd, offset, SEEK_CUR) == (off_t)-1)
93 return NULL;
94 }
95 return buffer;
96}
97
98ssize_t read_close(int fd, void *buf, size_t size)
99{
100 int e;
101 size = full_read(fd, buf, size);
102 e = errno;
103 close(fd);
104 errno = e;
105 return size;
106}
107
108ssize_t open_read_close(const char *filename, void *buf, size_t size)
109{
110 int fd = open(filename, O_RDONLY);
111 if (fd < 0)
112 return fd;
113 return read_close(fd, buf, size);
114}
115
116void *xmalloc_open_read_close(const char *filename, size_t *sizep)
117{
118 char *buf;
119 size_t size = sizep ? *sizep : INT_MAX;
120 int fd = xopen(filename, O_RDONLY);
121 off_t len = xlseek(fd, 0, SEEK_END);
122 xlseek(fd, 0, SEEK_SET);
123
124 if (len > size)
125 bb_error_msg_and_die("file '%s' is too big", filename);
126 size = len;
127 buf = xmalloc(size+1);
128 size = read_close(fd, buf, size);
129 if ((ssize_t)size < 0)
130 bb_perror_msg_and_die("'%s'", filename);
131 buf[size] = '\0';
132 if (sizep) *sizep = size;
133 return buf;
134}
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
new file mode 100644
index 000000000..121a3dffd
--- /dev/null
+++ b/libbb/recursive_action.c
@@ -0,0 +1,126 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12#undef DEBUG_RECURS_ACTION
13
14/*
15 * Walk down all the directories under the specified
16 * location, and do something (something specified
17 * by the fileAction and dirAction function pointers).
18 *
19 * Unfortunately, while nftw(3) could replace this and reduce
20 * code size a bit, nftw() wasn't supported before GNU libc 2.1,
21 * and so isn't sufficiently portable to take over since glibc2.1
22 * is so stinking huge.
23 */
24
25static int true_action(const char *fileName, struct stat *statbuf, void* userData, int depth)
26{
27 return TRUE;
28}
29
30/* fileAction return value of 0 on any file in directory will make
31 * recursive_action() return 0, but it doesn't stop directory traversal
32 * (fileAction/dirAction will be called on each file).
33 *
34 * if !depthFirst, dirAction return value of 0 (FALSE) or 2 (SKIP)
35 * prevents recursion into that directory, instead
36 * recursive_action() returns 0 (if FALSE) or 1 (if SKIP).
37 *
38 * followLinks=0/1 differs mainly in handling of links to dirs.
39 * 0: lstat(statbuf). Calls fileAction on link name even if points to dir.
40 * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
41 */
42
43int recursive_action(const char *fileName,
44 int recurse, int followLinks, int depthFirst,
45 int (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
46 int (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
47 void* userData,
48 int depth)
49{
50 struct stat statbuf;
51 int status;
52 DIR *dir;
53 struct dirent *next;
54
55 if (!fileAction) fileAction = true_action;
56 if (!dirAction) dirAction = true_action;
57
58 status = (followLinks ? stat : lstat)(fileName, &statbuf);
59
60 if (status < 0) {
61#ifdef DEBUG_RECURS_ACTION
62 bb_error_msg("status=%d followLinks=%d TRUE=%d",
63 status, followLinks, TRUE);
64#endif
65 bb_perror_msg("%s", fileName);
66 return FALSE;
67 }
68
69 /* If S_ISLNK(m), then we know that !S_ISDIR(m).
70 * Then we can skip checking first part: if it is true, then
71 * (!dir) is also true! */
72 if ( /* (!followLinks && S_ISLNK(statbuf.st_mode)) || */
73 !S_ISDIR(statbuf.st_mode)
74 ) {
75 return fileAction(fileName, &statbuf, userData, depth);
76 }
77
78 /* It's a directory (or a link to one, and followLinks is set) */
79
80 if (!recurse) {
81 return dirAction(fileName, &statbuf, userData, depth);
82 }
83
84 if (!depthFirst) {
85 status = dirAction(fileName, &statbuf, userData, depth);
86 if (!status) {
87 bb_perror_msg("%s", fileName);
88 return FALSE;
89 }
90 if (status == SKIP)
91 return TRUE;
92 }
93
94 dir = opendir(fileName);
95 if (!dir) {
96 /* findutils-4.1.20 reports this */
97 /* (i.e. it doesn't silently return with exit code 1) */
98 /* To trigger: "find -exec rm -rf {} \;" */
99 bb_perror_msg("%s", fileName);
100 return FALSE;
101 }
102 status = TRUE;
103 while ((next = readdir(dir)) != NULL) {
104 char *nextFile;
105
106 nextFile = concat_subpath_file(fileName, next->d_name);
107 if (nextFile == NULL)
108 continue;
109 if (!recursive_action(nextFile, TRUE, followLinks, depthFirst,
110 fileAction, dirAction, userData, depth+1)) {
111 status = FALSE;
112 }
113 free(nextFile);
114 }
115 closedir(dir);
116 if (depthFirst) {
117 if (!dirAction(fileName, &statbuf, userData, depth)) {
118 bb_perror_msg("%s", fileName);
119 return FALSE;
120 }
121 }
122
123 if (!status)
124 return FALSE;
125 return TRUE;
126}
diff --git a/libbb/remove_file.c b/libbb/remove_file.c
new file mode 100644
index 000000000..ab159a481
--- /dev/null
+++ b/libbb/remove_file.c
@@ -0,0 +1,111 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini remove_file implementation for busybox
4 *
5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <time.h>
12#include <utime.h>
13#include <dirent.h>
14#include <errno.h>
15#include <unistd.h>
16#include <stdlib.h>
17#include <string.h>
18#include <getopt.h>
19#include "libbb.h"
20
21int remove_file(const char *path, int flags)
22{
23 struct stat path_stat;
24 int path_exists = 1;
25
26 if (lstat(path, &path_stat) < 0) {
27 if (errno != ENOENT) {
28 bb_perror_msg("cannot stat '%s'", path);
29 return -1;
30 }
31
32 path_exists = 0;
33 }
34
35 if (!path_exists) {
36 if (!(flags & FILEUTILS_FORCE)) {
37 bb_perror_msg("cannot remove '%s'", path);
38 return -1;
39 }
40 return 0;
41 }
42
43 if (S_ISDIR(path_stat.st_mode)) {
44 DIR *dp;
45 struct dirent *d;
46 int status = 0;
47
48 if (!(flags & FILEUTILS_RECUR)) {
49 bb_error_msg("%s: is a directory", path);
50 return -1;
51 }
52
53 if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
54 isatty(0)) ||
55 (flags & FILEUTILS_INTERACTIVE)) {
56 fprintf(stderr, "%s: descend into directory '%s'? ", applet_name,
57 path);
58 if (!bb_ask_confirmation())
59 return 0;
60 }
61
62 if ((dp = opendir(path)) == NULL) {
63 return -1;
64 }
65
66 while ((d = readdir(dp)) != NULL) {
67 char *new_path;
68
69 new_path = concat_subpath_file(path, d->d_name);
70 if(new_path == NULL)
71 continue;
72 if (remove_file(new_path, flags) < 0)
73 status = -1;
74 free(new_path);
75 }
76
77 if (closedir(dp) < 0) {
78 bb_perror_msg("cannot close '%s'", path);
79 return -1;
80 }
81
82 if (flags & FILEUTILS_INTERACTIVE) {
83 fprintf(stderr, "%s: remove directory '%s'? ", applet_name, path);
84 if (!bb_ask_confirmation())
85 return status;
86 }
87
88 if (rmdir(path) < 0) {
89 bb_perror_msg("cannot remove '%s'", path);
90 return -1;
91 }
92
93 return status;
94 } else {
95 if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
96 !S_ISLNK(path_stat.st_mode) &&
97 isatty(0)) ||
98 (flags & FILEUTILS_INTERACTIVE)) {
99 fprintf(stderr, "%s: remove '%s'? ", applet_name, path);
100 if (!bb_ask_confirmation())
101 return 0;
102 }
103
104 if (unlink(path) < 0) {
105 bb_perror_msg("cannot remove '%s'", path);
106 return -1;
107 }
108
109 return 0;
110 }
111}
diff --git a/libbb/restricted_shell.c b/libbb/restricted_shell.c
new file mode 100644
index 000000000..74a64140f
--- /dev/null
+++ b/libbb/restricted_shell.c
@@ -0,0 +1,57 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <stdio.h>
32#include <errno.h>
33#include <unistd.h>
34#include <string.h>
35#include <stdlib.h>
36#include <syslog.h>
37#include <ctype.h>
38#include "libbb.h"
39
40
41
42/* Return 1 if SHELL is a restricted shell (one not returned by
43 getusershell), else 0, meaning it is a standard shell. */
44
45int restricted_shell ( const char *shell )
46{
47 char *line;
48
49 setusershell ( );
50 while (( line = getusershell ( ))) {
51 if (( *line != '#' ) && ( strcmp ( line, shell ) == 0 ))
52 break;
53 }
54 endusershell ( );
55 return line ? 0 : 1;
56}
57
diff --git a/libbb/run_shell.c b/libbb/run_shell.c
new file mode 100644
index 000000000..6be09088d
--- /dev/null
+++ b/libbb/run_shell.c
@@ -0,0 +1,101 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <stdio.h>
32#include <errno.h>
33#include <unistd.h>
34#include <string.h>
35#include <stdlib.h>
36#include <syslog.h>
37#include <ctype.h>
38#include "libbb.h"
39#ifdef CONFIG_SELINUX
40#include <selinux/selinux.h> /* for setexeccon */
41#endif
42
43#ifdef CONFIG_SELINUX
44static security_context_t current_sid;
45
46void
47renew_current_security_context(void)
48{
49 if (current_sid)
50 freecon(current_sid); /* Release old context */
51 getcon(&current_sid); /* update */
52}
53void
54set_current_security_context(security_context_t sid)
55{
56 if (current_sid)
57 freecon(current_sid); /* Release old context */
58 current_sid = sid;
59}
60
61#endif
62
63/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
64 If COMMAND is nonzero, pass it to the shell with the -c option.
65 If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
66 arguments. */
67
68void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args)
69{
70 const char **args;
71 int argno = 1;
72 int additional_args_cnt = 0;
73
74 for (args = additional_args; args && *args; args++)
75 additional_args_cnt++;
76
77 args = xmalloc(sizeof(char*) * (4 + additional_args_cnt));
78
79 args[0] = bb_get_last_path_component(xstrdup(shell));
80
81 if (loginshell)
82 args[0] = xasprintf("-%s", args[0]);
83
84 if (command) {
85 args[argno++] = "-c";
86 args[argno++] = command;
87 }
88 if (additional_args) {
89 for (; *additional_args; ++additional_args)
90 args[argno++] = *additional_args;
91 }
92 args[argno] = NULL;
93#ifdef CONFIG_SELINUX
94 if (current_sid && !setexeccon(current_sid)) {
95 freecon(current_sid);
96 execve(shell, (char **) args, environ);
97 } else
98#endif
99 execv(shell, (char **) args);
100 bb_perror_msg_and_die("cannot run %s", shell);
101}
diff --git a/libbb/safe_strncpy.c b/libbb/safe_strncpy.c
new file mode 100644
index 000000000..42bc16ea0
--- /dev/null
+++ b/libbb/safe_strncpy.c
@@ -0,0 +1,21 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <string.h>
11#include "libbb.h"
12
13
14
15/* Like strncpy but make sure the resulting string is always 0 terminated. */
16char * safe_strncpy(char *dst, const char *src, size_t size)
17{
18 if (!size) return dst;
19 dst[--size] = '\0';
20 return strncpy(dst, src, size);
21}
diff --git a/libbb/safe_write.c b/libbb/safe_write.c
new file mode 100644
index 000000000..c81f1247f
--- /dev/null
+++ b/libbb/safe_write.c
@@ -0,0 +1,26 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <errno.h>
12#include <unistd.h>
13#include "libbb.h"
14
15
16
17ssize_t safe_write(int fd, const void *buf, size_t count)
18{
19 ssize_t n;
20
21 do {
22 n = write(fd, buf, count);
23 } while (n < 0 && errno == EINTR);
24
25 return n;
26}
diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c
new file mode 100644
index 000000000..874a58efa
--- /dev/null
+++ b/libbb/setup_environment.c
@@ -0,0 +1,83 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <stdio.h>
32#include <errno.h>
33#include <unistd.h>
34#include <string.h>
35#include <stdlib.h>
36#include <syslog.h>
37#include <ctype.h>
38#include "libbb.h"
39
40
41
42#define DEFAULT_LOGIN_PATH "/bin:/usr/bin"
43#define DEFAULT_ROOT_LOGIN_PATH "/usr/sbin:/bin:/usr/bin:/sbin"
44
45void setup_environment(const char *shell, int loginshell, int changeenv, const struct passwd *pw)
46{
47 if (loginshell) {
48 const char *term;
49
50 /* Change the current working directory to be the home directory
51 * of the user. It is a fatal error for this process to be unable
52 * to change to that directory. There is no "default" home
53 * directory.
54 * Some systems default to HOME=/
55 */
56 if (chdir(pw->pw_dir)) {
57 xchdir("/");
58 fputs("warning: cannot change to home directory\n", stderr);
59 }
60
61 /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
62 Unset all other environment variables. */
63 term = getenv("TERM");
64 clearenv();
65 if (term)
66 xsetenv("TERM", term);
67 xsetenv("HOME", pw->pw_dir);
68 xsetenv("SHELL", shell);
69 xsetenv("USER", pw->pw_name);
70 xsetenv("LOGNAME", pw->pw_name);
71 xsetenv("PATH", (pw->pw_uid ? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH));
72 }
73 else if (changeenv) {
74 /* Set HOME, SHELL, and if not becoming a super-user,
75 USER and LOGNAME. */
76 xsetenv("HOME", pw->pw_dir);
77 xsetenv("SHELL", shell);
78 if (pw->pw_uid) {
79 xsetenv("USER", pw->pw_name);
80 xsetenv("LOGNAME", pw->pw_name);
81 }
82 }
83}
diff --git a/libbb/sha1.c b/libbb/sha1.c
new file mode 100644
index 000000000..34813e24a
--- /dev/null
+++ b/libbb/sha1.c
@@ -0,0 +1,178 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Based on shasum from http://www.netsw.org/crypto/hash/
4 * Majorly hacked up to use Dr Brian Gladman's sha1 code
5 *
6 * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
7 * Copyright (C) 2003 Glenn L. McGrath
8 * Copyright (C) 2003 Erik Andersen
9 *
10 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
11 *
12 * ---------------------------------------------------------------------------
13 * Issue Date: 10/11/2002
14 *
15 * This is a byte oriented version of SHA1 that operates on arrays of bytes
16 * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor
17 */
18
19#include <fcntl.h>
20#include <limits.h>
21#include <stdio.h>
22#include <stdint.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27#include "libbb.h"
28
29#define SHA1_BLOCK_SIZE 64
30#define SHA1_DIGEST_SIZE 20
31#define SHA1_HASH_SIZE SHA1_DIGEST_SIZE
32#define SHA2_GOOD 0
33#define SHA2_BAD 1
34
35#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
36
37#define SHA1_MASK (SHA1_BLOCK_SIZE - 1)
38
39/* reverse byte order in 32-bit words */
40#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
41#define parity(x,y,z) ((x) ^ (y) ^ (z))
42#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
43
44/* A normal version as set out in the FIPS. This version uses */
45/* partial loop unrolling and is optimised for the Pentium 4 */
46#define rnd(f,k) \
47 do { \
48 t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; \
49 e = d; d = c; c = rotl32(b, 30); b = t; \
50 } while(0)
51
52static void sha1_compile(sha1_ctx_t *ctx)
53{
54 uint32_t w[80], i, a, b, c, d, e, t;
55
56 /* note that words are compiled from the buffer into 32-bit */
57 /* words in big-endian order so an order reversal is needed */
58 /* here on little endian machines */
59 for (i = 0; i < SHA1_BLOCK_SIZE / 4; ++i)
60 w[i] = htonl(ctx->wbuf[i]);
61
62 for (i = SHA1_BLOCK_SIZE / 4; i < 80; ++i)
63 w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
64
65 a = ctx->hash[0];
66 b = ctx->hash[1];
67 c = ctx->hash[2];
68 d = ctx->hash[3];
69 e = ctx->hash[4];
70
71 for (i = 0; i < 20; ++i) {
72 rnd(ch, 0x5a827999);
73 }
74
75 for (i = 20; i < 40; ++i) {
76 rnd(parity, 0x6ed9eba1);
77 }
78
79 for (i = 40; i < 60; ++i) {
80 rnd(maj, 0x8f1bbcdc);
81 }
82
83 for (i = 60; i < 80; ++i) {
84 rnd(parity, 0xca62c1d6);
85 }
86
87 ctx->hash[0] += a;
88 ctx->hash[1] += b;
89 ctx->hash[2] += c;
90 ctx->hash[3] += d;
91 ctx->hash[4] += e;
92}
93
94void sha1_begin(sha1_ctx_t *ctx)
95{
96 ctx->count[0] = ctx->count[1] = 0;
97 ctx->hash[0] = 0x67452301;
98 ctx->hash[1] = 0xefcdab89;
99 ctx->hash[2] = 0x98badcfe;
100 ctx->hash[3] = 0x10325476;
101 ctx->hash[4] = 0xc3d2e1f0;
102}
103
104/* SHA1 hash data in an array of bytes into hash buffer and call the */
105/* hash_compile function as required. */
106void sha1_hash(const void *data, size_t length, sha1_ctx_t *ctx)
107{
108 uint32_t pos = (uint32_t) (ctx->count[0] & SHA1_MASK);
109 uint32_t freeb = SHA1_BLOCK_SIZE - pos;
110 const unsigned char *sp = data;
111
112 if ((ctx->count[0] += length) < length)
113 ++(ctx->count[1]);
114
115 while (length >= freeb) { /* tranfer whole blocks while possible */
116 memcpy(((unsigned char *) ctx->wbuf) + pos, sp, freeb);
117 sp += freeb;
118 length -= freeb;
119 freeb = SHA1_BLOCK_SIZE;
120 pos = 0;
121 sha1_compile(ctx);
122 }
123
124 memcpy(((unsigned char *) ctx->wbuf) + pos, sp, length);
125}
126
127void *sha1_end(void *resbuf, sha1_ctx_t *ctx)
128{
129 /* SHA1 Final padding and digest calculation */
130#if BB_BIG_ENDIAN
131 static uint32_t mask[4] = { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 };
132 static uint32_t bits[4] = { 0x80000000, 0x00800000, 0x00008000, 0x00000080 };
133#else
134 static uint32_t mask[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
135 static uint32_t bits[4] = { 0x00000080, 0x00008000, 0x00800000, 0x80000000 };
136#endif
137
138 uint8_t *hval = resbuf;
139 uint32_t i, cnt = (uint32_t) (ctx->count[0] & SHA1_MASK);
140
141 /* mask out the rest of any partial 32-bit word and then set */
142 /* the next byte to 0x80. On big-endian machines any bytes in */
143 /* the buffer will be at the top end of 32 bit words, on little */
144 /* endian machines they will be at the bottom. Hence the AND */
145 /* and OR masks above are reversed for little endian systems */
146 ctx->wbuf[cnt >> 2] =
147 (ctx->wbuf[cnt >> 2] & mask[cnt & 3]) | bits[cnt & 3];
148
149 /* we need 9 or more empty positions, one for the padding byte */
150 /* (above) and eight for the length count. If there is not */
151 /* enough space pad and empty the buffer */
152 if (cnt > SHA1_BLOCK_SIZE - 9) {
153 if (cnt < 60)
154 ctx->wbuf[15] = 0;
155 sha1_compile(ctx);
156 cnt = 0;
157 } else /* compute a word index for the empty buffer positions */
158 cnt = (cnt >> 2) + 1;
159
160 while (cnt < 14) /* and zero pad all but last two positions */
161 ctx->wbuf[cnt++] = 0;
162
163 /* assemble the eight byte counter in the buffer in big-endian */
164 /* format */
165
166 ctx->wbuf[14] = htonl((ctx->count[1] << 3) | (ctx->count[0] >> 29));
167 ctx->wbuf[15] = htonl(ctx->count[0] << 3);
168
169 sha1_compile(ctx);
170
171 /* extract the hash value as bytes in case the hash buffer is */
172 /* misaligned for 32-bit words */
173
174 for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
175 hval[i] = (unsigned char) (ctx->hash[i >> 2] >> 8 * (~i & 3));
176
177 return resbuf;
178}
diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c
new file mode 100644
index 000000000..b714c66b6
--- /dev/null
+++ b/libbb/simplify_path.c
@@ -0,0 +1,50 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bb_simplify_path implementation for busybox
4 *
5 * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12char *bb_simplify_path(const char *path)
13{
14 char *s, *start, *p;
15
16 if (path[0] == '/')
17 start = xstrdup(path);
18 else {
19 s = xgetcwd(NULL);
20 start = concat_path_file(s, path);
21 free(s);
22 }
23 p = s = start;
24
25 do {
26 if (*p == '/') {
27 if (*s == '/') { /* skip duplicate (or initial) slash */
28 continue;
29 } else if (*s == '.') {
30 if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
31 continue;
32 } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
33 ++s;
34 if (p > start) {
35 while (*--p != '/'); /* omit previous dir */
36 }
37 continue;
38 }
39 }
40 }
41 *++p = *s;
42 } while (*++s);
43
44 if ((p == start) || (*p != '/')) { /* not a trailing slash */
45 ++p; /* so keep last character */
46 }
47 *p = 0;
48
49 return start;
50}
diff --git a/libbb/skip_whitespace.c b/libbb/skip_whitespace.c
new file mode 100644
index 000000000..02c1f5828
--- /dev/null
+++ b/libbb/skip_whitespace.c
@@ -0,0 +1,18 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * skip_whitespace implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <ctype.h>
11#include "libbb.h"
12
13char *skip_whitespace(const char *s)
14{
15 while (isspace(*s)) ++s;
16
17 return (char *) s;
18}
diff --git a/libbb/speed_table.c b/libbb/speed_table.c
new file mode 100644
index 000000000..6137b7731
--- /dev/null
+++ b/libbb/speed_table.c
@@ -0,0 +1,117 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * compact speed_t <-> speed functions for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <termios.h>
11#include "libbb.h"
12
13struct speed_map {
14 unsigned short speed;
15 unsigned short value;
16};
17
18static const struct speed_map speeds[] = {
19 {B0, 0},
20 {B50, 50},
21 {B75, 75},
22 {B110, 110},
23 {B134, 134},
24 {B150, 150},
25 {B200, 200},
26 {B300, 300},
27 {B600, 600},
28 {B1200, 1200},
29 {B1800, 1800},
30 {B2400, 2400},
31 {B4800, 4800},
32 {B9600, 9600},
33#ifdef B19200
34 {B19200, 19200},
35#elif defined(EXTA)
36 {EXTA, 19200},
37#endif
38#ifdef B38400
39 {B38400, 38400/256 + 0x8000U},
40#elif defined(EXTB)
41 {EXTB, 38400/256 + 0x8000U},
42#endif
43#ifdef B57600
44 {B57600, 57600/256 + 0x8000U},
45#endif
46#ifdef B115200
47 {B115200, 115200/256 + 0x8000U},
48#endif
49#ifdef B230400
50 {B230400, 230400/256 + 0x8000U},
51#endif
52#ifdef B460800
53 {B460800, 460800/256 + 0x8000U},
54#endif
55};
56
57enum { NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map)) };
58
59unsigned int tty_baud_to_value(speed_t speed)
60{
61 int i = 0;
62
63 do {
64 if (speed == speeds[i].speed) {
65 if (speeds[i].value & 0x8000U) {
66 return ((unsigned long) (speeds[i].value) & 0x7fffU) * 256;
67 }
68 return speeds[i].value;
69 }
70 } while (++i < NUM_SPEEDS);
71
72 return 0;
73}
74
75speed_t tty_value_to_baud(unsigned int value)
76{
77 int i = 0;
78
79 do {
80 if (value == tty_baud_to_value(speeds[i].speed)) {
81 return speeds[i].speed;
82 }
83 } while (++i < NUM_SPEEDS);
84
85 return (speed_t) - 1;
86}
87
88#if 0
89/* testing code */
90#include <stdio.h>
91
92int main(void)
93{
94 unsigned long v;
95 speed_t s;
96
97 for (v = 0 ; v < 500000 ; v++) {
98 s = tty_value_to_baud(v);
99 if (s == (speed_t) -1) {
100 continue;
101 }
102 printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
103 }
104
105 printf("-------------------------------\n");
106
107 for (s = 0 ; s < 010017+1 ; s++) {
108 v = tty_baud_to_value(s);
109 if (!v) {
110 continue;
111 }
112 printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
113 }
114
115 return 0;
116}
117#endif
diff --git a/libbb/trim.c b/libbb/trim.c
new file mode 100644
index 000000000..d36391540
--- /dev/null
+++ b/libbb/trim.c
@@ -0,0 +1,31 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people.
6 * If you wrote this, please acknowledge your work.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include <stdio.h>
12#include <string.h>
13#include <ctype.h>
14#include "libbb.h"
15
16
17void trim(char *s)
18{
19 size_t len = strlen(s);
20 size_t lws;
21
22 /* trim trailing whitespace */
23 while (len && isspace(s[len-1])) --len;
24
25 /* trim leading whitespace */
26 if(len) {
27 lws = strspn(s, " \n\r\t\v");
28 memmove(s, s + lws, len -= lws);
29 }
30 s[len] = 0;
31}
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c
new file mode 100644
index 000000000..88311dd9c
--- /dev/null
+++ b/libbb/u_signal_names.c
@@ -0,0 +1,58 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Signal name/number conversion routines.
4 *
5 * Copyright 2006 Rob Landley <rob@landley.net>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12static const struct signal_name {
13 int number;
14 char name[5];
15} signals[] = {
16 // SUSv3 says kill must support these, and specifies the numerical values,
17 // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html
18 {0, "0"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"}, {6, "ABRT"}, {9, "KILL"},
19 {14, "ALRM"}, {15, "TERM"},
20 // And Posix adds the following:
21 {SIGILL, "ILL"}, {SIGTRAP, "TRAP"}, {SIGFPE, "FPE"}, {SIGUSR1, "USR1"},
22 {SIGSEGV, "SEGV"}, {SIGUSR2, "USR2"}, {SIGPIPE, "PIPE"}, {SIGCHLD, "CHLD"},
23 {SIGCONT, "CONT"}, {SIGSTOP, "STOP"}, {SIGTSTP, "TSTP"}, {SIGTTIN, "TTIN"},
24 {SIGTTOU, "TTOU"}
25};
26
27// Convert signal name to number.
28
29int get_signum(const char *name)
30{
31 int i;
32
33 i = atoi(name);
34 if (i) return i;
35 for (i = 0; i < sizeof(signals) / sizeof(struct signal_name); i++)
36 if (!strcasecmp(signals[i].name, name) ||
37 (!strncasecmp(signals[i].name, "SIG", 3)
38 && !strcasecmp(signals[i].name+3, signals[i].name)))
39 return signals[i].number;
40 return -1;
41}
42
43// Convert signal number to name
44
45const char *get_signame(int number)
46{
47 int i;
48 static char buf[8];
49
50 for (i=0; i < sizeof(signals) / sizeof(struct signal_name); i++) {
51 if (number == signals[i].number) {
52 return signals[i].name;
53 }
54 }
55
56 itoa_to_buf(number, buf, 8);
57 return buf;
58}
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
new file mode 100644
index 000000000..38401205b
--- /dev/null
+++ b/libbb/uuencode.c
@@ -0,0 +1,63 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 2006 Rob Landley <rob@landley.net>
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
6 */
7
8#include "libbb.h"
9
10/* Conversion table. for base 64 */
11const char bb_uuenc_tbl_base64[65] = {
12 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
13 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
14 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
15 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
16 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
17 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
18 'w', 'x', 'y', 'z', '0', '1', '2', '3',
19 '4', '5', '6', '7', '8', '9', '+', '/',
20 '=' /* termination character */
21};
22
23const char bb_uuenc_tbl_std[65] = {
24 '`', '!', '"', '#', '$', '%', '&', '\'',
25 '(', ')', '*', '+', ',', '-', '.', '/',
26 '0', '1', '2', '3', '4', '5', '6', '7',
27 '8', '9', ':', ';', '<', '=', '>', '?',
28 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
29 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
30 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
31 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
32 '`' /* termination character */
33};
34
35/*
36 * Encode the string S of length LENGTH to base64 format and place it
37 * to STORE. STORE will be 0-terminated, and must point to a writable
38 * buffer of at least 1+BASE64_LENGTH(length) bytes.
39 * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
40 */
41void bb_uuencode(const unsigned char *s, char *store, const int length, const char *tbl)
42{
43 int i;
44 char *p = store;
45
46 /* Transform the 3x8 bits to 4x6 bits, as required by base64. */
47 for (i = 0; i < length; i += 3) {
48 *p++ = tbl[s[0] >> 2];
49 *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
50 *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
51 *p++ = tbl[s[2] & 0x3f];
52 s += 3;
53 }
54 /* Pad the result if necessary... */
55 if (i == length + 1) {
56 *(p - 1) = tbl[64];
57 }
58 else if (i == length + 2) {
59 *(p - 1) = *(p - 2) = tbl[64];
60 }
61 /* ...and zero-terminate it. */
62 *p = '\0';
63}
diff --git a/libbb/vdprintf.c b/libbb/vdprintf.c
new file mode 100644
index 000000000..ffcb7a444
--- /dev/null
+++ b/libbb/vdprintf.c
@@ -0,0 +1,25 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <stdio.h>
11#include <unistd.h>
12#include "libbb.h"
13
14
15
16#if (__GLIBC__ < 2)
17int vdprintf(int d, const char *format, va_list ap)
18{
19 char buf[BUF_SIZE];
20 int len;
21
22 len = vsprintf(buf, format, ap);
23 return write(d, buf, len);
24}
25#endif
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c
new file mode 100644
index 000000000..0f018c517
--- /dev/null
+++ b/libbb/verror_msg.c
@@ -0,0 +1,46 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include <syslog.h>
12
13int logmode = LOGMODE_STDIO;
14const char *msg_eol = "\n";
15
16void bb_verror_msg(const char *s, va_list p, const char* strerr)
17{
18 /* va_copy is used because it is not portable
19 * to use va_list p twice */
20 va_list p2;
21 va_copy(p2, p);
22
23 if (logmode & LOGMODE_STDIO) {
24 fflush(stdout);
25 fprintf(stderr, "%s: ", applet_name);
26 vfprintf(stderr, s, p);
27 if (!strerr)
28 fputs(msg_eol, stderr);
29 else
30 fprintf(stderr, "%s%s%s",
31 s ? ": " : "",
32 strerr, msg_eol);
33 }
34 if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG)) {
35 if (!strerr)
36 vsyslog(LOG_ERR, s, p2);
37 else {
38 char *msg;
39 if (vasprintf(&msg, s, p2) < 0)
40 bb_error_msg_and_die(bb_msg_memory_exhausted);
41 syslog(LOG_ERR, "%s: %s", msg, strerr);
42 free(msg);
43 }
44 }
45 va_end(p2);
46}
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
new file mode 100644
index 000000000..ebd32f8cd
--- /dev/null
+++ b/libbb/vfork_daemon_rexec.c
@@ -0,0 +1,67 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Rexec program for system have fork() as vfork() with foreground option
4 *
5 * Copyright (C) Vladimir N. Oleynik <dzo@simtreas.ru>
6 * Copyright (C) 2003 Russ Dill <Russ.Dill@asu.edu>
7 *
8 * daemon() portion taken from uClibc:
9 *
10 * Copyright (c) 1991, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Modified for uClibc by Erik Andersen <andersee@debian.org>
14 *
15 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
16 */
17
18#include <unistd.h>
19#include <stdio.h>
20#include <fcntl.h>
21#include <paths.h>
22#include "libbb.h"
23
24
25#ifdef BB_NOMMU
26void vfork_daemon_rexec(int nochdir, int noclose,
27 int argc, char **argv, char *foreground_opt)
28{
29 int fd;
30 char **vfork_args;
31 int a = 0;
32
33 setsid();
34
35 if (!nochdir)
36 xchdir("/");
37
38 if (!noclose && (fd = open(bb_dev_null, O_RDWR, 0)) != -1) {
39 dup2(fd, STDIN_FILENO);
40 dup2(fd, STDOUT_FILENO);
41 dup2(fd, STDERR_FILENO);
42 if (fd > 2)
43 close(fd);
44 }
45
46 vfork_args = xcalloc(sizeof(char *), argc + 3);
47 vfork_args[a++] = CONFIG_BUSYBOX_EXEC_PATH;
48 while(*argv) {
49 vfork_args[a++] = *argv;
50 argv++;
51 }
52 vfork_args[a] = foreground_opt;
53 switch (vfork()) {
54 case 0: /* child */
55 /* Make certain we are not a session leader, or else we
56 * might reacquire a controlling terminal */
57 if (vfork())
58 _exit(0);
59 execv(vfork_args[0], vfork_args);
60 bb_perror_msg_and_die("execv %s", vfork_args[0]);
61 case -1: /* error */
62 bb_perror_msg_and_die("vfork");
63 default: /* parent */
64 exit(0);
65 }
66}
67#endif /* BB_NOMMU */
diff --git a/libbb/vherror_msg.c b/libbb/vherror_msg.c
new file mode 100644
index 000000000..04446a090
--- /dev/null
+++ b/libbb/vherror_msg.c
@@ -0,0 +1,15 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12void bb_vherror_msg(const char *s, va_list p)
13{
14 bb_verror_msg(s, p, hstrerror(h_errno));
15}
diff --git a/libbb/vinfo_msg.c b/libbb/vinfo_msg.c
new file mode 100644
index 000000000..fa2798625
--- /dev/null
+++ b/libbb/vinfo_msg.c
@@ -0,0 +1,26 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include <syslog.h>
12
13void bb_vinfo_msg(const char *s, va_list p)
14{
15 /* va_copy is used because it is not portable
16 * to use va_list p twice */
17 va_list p2;
18 va_copy(p2, p);
19 if (logmode & LOGMODE_STDIO) {
20 vprintf(s, p);
21 fputs(msg_eol, stdout);
22 }
23 if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG))
24 vsyslog(LOG_INFO, s, p2);
25 va_end(p2);
26}
diff --git a/libbb/vperror_msg.c b/libbb/vperror_msg.c
new file mode 100644
index 000000000..c3f79c23b
--- /dev/null
+++ b/libbb/vperror_msg.c
@@ -0,0 +1,15 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12void bb_vperror_msg(const char *s, va_list p)
13{
14 bb_verror_msg(s, p, strerror(errno));
15}
diff --git a/libbb/warn_ignoring_args.c b/libbb/warn_ignoring_args.c
new file mode 100644
index 000000000..be78a4414
--- /dev/null
+++ b/libbb/warn_ignoring_args.c
@@ -0,0 +1,17 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * warn_ignoring_args implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12void bb_warn_ignoring_args(int n)
13{
14 if (n) {
15 bb_error_msg("ignoring all arguments");
16 }
17}
diff --git a/libbb/wfopen.c b/libbb/wfopen.c
new file mode 100644
index 000000000..26e6a13e2
--- /dev/null
+++ b/libbb/wfopen.c
@@ -0,0 +1,20 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12FILE *fopen_or_warn(const char *path, const char *mode)
13{
14 FILE *fp = fopen(path, mode);
15 if (!fp) {
16 bb_perror_msg("%s", path);
17 errno = 0;
18 }
19 return fp;
20}
diff --git a/libbb/wfopen_input.c b/libbb/wfopen_input.c
new file mode 100644
index 000000000..3da855fe6
--- /dev/null
+++ b/libbb/wfopen_input.c
@@ -0,0 +1,31 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * wfopen_input implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* A number of applets need to open a file for reading, where the filename
11 * is a command line arg. Since often that arg is '-' (meaning stdin),
12 * we avoid testing everywhere by consolidating things in this routine.
13 *
14 * Note: We also consider "" to main stdin (for 'cmp' at least).
15 */
16
17#include "libbb.h"
18
19FILE *fopen_or_warn_stdin(const char *filename)
20{
21 FILE *fp = stdin;
22
23 if (filename != bb_msg_standard_input
24 && filename[0]
25 && (filename[0] != '-' || filename[1])
26 ) {
27 fp = fopen_or_warn(filename, "r");
28 }
29
30 return fp;
31}
diff --git a/libbb/xatonum.c b/libbb/xatonum.c
new file mode 100644
index 000000000..35607c317
--- /dev/null
+++ b/libbb/xatonum.c
@@ -0,0 +1,69 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ascii-to-numbers implementations for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12#define type long long
13#define xstrtou(rest) xstrtoull##rest
14#define xstrto(rest) xstrtoll##rest
15#define xatou(rest) xatoull##rest
16#define xato(rest) xatoll##rest
17#define XSTR_UTYPE_MAX ULLONG_MAX
18#define XSTR_TYPE_MAX LLONG_MAX
19#define XSTR_TYPE_MIN LLONG_MIN
20#define XSTR_STRTOU strtoull
21#include "xatonum_template.c"
22
23#if ULONG_MAX != ULLONG_MAX
24#define type long
25#define xstrtou(rest) xstrtoul##rest
26#define xstrto(rest) xstrtol##rest
27#define xatou(rest) xatoul##rest
28#define xato(rest) xatol##rest
29#define XSTR_UTYPE_MAX ULONG_MAX
30#define XSTR_TYPE_MAX LONG_MAX
31#define XSTR_TYPE_MIN LONG_MIN
32#define XSTR_STRTOU strtoul
33#include "xatonum_template.c"
34#endif
35
36#if UINT_MAX != ULONG_MAX
37extern inline unsigned bb_strtoui(const char *str, char **end, int b)
38{
39 unsigned long v = strtoul(str, end, b);
40 if (v > UINT_MAX) {
41 errno = ERANGE;
42 return UINT_MAX;
43 }
44 return v;
45}
46#define type int
47#define xstrtou(rest) xstrtou##rest
48#define xstrto(rest) xstrtoi##rest
49#define xatou(rest) xatou##rest
50#define xato(rest) xatoi##rest
51#define XSTR_UTYPE_MAX UINT_MAX
52#define XSTR_TYPE_MAX INT_MAX
53#define XSTR_TYPE_MIN INT_MIN
54/* libc has no strtoui, so we need to create/use our own */
55#define XSTR_STRTOU bb_strtoui
56#include "xatonum_template.c"
57#endif
58
59/* A few special cases */
60
61int xatoi_u(const char *numstr)
62{
63 return xatou_range(numstr, 0, INT_MAX);
64}
65
66uint16_t xatou16(const char *numstr)
67{
68 return xatou_range(numstr, 0, 0xffff);
69}
diff --git a/libbb/xatonum_template.c b/libbb/xatonum_template.c
new file mode 100644
index 000000000..53ba544eb
--- /dev/null
+++ b/libbb/xatonum_template.c
@@ -0,0 +1,185 @@
1/*
2You need to define the following (example):
3
4#define type long
5#define xstrtou(rest) xstrtoul##rest
6#define xstrto(rest) xstrtol##rest
7#define xatou(rest) xatoul##rest
8#define xato(rest) xatol##rest
9#define XSTR_UTYPE_MAX ULONG_MAX
10#define XSTR_TYPE_MAX LONG_MAX
11#define XSTR_TYPE_MIN LONG_MIN
12#define XSTR_STRTOU strtoul
13*/
14
15unsigned type xstrtou(_range_sfx)(const char *numstr, int base,
16 unsigned type lower,
17 unsigned type upper,
18 const struct suffix_mult *suffixes)
19{
20 unsigned type r;
21 int old_errno;
22 char *e;
23
24 /* Disallow '-' and any leading whitespace. Speed isn't critical here
25 * since we're parsing commandline args. So make sure we get the
26 * actual isspace function rather than a lnumstrer macro implementaion. */
27 if ((*numstr == '-') || (isspace)(*numstr))
28 goto inval;
29
30 /* Since this is a lib function, we're not allowed to reset errno to 0.
31 * Doing so could break an app that is deferring checking of errno.
32 * So, save the old value so that we can restore it if successful. */
33 old_errno = errno;
34 errno = 0;
35 r = XSTR_STRTOU(numstr, &e, base);
36 /* Do the initial validity check. Note: The standards do not
37 * guarantee that errno is set if no digits were found. So we
38 * must test for this explicitly. */
39 if (errno || (numstr == e))
40 goto inval; /* error / no digits / illegal trailing chars */
41
42 errno = old_errno; /* Ok. So restore errno. */
43
44 /* Do optional suffix parsing. Allow 'empty' suffix tables.
45 * Note that we also allow nul suffixes with associated multipliers,
46 * to allow for scaling of the numstr by some default multiplier. */
47 if (suffixes) {
48 while (suffixes->suffix) {
49 if (strcmp(suffixes->suffix, e) == 0) {
50 if (XSTR_UTYPE_MAX / suffixes->mult < r)
51 goto range; /* overflow! */
52 ++e;
53 r *= suffixes->mult;
54 break;
55 }
56 ++suffixes;
57 }
58 }
59
60 /* Note: trailing space is an error.
61 It would be easy enough to allow though if desired. */
62 if (*e)
63 goto inval;
64 /* Finally, check for range limits. */
65 if (r >= lower && r <= upper)
66 return r;
67 range:
68 bb_error_msg_and_die("number %s is not in %llu..%llu range",
69 numstr, (unsigned long long)lower,
70 (unsigned long long)upper);
71 inval:
72 bb_error_msg_and_die("invalid number '%s'", numstr);
73}
74
75unsigned type xstrtou(_range)(const char *numstr, int base,
76 unsigned type lower,
77 unsigned type upper)
78{
79 return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL);
80}
81
82unsigned type xstrtou(_sfx)(const char *numstr, int base,
83 const struct suffix_mult *suffixes)
84{
85 return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes);
86}
87
88unsigned type xstrtou()(const char *numstr, int base)
89{
90 return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL);
91}
92
93unsigned type xatou(_range_sfx)(const char *numstr,
94 unsigned type lower,
95 unsigned type upper,
96 const struct suffix_mult *suffixes)
97{
98 return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes);
99}
100
101unsigned type xatou(_range)(const char *numstr,
102 unsigned type lower,
103 unsigned type upper)
104{
105 return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL);
106}
107
108unsigned type xatou(_sfx)(const char *numstr,
109 const struct suffix_mult *suffixes)
110{
111 return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes);
112}
113
114unsigned type xatou()(const char *numstr)
115{
116 return xatou(_sfx)(numstr, NULL);
117}
118
119/* Signed ones */
120
121type xstrto(_range_sfx)(const char *numstr, int base,
122 type lower,
123 type upper,
124 const struct suffix_mult *suffixes)
125{
126 unsigned type u = XSTR_TYPE_MAX;
127 type r;
128 const char *p = numstr;
129
130 if ((p[0] == '-') && (p[1] != '+')) {
131 ++p;
132 ++u; /* two's complement */
133 }
134
135 r = xstrtou(_range_sfx)(p, base, 0, u, suffixes);
136
137 if (*numstr == '-') {
138 r = -r;
139 }
140
141 if (r < lower || r > upper) {
142 bb_error_msg_and_die("number %s is not in %lld..%lld range",
143 numstr, (long long)lower, (long long)upper);
144 }
145
146 return r;
147}
148
149type xstrto(_range)(const char *numstr, int base, type lower, type upper)
150{
151 return xstrto(_range_sfx)(numstr, base, lower, upper, NULL);
152}
153
154type xato(_range_sfx)(const char *numstr,
155 type lower,
156 type upper,
157 const struct suffix_mult *suffixes)
158{
159 return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes);
160}
161
162type xato(_range)(const char *numstr, type lower, type upper)
163{
164 return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL);
165}
166
167type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)
168{
169 return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes);
170}
171
172type xato()(const char *numstr)
173{
174 return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
175}
176
177#undef type
178#undef xstrtou
179#undef xstrto
180#undef xatou
181#undef xato
182#undef XSTR_UTYPE_MAX
183#undef XSTR_TYPE_MAX
184#undef XSTR_TYPE_MIN
185#undef XSTR_STRTOU
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
new file mode 100644
index 000000000..b85648007
--- /dev/null
+++ b/libbb/xconnect.c
@@ -0,0 +1,153 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Connect to host at port using address resolution from getaddrinfo
6 *
7 */
8
9#include "libbb.h"
10
11/* Return network byte ordered port number for a service.
12 * If "port" is a number use it as the port.
13 * If "port" is a name it is looked up in /etc/services, if it isnt found return
14 * default_port
15 */
16unsigned short bb_lookup_port(const char *port, const char *protocol, unsigned short default_port)
17{
18 unsigned short port_nr = htons(default_port);
19 if (port) {
20 char *endptr;
21 int old_errno;
22 long port_long;
23
24 /* Since this is a lib function, we're not allowed to reset errno to 0.
25 * Doing so could break an app that is deferring checking of errno. */
26 old_errno = errno;
27 errno = 0;
28 port_long = strtol(port, &endptr, 10);
29 if (errno != 0 || *endptr!='\0' || endptr==port || port_long < 0 || port_long > 65535) {
30 struct servent *tserv = getservbyname(port, protocol);
31 if (tserv) {
32 port_nr = tserv->s_port;
33 }
34 } else {
35 port_nr = htons(port_long);
36 }
37 errno = old_errno;
38 }
39 return port_nr;
40}
41
42void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
43{
44 struct hostent *he;
45
46 memset(s_in, 0, sizeof(struct sockaddr_in));
47 s_in->sin_family = AF_INET;
48 he = xgethostbyname(host);
49 memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
50}
51
52void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
53{
54 if (connect(s, s_addr, addrlen) < 0) {
55 if (ENABLE_FEATURE_CLEAN_UP) close(s);
56 if (s_addr->sa_family == AF_INET)
57 bb_perror_msg_and_die("cannot connect to remote host (%s)",
58 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
59 bb_perror_msg_and_die("cannot connect to remote host");
60 }
61}
62
63int xconnect_tcp_v4(struct sockaddr_in *s_addr)
64{
65 int s = xsocket(AF_INET, SOCK_STREAM, 0);
66 xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
67 return s;
68}
69
70static const int one = 1;
71int setsockopt_reuseaddr(int fd)
72{
73 return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
74}
75int setsockopt_broadcast(int fd)
76{
77 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
78}
79
80int dotted2sockaddr(const char *dotted, struct sockaddr* sp, int socklen)
81{
82 union {
83 struct in_addr a4;
84#if ENABLE_FEATURE_IPV6
85 struct in6_addr a6;
86#endif
87 } a;
88
89 /* TODO maybe: port spec? like n.n.n.n:nn */
90
91#if ENABLE_FEATURE_IPV6
92 if (socklen >= sizeof(struct sockaddr_in6)
93 && inet_pton(AF_INET6, dotted, &a.a6) > 0
94 ) {
95 ((struct sockaddr_in6*)sp)->sin6_family = AF_INET6;
96 ((struct sockaddr_in6*)sp)->sin6_addr = a.a6;
97 /* ((struct sockaddr_in6*)sp)->sin6_port = */
98 return 0; /* success */
99 }
100#endif
101 if (socklen >= sizeof(struct sockaddr_in)
102 && inet_pton(AF_INET, dotted, &a.a4) > 0
103 ) {
104 ((struct sockaddr_in*)sp)->sin_family = AF_INET;
105 ((struct sockaddr_in*)sp)->sin_addr = a.a4;
106 /* ((struct sockaddr_in*)sp)->sin_port = */
107 return 0; /* success */
108 }
109 return 1;
110}
111
112int xsocket_stream_ip4or6(sa_family_t *fp)
113{
114 int fd;
115#if ENABLE_FEATURE_IPV6
116 fd = socket(AF_INET6, SOCK_STREAM, 0);
117 if (fp) *fp = AF_INET6;
118 if (fd < 0)
119#endif
120 {
121 fd = xsocket(AF_INET, SOCK_STREAM, 0);
122 if (fp) *fp = AF_INET;
123 }
124 return fd;
125}
126
127int create_and_bind_socket_ip4or6(const char *hostaddr, int port)
128{
129 int fd;
130 sockaddr_inet sa;
131
132 memset(&sa, 0, sizeof(sa));
133 if (hostaddr) {
134 if (dotted2sockaddr(hostaddr, &sa.sa, sizeof(sa)))
135 bb_error_msg_and_die("bad address '%s'", hostaddr);
136 /* user specified bind addr dictates family */
137 fd = xsocket(sa.sa.sa_family, SOCK_STREAM, 0);
138 } else
139 fd = xsocket_stream_ip4or6(&sa.sa.sa_family);
140 setsockopt_reuseaddr(fd);
141
142 /* if (port >= 0) { */
143#if ENABLE_FEATURE_IPV6
144 if (sa.sa.sa_family == AF_INET6 /* && !sa.sin6.sin6_port */)
145 sa.sin6.sin6_port = htons(port);
146#endif
147 if (sa.sa.sa_family == AF_INET /* && !sa.sin.sin_port */)
148 sa.sin.sin_port = htons(port);
149 /* } */
150
151 xbind(fd, &sa.sa, sizeof(sa));
152 return fd;
153}
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
new file mode 100644
index 000000000..313e32814
--- /dev/null
+++ b/libbb/xfuncs.c
@@ -0,0 +1,521 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * Copyright (C) 2006 Rob Landley
7 * Copyright (C) 2006 Denis Vlasenko
8 *
9 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
10 */
11
12#include "busybox.h"
13
14/* All the functions starting with "x" call bb_error_msg_and_die() if they
15 * fail, so callers never need to check for errors. If it returned, it
16 * succeeded. */
17
18#ifndef DMALLOC
19/* dmalloc provides variants of these that do abort() on failure.
20 * Since dmalloc's prototypes overwrite the impls here as they are
21 * included after these prototypes in libbb.h, all is well.
22 */
23// Die if we can't allocate size bytes of memory.
24void *xmalloc(size_t size)
25{
26 void *ptr = malloc(size);
27 if (ptr == NULL && size != 0)
28 bb_error_msg_and_die(bb_msg_memory_exhausted);
29 return ptr;
30}
31
32// Die if we can't resize previously allocated memory. (This returns a pointer
33// to the new memory, which may or may not be the same as the old memory.
34// It'll copy the contents to a new chunk and free the old one if necessary.)
35void *xrealloc(void *ptr, size_t size)
36{
37 ptr = realloc(ptr, size);
38 if (ptr == NULL && size != 0)
39 bb_error_msg_and_die(bb_msg_memory_exhausted);
40 return ptr;
41}
42#endif /* DMALLOC */
43
44// Die if we can't allocate and zero size bytes of memory.
45void *xzalloc(size_t size)
46{
47 void *ptr = xmalloc(size);
48 memset(ptr, 0, size);
49 return ptr;
50}
51
52// Die if we can't copy a string to freshly allocated memory.
53char * xstrdup(const char *s)
54{
55 char *t;
56
57 if (s == NULL)
58 return NULL;
59
60 t = strdup(s);
61
62 if (t == NULL)
63 bb_error_msg_and_die(bb_msg_memory_exhausted);
64
65 return t;
66}
67
68// Die if we can't allocate n+1 bytes (space for the null terminator) and copy
69// the (possibly truncated to length n) string into it.
70char * xstrndup(const char *s, int n)
71{
72 int m;
73 char *t;
74
75 if (ENABLE_DEBUG && s == NULL)
76 bb_error_msg_and_die("xstrndup bug");
77
78 /* We can just xmalloc(n+1) and strncpy into it, */
79 /* but think about xstrndup("abc", 10000) wastage! */
80 m = n;
81 t = (char*) s;
82 while (m) {
83 if (!*t) break;
84 m--; t++;
85 }
86 n = n - m;
87 t = xmalloc(n + 1);
88 t[n] = '\0';
89
90 return memcpy(t,s,n);
91}
92
93// Die if we can't open a file and return a FILE * to it.
94// Notice we haven't got xfread(), This is for use with fscanf() and friends.
95FILE *xfopen(const char *path, const char *mode)
96{
97 FILE *fp = fopen(path, mode);
98 if (fp == NULL)
99 bb_perror_msg_and_die("%s", path);
100 return fp;
101}
102
103// Die if we can't open an existing file and return an fd.
104int xopen(const char *pathname, int flags)
105{
106 //if (ENABLE_DEBUG && (flags & O_CREAT))
107 // bb_error_msg_and_die("xopen() with O_CREAT");
108
109 return xopen3(pathname, flags, 0666);
110}
111
112// Die if we can't open a new file and return an fd.
113int xopen3(const char *pathname, int flags, int mode)
114{
115 int ret;
116
117 ret = open(pathname, flags, mode);
118 if (ret < 0) {
119 bb_perror_msg_and_die("%s", pathname);
120 }
121 return ret;
122}
123
124/*
125int ndelay_off(int fd)
126{
127 return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK);
128}
129*/
130// Turn on nonblocking I/O on a fd
131int ndelay_on(int fd)
132{
133 return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK);
134}
135
136// Die with an error message if we can't write the entire buffer.
137void xwrite(int fd, const void *buf, size_t count)
138{
139 if (count) {
140 ssize_t size = full_write(fd, buf, count);
141 if (size != count)
142 bb_error_msg_and_die("short write");
143 }
144}
145
146// Die with an error message if we can't lseek to the right spot.
147off_t xlseek(int fd, off_t offset, int whence)
148{
149 off_t off = lseek(fd, offset, whence);
150 if (off == (off_t)-1) {
151 if (whence == SEEK_SET)
152 bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
153 bb_perror_msg_and_die("lseek");
154 }
155 return off;
156}
157
158// Die with supplied filename if this FILE * has ferror set.
159void die_if_ferror(FILE *fp, const char *fn)
160{
161 if (ferror(fp)) {
162 bb_error_msg_and_die("%s: I/O error", fn);
163 }
164}
165
166// Die with an error message if stdout has ferror set.
167void die_if_ferror_stdout(void)
168{
169 die_if_ferror(stdout, bb_msg_standard_output);
170}
171
172// Die with an error message if we have trouble flushing stdout.
173void xfflush_stdout(void)
174{
175 if (fflush(stdout)) {
176 bb_perror_msg_and_die(bb_msg_standard_output);
177 }
178}
179
180// This does a fork/exec in one call, using vfork(). Return PID of new child,
181// -1 for failure. Runs argv[0], searching path if that has no / in it.
182pid_t spawn(char **argv)
183{
184 static int failed;
185 pid_t pid;
186 void *app = ENABLE_FEATURE_SH_STANDALONE_SHELL ? find_applet_by_name(argv[0]) : 0;
187
188 // Be nice to nommu machines.
189 failed = 0;
190 pid = vfork();
191 if (pid < 0) return pid;
192 if (!pid) {
193 execvp(app ? CONFIG_BUSYBOX_EXEC_PATH : *argv, argv);
194
195 // We're sharing a stack with blocked parent, let parent know we failed
196 // and then exit to unblock parent (but don't run atexit() stuff, which
197 // would screw up parent.)
198
199 failed = -1;
200 _exit(0);
201 }
202 return failed ? failed : pid;
203}
204
205// Die with an error message if we can't spawn a child process.
206pid_t xspawn(char **argv)
207{
208 pid_t pid = spawn(argv);
209 if (pid < 0) bb_perror_msg_and_die("%s", *argv);
210 return pid;
211}
212
213// Wait for the specified child PID to exit, returning child's error return.
214int wait4pid(int pid)
215{
216 int status;
217
218 if (pid == -1 || waitpid(pid, &status, 0) == -1) return -1;
219 if (WIFEXITED(status)) return WEXITSTATUS(status);
220 if (WIFSIGNALED(status)) return WTERMSIG(status);
221 return 0;
222}
223
224void xsetenv(const char *key, const char *value)
225{
226 if (setenv(key, value, 1))
227 bb_error_msg_and_die(bb_msg_memory_exhausted);
228}
229
230// Converts unsigned long long value into compact 4-char
231// representation. Examples: "1234", "1.2k", " 27M", "123T"
232// Fifth char is always '\0'
233void smart_ulltoa5(unsigned long long ul, char buf[5])
234{
235 char *fmt;
236 char c;
237 unsigned v,idx = 0;
238 ul *= 10;
239 if (ul > 9999*10) { // do not scale if 9999 or less
240 while (ul >= 10000) {
241 ul /= 1024;
242 idx++;
243 }
244 }
245 v = ul; // ullong divisions are expensive, avoid them
246
247 fmt = " 123456789";
248 if (!idx) { // 9999 or less: use 1234 format
249 c = buf[0] = " 123456789"[v/10000];
250 if (c!=' ') fmt = "0123456789";
251 c = buf[1] = fmt[v/1000%10];
252 if (c!=' ') fmt = "0123456789";
253 buf[2] = fmt[v/100%10];
254 buf[3] = "0123456789"[v/10%10];
255 } else {
256 if (v>=10*10) { // scaled value is >=10: use 123M format
257 c = buf[0] = " 123456789"[v/1000];
258 if (c!=' ') fmt = "0123456789";
259 buf[1] = fmt[v/100%10];
260 buf[2] = "0123456789"[v/10%10];
261 } else { // scaled value is <10: use 1.2M format
262 buf[0] = "0123456789"[v/10];
263 buf[1] = '.';
264 buf[2] = "0123456789"[v%10];
265 }
266 // see http://en.wikipedia.org/wiki/Tera
267 buf[3] = " kMGTPEZY"[idx];
268 }
269 buf[4] = '\0';
270}
271
272// Convert unsigned integer to ascii, writing into supplied buffer. A
273// truncated result is always null terminated (unless buflen is 0), and
274// contains the first few digits of the result ala strncpy.
275void BUG_sizeof_unsigned_not_4(void);
276void utoa_to_buf(unsigned n, char *buf, unsigned buflen)
277{
278 unsigned i, out, res;
279 if (sizeof(unsigned) != 4)
280 BUG_sizeof_unsigned_not_4();
281 if (buflen) {
282 out = 0;
283 for (i = 1000000000; i; i /= 10) {
284 res = n / i;
285 if (res || out || i == 1) {
286 if (!--buflen) break;
287 out++;
288 n -= res*i;
289 *buf++ = '0' + res;
290 }
291 }
292 *buf = '\0';
293 }
294}
295
296// Convert signed integer to ascii, like utoa_to_buf()
297void itoa_to_buf(int n, char *buf, unsigned buflen)
298{
299 if (buflen && n<0) {
300 n = -n;
301 *buf++ = '-';
302 buflen--;
303 }
304 utoa_to_buf((unsigned)n, buf, buflen);
305}
306
307// The following two functions use a static buffer, so calling either one a
308// second time will overwrite previous results.
309//
310// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes.
311// Int should always be 32 bits on any remotely Unix-like system, see
312// http://www.unix.org/whitepapers/64bit.html for the reasons why.
313
314static char local_buf[12];
315
316// Convert unsigned integer to ascii using a static buffer (returned).
317char *utoa(unsigned n)
318{
319 utoa_to_buf(n, local_buf, sizeof(local_buf));
320
321 return local_buf;
322}
323
324// Convert signed integer to ascii using a static buffer (returned).
325char *itoa(int n)
326{
327 itoa_to_buf(n, local_buf, sizeof(local_buf));
328
329 return local_buf;
330}
331
332// Die with an error message if we can't set gid. (Because resource limits may
333// limit this user to a given number of processes, and if that fills up the
334// setgid() will fail and we'll _still_be_root_, which is bad.)
335void xsetgid(gid_t gid)
336{
337 if (setgid(gid)) bb_error_msg_and_die("setgid");
338}
339
340// Die with an error message if we can't set uid. (See xsetgid() for why.)
341void xsetuid(uid_t uid)
342{
343 if (setuid(uid)) bb_error_msg_and_die("setuid");
344}
345
346// Return how long the file at fd is, if there's any way to determine it.
347off_t fdlength(int fd)
348{
349 off_t bottom = 0, top = 0, pos;
350 long size;
351
352 // If the ioctl works for this, return it.
353
354 if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512;
355
356 // FIXME: explain why lseek(SEEK_END) is not used here!
357
358 // If not, do a binary search for the last location we can read. (Some
359 // block devices don't do BLKGETSIZE right.)
360
361 do {
362 char temp;
363
364 pos = bottom + (top - bottom) / 2;
365
366 // If we can read from the current location, it's bigger.
367
368 if (lseek(fd, pos, SEEK_SET)>=0 && safe_read(fd, &temp, 1)==1) {
369 if (bottom == top) bottom = top = (top+1) * 2;
370 else bottom = pos;
371
372 // If we can't, it's smaller.
373
374 } else {
375 if (bottom == top) {
376 if (!top) return 0;
377 bottom = top/2;
378 }
379 else top = pos;
380 }
381 } while (bottom + 1 != top);
382
383 return pos + 1;
384}
385
386// Die with an error message if we can't malloc() enough space and do an
387// sprintf() into that space.
388char *xasprintf(const char *format, ...)
389{
390 va_list p;
391 int r;
392 char *string_ptr;
393
394#if 1
395 // GNU extension
396 va_start(p, format);
397 r = vasprintf(&string_ptr, format, p);
398 va_end(p);
399#else
400 // Bloat for systems that haven't got the GNU extension.
401 va_start(p, format);
402 r = vsnprintf(NULL, 0, format, p);
403 va_end(p);
404 string_ptr = xmalloc(r+1);
405 va_start(p, format);
406 r = vsnprintf(string_ptr, r+1, format, p);
407 va_end(p);
408#endif
409
410 if (r < 0) bb_error_msg_and_die(bb_msg_memory_exhausted);
411 return string_ptr;
412}
413
414// Die with an error message if we can't copy an entire FILE * to stdout, then
415// close that file.
416void xprint_and_close_file(FILE *file)
417{
418 fflush(stdout);
419 // copyfd outputs error messages for us.
420 if (bb_copyfd_eof(fileno(file), 1) == -1)
421 exit(xfunc_error_retval);
422
423 fclose(file);
424}
425
426// Die if we can't chdir to a new path.
427void xchdir(const char *path)
428{
429 if (chdir(path))
430 bb_perror_msg_and_die("chdir(%s)", path);
431}
432
433// Print a warning message if opendir() fails, but don't die.
434DIR *warn_opendir(const char *path)
435{
436 DIR *dp;
437
438 if ((dp = opendir(path)) == NULL) {
439 bb_perror_msg("cannot open '%s'", path);
440 return NULL;
441 }
442 return dp;
443}
444
445// Die with an error message if opendir() fails.
446DIR *xopendir(const char *path)
447{
448 DIR *dp;
449
450 if ((dp = opendir(path)) == NULL)
451 bb_perror_msg_and_die("cannot open '%s'", path);
452 return dp;
453}
454
455#ifndef BB_NOMMU
456// Die with an error message if we can't daemonize.
457void xdaemon(int nochdir, int noclose)
458{
459 if (daemon(nochdir, noclose))
460 bb_perror_msg_and_die("daemon");
461}
462#endif
463
464// Die with an error message if we can't open a new socket.
465int xsocket(int domain, int type, int protocol)
466{
467 int r = socket(domain, type, protocol);
468
469 if (r < 0) bb_perror_msg_and_die("socket");
470
471 return r;
472}
473
474// Die with an error message if we can't bind a socket to an address.
475void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
476{
477 if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind");
478}
479
480// Die with an error message if we can't listen for connections on a socket.
481void xlisten(int s, int backlog)
482{
483 if (listen(s, backlog)) bb_perror_msg_and_die("listen");
484}
485
486// xstat() - a stat() which dies on failure with meaningful error message
487void xstat(char *name, struct stat *stat_buf)
488{
489 if (stat(name, stat_buf))
490 bb_perror_msg_and_die("can't stat '%s'", name);
491}
492
493/* It is perfectly ok to pass in a NULL for either width or for
494 * height, in which case that value will not be set. */
495int get_terminal_width_height(int fd, int *width, int *height)
496{
497 struct winsize win = { 0, 0, 0, 0 };
498 int ret = ioctl(fd, TIOCGWINSZ, &win);
499
500 if (height) {
501 if (!win.ws_row) {
502 char *s = getenv("LINES");
503 if (s) win.ws_row = atoi(s);
504 }
505 if (win.ws_row <= 1 || win.ws_row >= 30000)
506 win.ws_row = 24;
507 *height = (int) win.ws_row;
508 }
509
510 if (width) {
511 if (!win.ws_col) {
512 char *s = getenv("COLUMNS");
513 if (s) win.ws_col = atoi(s);
514 }
515 if (win.ws_col <= 1 || win.ws_col >= 30000)
516 win.ws_col = 80;
517 *width = (int) win.ws_col;
518 }
519
520 return ret;
521}
diff --git a/libbb/xgetcwd.c b/libbb/xgetcwd.c
new file mode 100644
index 000000000..0ac450d3b
--- /dev/null
+++ b/libbb/xgetcwd.c
@@ -0,0 +1,44 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * xgetcwd.c -- return current directory with unlimited length
4 * Copyright (C) 1992, 1996 Free Software Foundation, Inc.
5 * Written by David MacKenzie <djm@gnu.ai.mit.edu>.
6 *
7 * Special function for busybox written by Vladimir Oleynik <dzo@simtreas.ru>
8*/
9
10#include "libbb.h"
11
12/* Amount to increase buffer size by in each try. */
13#define PATH_INCR 32
14
15/* Return the current directory, newly allocated, arbitrarily long.
16 Return NULL and set errno on error.
17 If argument is not NULL (previous usage allocate memory), call free()
18*/
19
20char *
21xgetcwd(char *cwd)
22{
23 char *ret;
24 unsigned path_max;
25
26 path_max = (unsigned) PATH_MAX;
27 path_max += 2; /* The getcwd docs say to do this. */
28
29 if (cwd==0)
30 cwd = xmalloc(path_max);
31
32 while ((ret = getcwd(cwd, path_max)) == NULL && errno == ERANGE) {
33 path_max += PATH_INCR;
34 cwd = xrealloc(cwd, path_max);
35 }
36
37 if (ret == NULL) {
38 free(cwd);
39 bb_perror_msg("getcwd");
40 return NULL;
41 }
42
43 return cwd;
44}
diff --git a/libbb/xgethostbyname.c b/libbb/xgethostbyname.c
new file mode 100644
index 000000000..c3158c339
--- /dev/null
+++ b/libbb/xgethostbyname.c
@@ -0,0 +1,19 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini xgethostbyname implementation.
4 *
5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <netdb.h>
11#include "libbb.h"
12
13struct hostent *xgethostbyname(const char *name)
14{
15 struct hostent *retval = gethostbyname(name);
16 if (!retval)
17 bb_herror_msg_and_die("%s", name);
18 return retval;
19}
diff --git a/libbb/xgethostbyname2.c b/libbb/xgethostbyname2.c
new file mode 100644
index 000000000..83d538669
--- /dev/null
+++ b/libbb/xgethostbyname2.c
@@ -0,0 +1,22 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini xgethostbyname2 implementation.
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
6 */
7
8#include <netdb.h>
9#include "libbb.h"
10
11
12#ifdef CONFIG_FEATURE_IPV6
13struct hostent *xgethostbyname2(const char *name, int af)
14{
15 struct hostent *retval;
16
17 if ((retval = gethostbyname2(name, af)) == NULL)
18 bb_herror_msg_and_die("%s", name);
19
20 return retval;
21}
22#endif
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
new file mode 100644
index 000000000..14863d9d5
--- /dev/null
+++ b/libbb/xreadlink.c
@@ -0,0 +1,38 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * xreadlink.c - safe implementation of readlink.
4 * Returns a NULL on failure...
5 */
6
7#include <stdio.h>
8
9/*
10 * NOTE: This function returns a malloced char* that you will have to free
11 * yourself. You have been warned.
12 */
13
14#include <unistd.h>
15#include "libbb.h"
16
17char *xreadlink(const char *path)
18{
19 enum { GROWBY = 80 }; /* how large we will grow strings by */
20
21 char *buf = NULL;
22 int bufsize = 0, readsize = 0;
23
24 do {
25 buf = xrealloc(buf, bufsize += GROWBY);
26 readsize = readlink(path, buf, bufsize); /* 1st try */
27 if (readsize == -1) {
28 bb_perror_msg("%s", path);
29 free(buf);
30 return NULL;
31 }
32 }
33 while (bufsize < readsize + 1);
34
35 buf[readsize] = '\0';
36
37 return buf;
38}
diff --git a/libbb/xregcomp.c b/libbb/xregcomp.c
new file mode 100644
index 000000000..4bcb9aedf
--- /dev/null
+++ b/libbb/xregcomp.c
@@ -0,0 +1,26 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) many different people.
6 * If you wrote this, please acknowledge your work.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include <stdio.h>
12#include "libbb.h"
13#include "xregex.h"
14
15
16
17void xregcomp(regex_t *preg, const char *regex, int cflags)
18{
19 int ret;
20 if ((ret = regcomp(preg, regex, cflags)) != 0) {
21 int errmsgsz = regerror(ret, preg, NULL, 0);
22 char *errmsg = xmalloc(errmsgsz);
23 regerror(ret, preg, errmsg, errmsgsz);
24 bb_error_msg_and_die("xregcomp: %s", errmsg);
25 }
26}