aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-10-08 03:06:04 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-10-08 03:06:04 +0200
commit4ac9819263114edb9b5b638ffa6d2e41a4bb46e7 (patch)
treef0c5bc9c7a2bf3a384b85350bfe4c9ca5ec4858f /libbb
parent5b807cd5acd1f27b3e7aa36aac2728be27c5907c (diff)
downloadbusybox-w32-4ac9819263114edb9b5b638ffa6d2e41a4bb46e7.tar.gz
busybox-w32-4ac9819263114edb9b5b638ffa6d2e41a4bb46e7.tar.bz2
busybox-w32-4ac9819263114edb9b5b638ffa6d2e41a4bb46e7.zip
apply post-1.15.1 fixes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
-rw-r--r--libbb/lineedit.c49
-rw-r--r--libbb/procps.c133
-rw-r--r--libbb/recursive_action.c17
3 files changed, 111 insertions, 88 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 9a773b4b8..071fc5bce 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -114,8 +114,8 @@ struct lineedit_statics {
114 unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */ 114 unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
115 115
116 unsigned cursor; 116 unsigned cursor;
117 unsigned command_len; 117 int command_len; /* must be signed (^D returns -1 len) */
118 /* *int* maxsize: we want x in "if (x > S.maxsize)" 118 /* signed maxsize: we want x in "if (x > S.maxsize)"
119 * to _not_ be promoted to unsigned */ 119 * to _not_ be promoted to unsigned */
120 int maxsize; 120 int maxsize;
121 CHAR_T *command_ps; 121 CHAR_T *command_ps;
@@ -1095,15 +1095,15 @@ static void save_command_ps_at_cur_history(void)
1095 int cur = state->cur_history; 1095 int cur = state->cur_history;
1096 free(state->history[cur]); 1096 free(state->history[cur]);
1097 1097
1098#if ENABLE_FEATURE_ASSUME_UNICODE 1098# if ENABLE_FEATURE_ASSUME_UNICODE
1099 { 1099 {
1100 char tbuf[MAX_LINELEN]; 1100 char tbuf[MAX_LINELEN];
1101 save_string(tbuf, sizeof(tbuf)); 1101 save_string(tbuf, sizeof(tbuf));
1102 state->history[cur] = xstrdup(tbuf); 1102 state->history[cur] = xstrdup(tbuf);
1103 } 1103 }
1104#else 1104# else
1105 state->history[cur] = xstrdup(command_ps); 1105 state->history[cur] = xstrdup(command_ps);
1106#endif 1106# endif
1107 } 1107 }
1108} 1108}
1109 1109
@@ -1131,7 +1131,7 @@ static int get_next_history(void)
1131 return 0; 1131 return 0;
1132} 1132}
1133 1133
1134#if ENABLE_FEATURE_EDITING_SAVEHISTORY 1134# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1135/* We try to ensure that concurrent additions to the history 1135/* We try to ensure that concurrent additions to the history
1136 * do not overwrite each other. 1136 * do not overwrite each other.
1137 * Otherwise shell users get unhappy. 1137 * Otherwise shell users get unhappy.
@@ -1256,10 +1256,10 @@ static void save_history(char *str)
1256 free_line_input_t(st_temp); 1256 free_line_input_t(st_temp);
1257 } 1257 }
1258} 1258}
1259#else 1259# else
1260#define load_history(a) ((void)0) 1260# define load_history(a) ((void)0)
1261#define save_history(a) ((void)0) 1261# define save_history(a) ((void)0)
1262#endif /* FEATURE_COMMAND_SAVEHISTORY */ 1262# endif /* FEATURE_COMMAND_SAVEHISTORY */
1263 1263
1264static void remember_in_history(char *str) 1264static void remember_in_history(char *str)
1265{ 1265{
@@ -1290,15 +1290,15 @@ static void remember_in_history(char *str)
1290 /* i <= MAX_HISTORY */ 1290 /* i <= MAX_HISTORY */
1291 state->cur_history = i; 1291 state->cur_history = i;
1292 state->cnt_history = i; 1292 state->cnt_history = i;
1293#if ENABLE_FEATURE_EDITING_SAVEHISTORY 1293# if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
1294 if ((state->flags & SAVE_HISTORY) && state->hist_file) 1294 if ((state->flags & SAVE_HISTORY) && state->hist_file)
1295 save_history(str); 1295 save_history(str);
1296#endif 1296# endif
1297 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) 1297 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
1298} 1298}
1299 1299
1300#else /* MAX_HISTORY == 0 */ 1300#else /* MAX_HISTORY == 0 */
1301#define remember_in_history(a) ((void)0) 1301# define remember_in_history(a) ((void)0)
1302#endif /* MAX_HISTORY */ 1302#endif /* MAX_HISTORY */
1303 1303
1304 1304
@@ -1476,11 +1476,11 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1476 c = *prmt_ptr++; 1476 c = *prmt_ptr++;
1477 1477
1478 switch (c) { 1478 switch (c) {
1479#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR 1479# if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1480 case 'u': 1480 case 'u':
1481 pbuf = user_buf ? user_buf : (char*)""; 1481 pbuf = user_buf ? user_buf : (char*)"";
1482 break; 1482 break;
1483#endif 1483# endif
1484 case 'h': 1484 case 'h':
1485 pbuf = free_me = safe_gethostname(); 1485 pbuf = free_me = safe_gethostname();
1486 *strchrnul(pbuf, '.') = '\0'; 1486 *strchrnul(pbuf, '.') = '\0';
@@ -1488,7 +1488,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1488 case '$': 1488 case '$':
1489 c = (geteuid() == 0 ? '#' : '$'); 1489 c = (geteuid() == 0 ? '#' : '$');
1490 break; 1490 break;
1491#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR 1491# if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1492 case 'w': 1492 case 'w':
1493 /* /home/user[/something] -> ~[/something] */ 1493 /* /home/user[/something] -> ~[/something] */
1494 pbuf = cwd_buf; 1494 pbuf = cwd_buf;
@@ -1501,7 +1501,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1501 pbuf = free_me = xasprintf("~%s", cwd_buf + l); 1501 pbuf = free_me = xasprintf("~%s", cwd_buf + l);
1502 } 1502 }
1503 break; 1503 break;
1504#endif 1504# endif
1505 case 'W': 1505 case 'W':
1506 pbuf = cwd_buf; 1506 pbuf = cwd_buf;
1507 cp = strrchr(pbuf, '/'); 1507 cp = strrchr(pbuf, '/');
@@ -1688,13 +1688,15 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1688 1688
1689 /* With null flags, no other fields are ever used */ 1689 /* With null flags, no other fields are ever used */
1690 state = st ? st : (line_input_t*) &const_int_0; 1690 state = st ? st : (line_input_t*) &const_int_0;
1691#if ENABLE_FEATURE_EDITING_SAVEHISTORY 1691#if MAX_HISTORY > 0
1692# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1692 if ((state->flags & SAVE_HISTORY) && state->hist_file) 1693 if ((state->flags & SAVE_HISTORY) && state->hist_file)
1693 if (state->cnt_history == 0) 1694 if (state->cnt_history == 0)
1694 load_history(state); 1695 load_history(state);
1695#endif 1696# endif
1696 if (state->flags & DO_HISTORY) 1697 if (state->flags & DO_HISTORY)
1697 state->cur_history = state->cnt_history; 1698 state->cur_history = state->cnt_history;
1699#endif
1698 1700
1699 /* prepare before init handlers */ 1701 /* prepare before init handlers */
1700 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ 1702 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
@@ -1716,7 +1718,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1716 new_settings.c_cc[VTIME] = 0; 1718 new_settings.c_cc[VTIME] = 0;
1717 /* Turn off CTRL-C, so we can trap it */ 1719 /* Turn off CTRL-C, so we can trap it */
1718#ifndef _POSIX_VDISABLE 1720#ifndef _POSIX_VDISABLE
1719#define _POSIX_VDISABLE '\0' 1721# define _POSIX_VDISABLE '\0'
1720#endif 1722#endif
1721 new_settings.c_cc[VINTR] = _POSIX_VDISABLE; 1723 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
1722 tcsetattr_stdin_TCSANOW(&new_settings); 1724 tcsetattr_stdin_TCSANOW(&new_settings);
@@ -2037,7 +2039,8 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2037 rewrite_line: 2039 rewrite_line:
2038 /* Rewrite the line with the selected history item */ 2040 /* Rewrite the line with the selected history item */
2039 /* change command */ 2041 /* change command */
2040 command_len = load_string(state->history[state->cur_history] ? : "", maxsize); 2042 command_len = load_string(state->history[state->cur_history] ?
2043 state->history[state->cur_history] : "", maxsize);
2041 /* redraw and go to eol (bol, in vi) */ 2044 /* redraw and go to eol (bol, in vi) */
2042 redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); 2045 redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
2043 break; 2046 break;
@@ -2121,7 +2124,9 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2121#undef command 2124#undef command
2122 2125
2123#if ENABLE_FEATURE_ASSUME_UNICODE 2126#if ENABLE_FEATURE_ASSUME_UNICODE
2124 command_len = save_string(command, maxsize - 1); 2127 command[0] = '\0';
2128 if (command_len > 0)
2129 command_len = save_string(command, maxsize - 1);
2125 free(command_ps); 2130 free(command_ps);
2126#endif 2131#endif
2127 2132
diff --git a/libbb/procps.c b/libbb/procps.c
index 307d8d622..7276f60ef 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -134,8 +134,8 @@ static unsigned long fast_strtoul_16(char **endptr)
134 return n; 134 return n;
135} 135}
136/* TOPMEM uses fast_strtoul_10, so... */ 136/* TOPMEM uses fast_strtoul_10, so... */
137#undef ENABLE_FEATURE_FAST_TOP 137# undef ENABLE_FEATURE_FAST_TOP
138#define ENABLE_FEATURE_FAST_TOP 1 138# define ENABLE_FEATURE_FAST_TOP 1
139#endif 139#endif
140 140
141#if ENABLE_FEATURE_FAST_TOP 141#if ENABLE_FEATURE_FAST_TOP
@@ -198,14 +198,16 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
198 if (errno) 198 if (errno)
199 continue; 199 continue;
200 200
201 /* After this point we have to break, not continue 201 /* After this point we can:
202 * ("continue" would mean that current /proc/NNN 202 * "break": stop parsing, return the data
203 * is not a valid process info) */ 203 * "continue": try next /proc/XXX
204 */
204 205
205 memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz)); 206 memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
206 207
207 sp->pid = pid; 208 sp->pid = pid;
208 if (!(flags & ~PSSCAN_PID)) break; 209 if (!(flags & ~PSSCAN_PID))
210 break; /* we needed only pid, we got it */
209 211
210#if ENABLE_SELINUX 212#if ENABLE_SELINUX
211 if (flags & PSSCAN_CONTEXT) { 213 if (flags & PSSCAN_CONTEXT) {
@@ -218,7 +220,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
218 220
219 if (flags & PSSCAN_UIDGID) { 221 if (flags & PSSCAN_UIDGID) {
220 if (stat(filename, &sb)) 222 if (stat(filename, &sb))
221 break; 223 continue; /* process probably exited */
222 /* Effective UID/GID, not real */ 224 /* Effective UID/GID, not real */
223 sp->uid = sb.st_uid; 225 sp->uid = sb.st_uid;
224 sp->gid = sb.st_gid; 226 sp->gid = sb.st_gid;
@@ -234,10 +236,10 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
234 strcpy(filename_tail, "stat"); 236 strcpy(filename_tail, "stat");
235 n = read_to_buf(filename, buf); 237 n = read_to_buf(filename, buf);
236 if (n < 0) 238 if (n < 0)
237 break; 239 continue; /* process probably exited */
238 cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ 240 cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
239 /*if (!cp || cp[1] != ' ') 241 /*if (!cp || cp[1] != ' ')
240 break;*/ 242 continue;*/
241 cp[0] = '\0'; 243 cp[0] = '\0';
242 if (sizeof(sp->comm) < 16) 244 if (sizeof(sp->comm) < 16)
243 BUG_comm_size(); 245 BUG_comm_size();
@@ -257,12 +259,12 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
257 "%lu " /* start_time */ 259 "%lu " /* start_time */
258 "%lu " /* vsize */ 260 "%lu " /* vsize */
259 "%lu " /* rss */ 261 "%lu " /* rss */
260#if ENABLE_FEATURE_TOP_SMP_PROCESS 262# if ENABLE_FEATURE_TOP_SMP_PROCESS
261 "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ 263 "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
262 "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */ 264 "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */
263 "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */ 265 "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */
264 "%d" /*cpu last seen on*/ 266 "%d" /*cpu last seen on*/
265#endif 267# endif
266 , 268 ,
267 sp->state, &sp->ppid, 269 sp->state, &sp->ppid,
268 &sp->pgid, &sp->sid, &tty, 270 &sp->pgid, &sp->sid, &tty,
@@ -271,17 +273,17 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
271 &sp->start_time, 273 &sp->start_time,
272 &vsz, 274 &vsz,
273 &rss 275 &rss
274#if ENABLE_FEATURE_TOP_SMP_PROCESS 276# if ENABLE_FEATURE_TOP_SMP_PROCESS
275 , &sp->last_seen_on_cpu 277 , &sp->last_seen_on_cpu
276#endif 278# endif
277 ); 279 );
278 280
279 if (n < 11) 281 if (n < 11)
280 break; 282 continue; /* bogus data, get next /proc/XXX */
281#if ENABLE_FEATURE_TOP_SMP_PROCESS 283# if ENABLE_FEATURE_TOP_SMP_PROCESS
282 if (n < 11+15) 284 if (n < 11+15)
283 sp->last_seen_on_cpu = 0; 285 sp->last_seen_on_cpu = 0;
284#endif 286# endif
285 287
286 /* vsz is in bytes and we want kb */ 288 /* vsz is in bytes and we want kb */
287 sp->vsz = vsz >> 10; 289 sp->vsz = vsz >> 10;
@@ -311,14 +313,14 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
311 sp->vsz = fast_strtoul_10(&cp) >> 10; 313 sp->vsz = fast_strtoul_10(&cp) >> 10;
312 /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ 314 /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
313 sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; 315 sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb;
314#if ENABLE_FEATURE_TOP_SMP_PROCESS 316# if ENABLE_FEATURE_TOP_SMP_PROCESS
315 /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ 317 /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
316 /* (4): signal, blocked, sigignore, sigcatch */ 318 /* (4): signal, blocked, sigignore, sigcatch */
317 /* (4): wchan, nswap, cnswap, exit_signal */ 319 /* (4): wchan, nswap, cnswap, exit_signal */
318 cp = skip_fields(cp, 14); 320 cp = skip_fields(cp, 14);
319//FIXME: is it safe to assume this field exists? 321//FIXME: is it safe to assume this field exists?
320 sp->last_seen_on_cpu = fast_strtoul_10(&cp); 322 sp->last_seen_on_cpu = fast_strtoul_10(&cp);
321#endif 323# endif
322#endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */ 324#endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */
323 325
324#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 326#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
@@ -343,48 +345,48 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
343 345
344 strcpy(filename_tail, "smaps"); 346 strcpy(filename_tail, "smaps");
345 file = fopen_for_read(filename); 347 file = fopen_for_read(filename);
346 if (!file) 348 if (file) {
347 break; 349 while (fgets(buf, sizeof(buf), file)) {
348 while (fgets(buf, sizeof(buf), file)) { 350 unsigned long sz;
349 unsigned long sz; 351 char *tp;
350 char *tp; 352 char w;
351 char w;
352#define SCAN(str, name) \ 353#define SCAN(str, name) \
353 if (strncmp(buf, str, sizeof(str)-1) == 0) { \ 354 if (strncmp(buf, str, sizeof(str)-1) == 0) { \
354 tp = skip_whitespace(buf + sizeof(str)-1); \ 355 tp = skip_whitespace(buf + sizeof(str)-1); \
355 sp->name += fast_strtoul_10(&tp); \ 356 sp->name += fast_strtoul_10(&tp); \
356 continue; \ 357 continue; \
357 } 358 }
358 SCAN("Shared_Clean:" , shared_clean ); 359 SCAN("Shared_Clean:" , shared_clean );
359 SCAN("Shared_Dirty:" , shared_dirty ); 360 SCAN("Shared_Dirty:" , shared_dirty );
360 SCAN("Private_Clean:", private_clean); 361 SCAN("Private_Clean:", private_clean);
361 SCAN("Private_Dirty:", private_dirty); 362 SCAN("Private_Dirty:", private_dirty);
362#undef SCAN 363#undef SCAN
363 // f7d29000-f7d39000 rw-s ADR M:m OFS FILE 364 // f7d29000-f7d39000 rw-s ADR M:m OFS FILE
364 tp = strchr(buf, '-'); 365 tp = strchr(buf, '-');
365 if (tp) { 366 if (tp) {
366 *tp = ' '; 367 *tp = ' ';
367 tp = buf; 368 tp = buf;
368 sz = fast_strtoul_16(&tp); /* start */ 369 sz = fast_strtoul_16(&tp); /* start */
369 sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */ 370 sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */
370 // tp -> "rw-s" string 371 // tp -> "rw-s" string
371 w = tp[1]; 372 w = tp[1];
372 // skipping "rw-s ADR M:m OFS " 373 // skipping "rw-s ADR M:m OFS "
373 tp = skip_whitespace(skip_fields(tp, 4)); 374 tp = skip_whitespace(skip_fields(tp, 4));
374 // filter out /dev/something (something != zero) 375 // filter out /dev/something (something != zero)
375 if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { 376 if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
376 if (w == 'w') { 377 if (w == 'w') {
377 sp->mapped_rw += sz; 378 sp->mapped_rw += sz;
378 } else if (w == '-') { 379 } else if (w == '-') {
379 sp->mapped_ro += sz; 380 sp->mapped_ro += sz;
381 }
380 } 382 }
381 }
382//else printf("DROPPING %s (%s)\n", buf, tp); 383//else printf("DROPPING %s (%s)\n", buf, tp);
383 if (strcmp(tp, "[stack]\n") == 0) 384 if (strcmp(tp, "[stack]\n") == 0)
384 sp->stack += sz; 385 sp->stack += sz;
386 }
385 } 387 }
388 fclose(file);
386 } 389 }
387 fclose(file);
388 } 390 }
389#endif /* TOPMEM */ 391#endif /* TOPMEM */
390#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 392#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
@@ -393,23 +395,34 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
393 395
394 strcpy(filename_tail, "status"); 396 strcpy(filename_tail, "status");
395 file = fopen_for_read(filename); 397 file = fopen_for_read(filename);
396 if (!file) 398 if (file) {
397 break; 399 while (fgets(buf, sizeof(buf), file)) {
398 while (fgets(buf, sizeof(buf), file)) { 400 char *tp;
399 char *tp;
400#define SCAN_TWO(str, name, statement) \ 401#define SCAN_TWO(str, name, statement) \
401 if (strncmp(buf, str, sizeof(str)-1) == 0) { \ 402 if (strncmp(buf, str, sizeof(str)-1) == 0) { \
402 tp = skip_whitespace(buf + sizeof(str)-1); \ 403 tp = skip_whitespace(buf + sizeof(str)-1); \
403 sscanf(tp, "%u", &sp->name); \ 404 sscanf(tp, "%u", &sp->name); \
404 statement; \ 405 statement; \
405 } 406 }
406 SCAN_TWO("Uid:", ruid, continue); 407 SCAN_TWO("Uid:", ruid, continue);
407 SCAN_TWO("Gid:", rgid, break); 408 SCAN_TWO("Gid:", rgid, break);
408#undef SCAN_TWO 409#undef SCAN_TWO
410 }
411 fclose(file);
409 } 412 }
410 fclose(file);
411 } 413 }
412#endif /* PS_ADDITIONAL_COLUMNS */ 414#endif /* PS_ADDITIONAL_COLUMNS */
415 if (flags & PSSCAN_EXE) {
416 strcpy(filename_tail, "exe");
417 free(sp->exe);
418 sp->exe = xmalloc_readlink(filename);
419 }
420 /* Note: if /proc/PID/cmdline is empty,
421 * code below "breaks". Therefore it must be
422 * the last code to parse /proc/PID/xxx data
423 * (we used to have /proc/PID/exe parsing after it
424 * and were getting stale sp->exe).
425 */
413#if 0 /* PSSCAN_CMD is not used */ 426#if 0 /* PSSCAN_CMD is not used */
414 if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) { 427 if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
415 free(sp->argv0); 428 free(sp->argv0);
@@ -452,13 +465,9 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
452 } 465 }
453 } 466 }
454#endif 467#endif
455 if (flags & PSSCAN_EXE) {
456 strcpy(filename_tail, "exe");
457 free(sp->exe);
458 sp->exe = xmalloc_readlink(filename);
459 }
460 break; 468 break;
461 } 469 } /* for (;;) */
470
462 return sp; 471 return sp;
463} 472}
464 473
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
index 3ec596a35..3a4eb28db 100644
--- a/libbb/recursive_action.c
+++ b/libbb/recursive_action.c
@@ -61,6 +61,7 @@ int FAST_FUNC recursive_action(const char *fileName,
61 unsigned depth) 61 unsigned depth)
62{ 62{
63 struct stat statbuf; 63 struct stat statbuf;
64 unsigned follow;
64 int status; 65 int status;
65 DIR *dir; 66 DIR *dir;
66 struct dirent *next; 67 struct dirent *next;
@@ -68,14 +69,22 @@ int FAST_FUNC recursive_action(const char *fileName,
68 if (!fileAction) fileAction = true_action; 69 if (!fileAction) fileAction = true_action;
69 if (!dirAction) dirAction = true_action; 70 if (!dirAction) dirAction = true_action;
70 71
71 status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */ 72 follow = ACTION_FOLLOWLINKS;
72 if (!depth) 73 if (depth == 0)
73 status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; 74 follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
74 status = ((flags & status) ? stat : lstat)(fileName, &statbuf); 75 follow &= flags;
76 status = (follow ? stat : lstat)(fileName, &statbuf);
75 if (status < 0) { 77 if (status < 0) {
76#ifdef DEBUG_RECURS_ACTION 78#ifdef DEBUG_RECURS_ACTION
77 bb_error_msg("status=%d flags=%x", status, flags); 79 bb_error_msg("status=%d flags=%x", status, flags);
78#endif 80#endif
81 if ((flags & ACTION_DANGLING_OK)
82 && errno == ENOENT
83 && lstat(fileName, &statbuf) == 0
84 ) {
85 /* Dangling link */
86 return fileAction(fileName, &statbuf, userData, depth);
87 }
79 goto done_nak_warn; 88 goto done_nak_warn;
80 } 89 }
81 90