aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2015-03-14 20:33:00 +0000
committerRon Yorston <rmy@pobox.com>2015-03-14 20:33:00 +0000
commita4f58436b78fe59e57620c6e0301f213ee25f273 (patch)
tree8355f724926e605280af2d6f2b1ccc6b1bd02dee /libbb
parentba0c36cfcf84efbac6f89e27238e04bb57e9cd45 (diff)
parent49acc1a7618a28d34381cbb7661d7c981fcb238f (diff)
downloadbusybox-w32-a4f58436b78fe59e57620c6e0301f213ee25f273.tar.gz
busybox-w32-a4f58436b78fe59e57620c6e0301f213ee25f273.tar.bz2
busybox-w32-a4f58436b78fe59e57620c6e0301f213ee25f273.zip
Merge branch 'busybox' into merge
Conflicts: coreutils/od_bloaty.c libbb/lineedit.c
Diffstat (limited to 'libbb')
-rw-r--r--libbb/appletlib.c8
-rw-r--r--libbb/bb_pwd.c48
-rw-r--r--libbb/compare_string_array.c23
-rw-r--r--libbb/inet_common.c84
-rw-r--r--libbb/lineedit.c35
-rw-r--r--libbb/loop.c11
-rw-r--r--libbb/match_fstype.c7
-rw-r--r--libbb/procps.c12
-rw-r--r--libbb/rtc.c2
-rw-r--r--libbb/skip_whitespace.c2
-rw-r--r--libbb/update_passwd.c45
-rw-r--r--libbb/utmp.c14
-rw-r--r--libbb/xconnect.c2
13 files changed, 142 insertions, 151 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index dba66cc93..3f51ecef6 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -197,7 +197,7 @@ void lbb_prepare(const char *applet
197 if (argv[1] 197 if (argv[1]
198 && !argv[2] 198 && !argv[2]
199 && strcmp(argv[1], "--help") == 0 199 && strcmp(argv[1], "--help") == 0
200 && strncmp(applet, "busybox", 7) != 0 200 && !is_prefixed_with(applet, "busybox")
201 ) { 201 ) {
202 /* Special case. POSIX says "test --help" 202 /* Special case. POSIX says "test --help"
203 * should be no different from e.g. "test --foo". */ 203 * should be no different from e.g. "test --foo". */
@@ -686,7 +686,7 @@ static int busybox_main(char **argv)
686 return 0; 686 return 0;
687 } 687 }
688 688
689 if (strncmp(argv[1], "--list", 6) == 0) { 689 if (is_prefixed_with(argv[1], "--list")) {
690 unsigned i = 0; 690 unsigned i = 0;
691 const char *a = applet_names; 691 const char *a = applet_names;
692 dup2(1, 2); 692 dup2(1, 2);
@@ -791,7 +791,7 @@ void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
791 int applet = find_applet_by_name(name); 791 int applet = find_applet_by_name(name);
792 if (applet >= 0) 792 if (applet >= 0)
793 run_applet_no_and_exit(applet, argv); 793 run_applet_no_and_exit(applet, argv);
794 if (strncmp(name, "busybox", 7) == 0) 794 if (is_prefixed_with(name, "busybox"))
795 exit(busybox_main(argv)); 795 exit(busybox_main(argv));
796} 796}
797 797
@@ -842,7 +842,7 @@ int main(int argc UNUSED_PARAM, char **argv)
842 842
843#if defined(SINGLE_APPLET_MAIN) 843#if defined(SINGLE_APPLET_MAIN)
844 /* Only one applet is selected in .config */ 844 /* Only one applet is selected in .config */
845 if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) { 845 if (argv[1] && is_prefixed_with(argv[0], "busybox")) {
846 /* "busybox <applet> <params>" should still work as expected */ 846 /* "busybox <applet> <params>" should still work as expected */
847 argv++; 847 argv++;
848 } 848 }
diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c
index 8250cd446..4829b723a 100644
--- a/libbb/bb_pwd.c
+++ b/libbb/bb_pwd.c
@@ -110,51 +110,3 @@ unsigned long FAST_FUNC get_ug_id(const char *s,
110 return xname2id(s); 110 return xname2id(s);
111 return r; 111 return r;
112} 112}
113
114/* Experimental "mallocing" API.
115 * The goal is nice: "we want to support a case when "guests" group is very large"
116 * but the code is butt-ugly.
117 */
118#if 0
119static char *find_latest(char last, char *cp)
120{
121 if (!cp)
122 return last;
123 cp += strlen(cp) + 1;
124 if (last < cp)
125 last = cp;
126 return last;
127}
128
129struct group* FAST_FUNC xmalloc_getgrnam(const char *name)
130{
131 struct {
132 struct group gr;
133 // May still be not enough!
134 char buf[64*1024 - sizeof(struct group) - 16];
135 } *s;
136 struct group *grp;
137 int r;
138 char *last;
139 char **gr_mem;
140
141 s = xmalloc(sizeof(*s));
142 r = getgrnam_r(name, &s->gr, s->buf, sizeof(s->buf), &grp);
143 if (!grp) {
144 free(s);
145 return grp;
146 }
147 last = find_latest(s->buf, grp->gr_name);
148 last = find_latest(last, grp->gr_passwd);
149 gr_mem = grp->gr_mem;
150 while (*gr_mem)
151 last = find_latest(last, *gr_mem++);
152 gr_mem++; /* points past NULL */
153 if (last < (char*)gr_mem)
154 last = (char*)gr_mem;
155//FIXME: what if we get not only truncated, but also moved here?
156// grp->gr_name pointer and friends are invalid now!!!
157 s = xrealloc(s, last - (char*)s);
158 return grp;
159}
160#endif
diff --git a/libbb/compare_string_array.c b/libbb/compare_string_array.c
index 4b10cc138..e24815a03 100644
--- a/libbb/compare_string_array.c
+++ b/libbb/compare_string_array.c
@@ -5,6 +5,24 @@
5 5
6#include "libbb.h" 6#include "libbb.h"
7 7
8char* FAST_FUNC is_prefixed_with(const char *string, const char *key)
9{
10#if 0 /* Two passes over key - probably slower */
11 int len = strlen(key);
12 if (strncmp(string, key, len) == 0)
13 return string + len;
14 return NULL;
15#else /* Open-coded */
16 while (*key != '\0') {
17 if (*key != *string)
18 return NULL;
19 key++;
20 string++;
21 }
22 return (char*)string;
23#endif
24}
25
8/* returns the array index of the string */ 26/* returns the array index of the string */
9/* (index of first match is returned, or -1) */ 27/* (index of first match is returned, or -1) */
10int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key) 28int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key)
@@ -39,10 +57,9 @@ int FAST_FUNC index_in_strings(const char *strings, const char *key)
39int FAST_FUNC index_in_substr_array(const char *const string_array[], const char *key) 57int FAST_FUNC index_in_substr_array(const char *const string_array[], const char *key)
40{ 58{
41 int i; 59 int i;
42 int len = strlen(key); 60 if (key[0]) {
43 if (len) {
44 for (i = 0; string_array[i] != 0; i++) { 61 for (i = 0; string_array[i] != 0; i++) {
45 if (strncmp(string_array[i], key, len) == 0) { 62 if (is_prefixed_with(string_array[i], key)) {
46 return i; 63 return i;
47 } 64 }
48 } 65 }
diff --git a/libbb/inet_common.c b/libbb/inet_common.c
index b3e0802ee..5b4a4a10b 100644
--- a/libbb/inet_common.c
+++ b/libbb/inet_common.c
@@ -32,14 +32,12 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf
32 return 0; 32 return 0;
33 } 33 }
34 /* If we expect this to be a hostname, try hostname database first */ 34 /* If we expect this to be a hostname, try hostname database first */
35#ifdef DEBUG
36 if (hostfirst) { 35 if (hostfirst) {
36#ifdef DEBUG
37 bb_error_msg("gethostbyname(%s)", name); 37 bb_error_msg("gethostbyname(%s)", name);
38 }
39#endif 38#endif
40 if (hostfirst) {
41 hp = gethostbyname(name); 39 hp = gethostbyname(name);
42 if (hp != NULL) { 40 if (hp) {
43 memcpy(&s_in->sin_addr, hp->h_addr_list[0], 41 memcpy(&s_in->sin_addr, hp->h_addr_list[0],
44 sizeof(struct in_addr)); 42 sizeof(struct in_addr));
45 return 0; 43 return 0;
@@ -51,7 +49,7 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf
51 bb_error_msg("getnetbyname(%s)", name); 49 bb_error_msg("getnetbyname(%s)", name);
52#endif 50#endif
53 np = getnetbyname(name); 51 np = getnetbyname(name);
54 if (np != NULL) { 52 if (np) {
55 s_in->sin_addr.s_addr = htonl(np->n_net); 53 s_in->sin_addr.s_addr = htonl(np->n_net);
56 return 1; 54 return 1;
57 } 55 }
@@ -66,7 +64,7 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf
66 bb_error_msg("gethostbyname(%s)", name); 64 bb_error_msg("gethostbyname(%s)", name);
67#endif 65#endif
68 hp = gethostbyname(name); 66 hp = gethostbyname(name);
69 if (hp == NULL) { 67 if (!hp) {
70 return -1; 68 return -1;
71 } 69 }
72 memcpy(&s_in->sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); 70 memcpy(&s_in->sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
@@ -74,7 +72,7 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf
74} 72}
75 73
76 74
77/* numeric: & 0x8000: default instead of *, 75/* numeric: & 0x8000: "default" instead of "*",
78 * & 0x4000: host instead of net, 76 * & 0x4000: host instead of net,
79 * & 0x0fff: don't resolve 77 * & 0x0fff: don't resolve
80 */ 78 */
@@ -83,16 +81,16 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne
83 /* addr-to-name cache */ 81 /* addr-to-name cache */
84 struct addr { 82 struct addr {
85 struct addr *next; 83 struct addr *next;
86 struct sockaddr_in addr; 84 uint32_t nip;
87 int host; 85 smallint is_host;
88 char name[1]; 86 char name[1];
89 }; 87 };
90 static struct addr *cache = NULL; 88 static struct addr *cache = NULL;
91 89
92 struct addr *pn; 90 struct addr *pn;
93 char *name; 91 char *name;
94 uint32_t ad, host_ad; 92 uint32_t nip;
95 int host = 0; 93 smallint is_host;
96 94
97 if (s_in->sin_family != AF_INET) { 95 if (s_in->sin_family != AF_INET) {
98#ifdef DEBUG 96#ifdef DEBUG
@@ -102,61 +100,57 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne
102 errno = EAFNOSUPPORT; 100 errno = EAFNOSUPPORT;
103 return NULL; 101 return NULL;
104 } 102 }
105 ad = s_in->sin_addr.s_addr; 103 nip = s_in->sin_addr.s_addr;
106#ifdef DEBUG 104#ifdef DEBUG
107 bb_error_msg("rresolve: %08x, mask %08x, num %08x", (unsigned)ad, netmask, numeric); 105 bb_error_msg("rresolve: %08x mask:%08x num:%08x", (unsigned)nip, netmask, numeric);
108#endif 106#endif
109 if (ad == INADDR_ANY) {
110 if ((numeric & 0x0FFF) == 0) {
111 if (numeric & 0x8000)
112 return xstrdup("default");
113 return xstrdup("*");
114 }
115 }
116 if (numeric & 0x0FFF) 107 if (numeric & 0x0FFF)
117 return xstrdup(inet_ntoa(s_in->sin_addr)); 108 return xmalloc_sockaddr2dotted_noport((void*)s_in);
109 if (nip == INADDR_ANY) {
110 if (numeric & 0x8000)
111 return xstrdup("default");
112 return xstrdup("*");
113 }
114
115 is_host = ((nip & (~netmask)) != 0 || (numeric & 0x4000));
118 116
119 if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
120 host = 1;
121 pn = cache; 117 pn = cache;
122 while (pn) { 118 while (pn) {
123 if (pn->addr.sin_addr.s_addr == ad && pn->host == host) { 119 if (pn->nip == nip && pn->is_host == is_host) {
124#ifdef DEBUG 120#ifdef DEBUG
125 bb_error_msg("rresolve: found %s %08x in cache", 121 bb_error_msg("rresolve: found %s %08x in cache",
126 (host ? "host" : "net"), (unsigned)ad); 122 (is_host ? "host" : "net"), (unsigned)nip);
127#endif 123#endif
128 return xstrdup(pn->name); 124 return xstrdup(pn->name);
129 } 125 }
130 pn = pn->next; 126 pn = pn->next;
131 } 127 }
132 128
133 host_ad = ntohl(ad);
134 name = NULL; 129 name = NULL;
135 if (host) { 130 if (is_host) {
136 struct hostent *ent;
137#ifdef DEBUG 131#ifdef DEBUG
138 bb_error_msg("gethostbyaddr (%08x)", (unsigned)ad); 132 bb_error_msg("sockaddr2host_noport(%08x)", (unsigned)nip);
139#endif 133#endif
140 ent = gethostbyaddr((char *) &ad, 4, AF_INET); 134 name = xmalloc_sockaddr2host_noport((void*)s_in);
141 if (ent)
142 name = xstrdup(ent->h_name);
143 } else if (ENABLE_FEATURE_ETC_NETWORKS) { 135 } else if (ENABLE_FEATURE_ETC_NETWORKS) {
144 struct netent *np; 136 struct netent *np;
145#ifdef DEBUG 137#ifdef DEBUG
146 bb_error_msg("getnetbyaddr (%08x)", (unsigned)host_ad); 138 bb_error_msg("getnetbyaddr(%08x)", (unsigned)ntohl(nip));
147#endif 139#endif
148 np = getnetbyaddr(host_ad, AF_INET); 140 np = getnetbyaddr(ntohl(nip), AF_INET);
149 if (np) 141 if (np)
150 name = xstrdup(np->n_name); 142 name = xstrdup(np->n_name);
151 } 143 }
152 if (!name) 144 if (!name)
153 name = xstrdup(inet_ntoa(s_in->sin_addr)); 145 name = xmalloc_sockaddr2dotted_noport((void*)s_in);
146
154 pn = xmalloc(sizeof(*pn) + strlen(name)); /* no '+ 1', it's already accounted for */ 147 pn = xmalloc(sizeof(*pn) + strlen(name)); /* no '+ 1', it's already accounted for */
155 pn->next = cache; 148 pn->next = cache;
156 pn->addr = *s_in; 149 pn->nip = nip;
157 pn->host = host; 150 pn->is_host = is_host;
158 strcpy(pn->name, name); 151 strcpy(pn->name, name);
159 cache = pn; 152 cache = pn;
153
160 return name; 154 return name;
161} 155}
162 156
@@ -188,9 +182,6 @@ int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
188 182
189char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) 183char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
190{ 184{
191 char name[128];
192 int s;
193
194 if (sin6->sin6_family != AF_INET6) { 185 if (sin6->sin6_family != AF_INET6) {
195#ifdef DEBUG 186#ifdef DEBUG
196 bb_error_msg("rresolve: unsupported address family %d!", 187 bb_error_msg("rresolve: unsupported address family %d!",
@@ -200,8 +191,7 @@ char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
200 return NULL; 191 return NULL;
201 } 192 }
202 if (numeric & 0x7FFF) { 193 if (numeric & 0x7FFF) {
203 inet_ntop(AF_INET6, &sin6->sin6_addr, name, sizeof(name)); 194 return xmalloc_sockaddr2dotted_noport((void*)sin6);
204 return xstrdup(name);
205 } 195 }
206 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 196 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
207 if (numeric & 0x8000) 197 if (numeric & 0x8000)
@@ -209,15 +199,7 @@ char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
209 return xstrdup("*"); 199 return xstrdup("*");
210 } 200 }
211 201
212 s = getnameinfo((struct sockaddr *) sin6, sizeof(*sin6), 202 return xmalloc_sockaddr2host_noport((void*)sin6);
213 name, sizeof(name),
214 /*serv,servlen:*/ NULL, 0,
215 0);
216 if (s != 0) {
217 bb_error_msg("getnameinfo failed");
218 return NULL;
219 }
220 return xstrdup(name);
221} 203}
222 204
223#endif /* CONFIG_FEATURE_IPV6 */ 205#endif /* CONFIG_FEATURE_IPV6 */
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 3d96a8e9f..7982f2997 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -714,23 +714,20 @@ static char *username_path_completion(char *ud)
714 */ 714 */
715static NOINLINE unsigned complete_username(const char *ud) 715static NOINLINE unsigned complete_username(const char *ud)
716{ 716{
717 /* Using _r function to avoid pulling in static buffers */ 717 struct passwd *pw;
718 char line_buff[256];
719 struct passwd pwd;
720 struct passwd *result;
721 unsigned userlen; 718 unsigned userlen;
722 719
723 ud++; /* skip ~ */ 720 ud++; /* skip ~ */
724 userlen = strlen(ud); 721 userlen = strlen(ud);
725 722
726 setpwent(); 723 setpwent();
727 while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) { 724 while ((pw = getpwent()) != NULL) {
728 /* Null usernames should result in all users as possible completions. */ 725 /* Null usernames should result in all users as possible completions. */
729 if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) { 726 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) {
730 add_match(xasprintf("~%s/", pwd.pw_name)); 727 add_match(xasprintf("~%s/", pw->pw_name));
731 } 728 }
732 } 729 }
733 endpwent(); 730 endpwent(); /* don't keep password file open */
734 731
735 return 1 + userlen; 732 return 1 + userlen;
736} 733}
@@ -845,7 +842,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
845 if (!pfind[0] && DOT_OR_DOTDOT(name_found)) 842 if (!pfind[0] && DOT_OR_DOTDOT(name_found))
846 continue; 843 continue;
847 /* match? */ 844 /* match? */
848 if (strncmp(name_found, pfind, pf_len) != 0) 845 if (!is_prefixed_with(name_found, pfind))
849 continue; /* no */ 846 continue; /* no */
850 847
851 found = concat_path_file(paths[i], name_found); 848 found = concat_path_file(paths[i], name_found);
@@ -1932,19 +1929,25 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1932 cwd_buf = xrealloc_getcwd_or_warn(NULL); 1929 cwd_buf = xrealloc_getcwd_or_warn(NULL);
1933 if (!cwd_buf) 1930 if (!cwd_buf)
1934 cwd_buf = (char *)bb_msg_unknown; 1931 cwd_buf = (char *)bb_msg_unknown;
1935 else { 1932 else if (home_pwd_buf[0]) {
1933 char *after_home_user;
1934
1936 /* /home/user[/something] -> ~[/something] */ 1935 /* /home/user[/something] -> ~[/something] */
1937 l = strlen(home_pwd_buf);
1938 if (l != 0
1939#if !ENABLE_PLATFORM_MINGW32 1936#if !ENABLE_PLATFORM_MINGW32
1940 && strncmp(home_pwd_buf, cwd_buf, l) == 0 1937 after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf);
1941#else 1938#else
1942 && strncasecmp(home_pwd_buf, cwd_buf, l) == 0 1939 after_home_user = NULL;
1940 l = strlen(home_pwd_buf);
1941 if (l != 0
1942 && strncasecmp(home_pwd_buf, cwd_buf, l) == 0) {
1943 after_home_user = cwd_buf + l;
1944 }
1943#endif 1945#endif
1944 && (cwd_buf[l] == '/' || cwd_buf[l] == '\0') 1946 if (after_home_user
1947 && (*after_home_user == '/' || *after_home_user == '\0')
1945 ) { 1948 ) {
1946 cwd_buf[0] = '~'; 1949 cwd_buf[0] = '~';
1947 overlapping_strcpy(cwd_buf + 1, cwd_buf + l); 1950 overlapping_strcpy(cwd_buf + 1, after_home_user);
1948 } 1951 }
1949 } 1952 }
1950 } 1953 }
diff --git a/libbb/loop.c b/libbb/loop.c
index c96c5e070..d30b378d7 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -154,16 +154,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
154 else 154 else
155 ioctl(dfd, LOOP_CLR_FD, 0); 155 ioctl(dfd, LOOP_CLR_FD, 0);
156 } 156 }
157 157 } else {
158 /* If this block device already set up right, re-use it.
159 * (Yes this is racy, but associating two loop devices with the same
160 * file isn't pretty either. In general, mounting the same file twice
161 * without using losetup manually is problematic.)
162 */
163 } else
164 if (strcmp(file, (char *)loopinfo.lo_file_name) != 0
165 || offset != loopinfo.lo_offset
166 ) {
167 rc = -1; 158 rc = -1;
168 } 159 }
169 close(dfd); 160 close(dfd);
diff --git a/libbb/match_fstype.c b/libbb/match_fstype.c
index 32c3d7f18..b066b4211 100644
--- a/libbb/match_fstype.c
+++ b/libbb/match_fstype.c
@@ -17,7 +17,6 @@
17int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) 17int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
18{ 18{
19 int match = 1; 19 int match = 1;
20 int len;
21 20
22 if (!t_fstype) 21 if (!t_fstype)
23 return match; 22 return match;
@@ -27,10 +26,10 @@ int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
27 t_fstype += 2; 26 t_fstype += 2;
28 } 27 }
29 28
30 len = strlen(mt->mnt_type);
31 while (1) { 29 while (1) {
32 if (strncmp(mt->mnt_type, t_fstype, len) == 0 30 char *after_mnt_type = is_prefixed_with(t_fstype, mt->mnt_type);
33 && (t_fstype[len] == '\0' || t_fstype[len] == ',') 31 if (after_mnt_type
32 && (*after_mnt_type == '\0' || *after_mnt_type == ',')
34 ) { 33 ) {
35 return match; 34 return match;
36 } 35 }
diff --git a/libbb/procps.c b/libbb/procps.c
index 3c99ac6e7..fff9f8b0b 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -206,11 +206,11 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
206 // Rss: nnn kB 206 // Rss: nnn kB
207 // ..... 207 // .....
208 208
209 char *tp = buf, *p; 209 char *tp, *p;
210 210
211#define SCAN(S, X) \ 211#define SCAN(S, X) \
212 if (strncmp(tp, S, sizeof(S)-1) == 0) { \ 212 if ((tp = is_prefixed_with(buf, S)) != NULL) { \
213 tp = skip_whitespace(tp + sizeof(S)-1); \ 213 tp = skip_whitespace(tp); \
214 total->X += currec.X = fast_strtoul_10(&tp); \ 214 total->X += currec.X = fast_strtoul_10(&tp); \
215 continue; \ 215 continue; \
216 } 216 }
@@ -248,7 +248,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
248 // skipping "rw-s FILEOFS M:m INODE " 248 // skipping "rw-s FILEOFS M:m INODE "
249 tp = skip_whitespace(skip_fields(tp, 4)); 249 tp = skip_whitespace(skip_fields(tp, 4));
250 // filter out /dev/something (something != zero) 250 // filter out /dev/something (something != zero)
251 if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { 251 if (!is_prefixed_with(tp, "/dev/") || strcmp(tp, "/dev/zero\n") == 0) {
252 if (currec.smap_mode[1] == 'w') { 252 if (currec.smap_mode[1] == 'w') {
253 currec.mapped_rw = currec.smap_size; 253 currec.mapped_rw = currec.smap_size;
254 total->mapped_rw += currec.smap_size; 254 total->mapped_rw += currec.smap_size;
@@ -498,8 +498,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
498 while (fgets(buf, sizeof(buf), file)) { 498 while (fgets(buf, sizeof(buf), file)) {
499 char *tp; 499 char *tp;
500#define SCAN_TWO(str, name, statement) \ 500#define SCAN_TWO(str, name, statement) \
501 if (strncmp(buf, str, sizeof(str)-1) == 0) { \ 501 if ((tp = is_prefixed_with(buf, str)) != NULL) { \
502 tp = skip_whitespace(buf + sizeof(str)-1); \ 502 tp = skip_whitespace(tp); \
503 sscanf(tp, "%u", &sp->name); \ 503 sscanf(tp, "%u", &sp->name); \
504 statement; \ 504 statement; \
505 } 505 }
diff --git a/libbb/rtc.c b/libbb/rtc.c
index 6d06d57f9..c4117ba34 100644
--- a/libbb/rtc.c
+++ b/libbb/rtc.c
@@ -22,7 +22,7 @@ int FAST_FUNC rtc_adjtime_is_utc(void)
22 char buffer[128]; 22 char buffer[128];
23 23
24 while (fgets(buffer, sizeof(buffer), f)) { 24 while (fgets(buffer, sizeof(buffer), f)) {
25 if (strncmp(buffer, "UTC", 3) == 0) { 25 if (is_prefixed_with(buffer, "UTC")) {
26 utc = 1; 26 utc = 1;
27 break; 27 break;
28 } 28 }
diff --git a/libbb/skip_whitespace.c b/libbb/skip_whitespace.c
index 8c7b674c3..b6cfbba4d 100644
--- a/libbb/skip_whitespace.c
+++ b/libbb/skip_whitespace.c
@@ -33,7 +33,7 @@ char* FAST_FUNC skip_non_whitespace(const char *s)
33 33
34char* FAST_FUNC skip_dev_pfx(const char *tty_name) 34char* FAST_FUNC skip_dev_pfx(const char *tty_name)
35{ 35{
36 if (strncmp(tty_name, "/dev/", 5) == 0) 36 if (is_prefixed_with(tty_name, "/dev/"))
37 tty_name += 5; 37 tty_name += 5;
38 return (char*)tty_name; 38 return (char*)tty_name;
39} 39}
diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c
index a30af6f72..a2004f480 100644
--- a/libbb/update_passwd.c
+++ b/libbb/update_passwd.c
@@ -62,6 +62,8 @@ static void check_selinux_update_passwd(const char *username)
62 only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd 62 only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd
63 or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd 63 or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd
64 64
65 8) delete a user from all groups: update_passwd(FILE, NULL, NULL, MEMBER)
66
65 This function does not validate the arguments fed to it 67 This function does not validate the arguments fed to it
66 so the calling program should take care of that. 68 so the calling program should take care of that.
67 69
@@ -82,7 +84,6 @@ int FAST_FUNC update_passwd(const char *filename,
82 char *fnamesfx; 84 char *fnamesfx;
83 char *sfx_char; 85 char *sfx_char;
84 char *name_colon; 86 char *name_colon;
85 unsigned user_len;
86 int old_fd; 87 int old_fd;
87 int new_fd; 88 int new_fd;
88 int i; 89 int i;
@@ -99,13 +100,13 @@ int FAST_FUNC update_passwd(const char *filename,
99 if (filename == NULL) 100 if (filename == NULL)
100 return ret; 101 return ret;
101 102
102 check_selinux_update_passwd(name); 103 if (name)
104 check_selinux_update_passwd(name);
103 105
104 /* New passwd file, "/etc/passwd+" for now */ 106 /* New passwd file, "/etc/passwd+" for now */
105 fnamesfx = xasprintf("%s+", filename); 107 fnamesfx = xasprintf("%s+", filename);
106 sfx_char = &fnamesfx[strlen(fnamesfx)-1]; 108 sfx_char = &fnamesfx[strlen(fnamesfx)-1];
107 name_colon = xasprintf("%s:", name); 109 name_colon = xasprintf("%s:", name ? name : "");
108 user_len = strlen(name_colon);
109 110
110 if (shadow) 111 if (shadow)
111 old_fp = fopen(filename, "r+"); 112 old_fp = fopen(filename, "r+");
@@ -167,13 +168,45 @@ int FAST_FUNC update_passwd(const char *filename,
167 line = xmalloc_fgetline(old_fp); 168 line = xmalloc_fgetline(old_fp);
168 if (!line) /* EOF/error */ 169 if (!line) /* EOF/error */
169 break; 170 break;
170 if (strncmp(name_colon, line, user_len) != 0) { 171
172 if (!name && member) {
173 /* Delete member from all groups */
174 /* line is "GROUP:PASSWD:[member1[,member2]...]" */
175 unsigned member_len = strlen(member);
176 char *list = strrchr(line, ':');
177 while (list) {
178 list++;
179 next_list_element:
180 if (is_prefixed_with(list, member)) {
181 char c;
182 changed_lines++;
183 c = list[member_len];
184 if (c == '\0') {
185 if (list[-1] == ',')
186 list--;
187 *list = '\0';
188 break;
189 }
190 if (c == ',') {
191 overlapping_strcpy(list, list + member_len + 1);
192 goto next_list_element;
193 }
194 changed_lines--;
195 }
196 list = strchr(list, ',');
197 }
198 fprintf(new_fp, "%s\n", line);
199 goto next;
200 }
201
202 cp = is_prefixed_with(line, name_colon);
203 if (!cp) {
171 fprintf(new_fp, "%s\n", line); 204 fprintf(new_fp, "%s\n", line);
172 goto next; 205 goto next;
173 } 206 }
174 207
175 /* We have a match with "name:"... */ 208 /* We have a match with "name:"... */
176 cp = line + user_len; /* move past name: */ 209 /* cp points past "name:" */
177 210
178#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP 211#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
179 if (member) { 212 if (member) {
diff --git a/libbb/utmp.c b/libbb/utmp.c
index 09443fb6c..8ad9ba27e 100644
--- a/libbb/utmp.c
+++ b/libbb/utmp.c
@@ -130,3 +130,17 @@ void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const
130 updwtmp(bb_path_wtmp_file, &utent); 130 updwtmp(bb_path_wtmp_file, &utent);
131#endif 131#endif
132} 132}
133
134/* man utmp:
135 * When init(8) finds that a process has exited, it locates its utmp entry
136 * by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host
137 * and ut_time with null bytes.
138 * [same applies to other processes which maintain utmp entries, like telnetd]
139 *
140 * We do not bother actually clearing fields:
141 * it might be interesting to know who was logged in and from where
142 */
143void FAST_FUNC update_utmp_DEAD_PROCESS(pid_t pid)
144{
145 update_utmp(pid, DEAD_PROCESS, NULL, NULL, NULL);
146}
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 1c8bb2b73..2a96e03dc 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -171,7 +171,7 @@ IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;)
171 const char *cp; 171 const char *cp;
172 struct addrinfo hint; 172 struct addrinfo hint;
173 173
174 if (ENABLE_FEATURE_UNIX_LOCAL && strncmp(host, "local:", 6) == 0) { 174 if (ENABLE_FEATURE_UNIX_LOCAL && is_prefixed_with(host, "local:")) {
175 struct sockaddr_un *sun; 175 struct sockaddr_un *sun;
176 176
177 r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un)); 177 r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));