aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-03-22 15:21:20 +0000
committerRon Yorston <rmy@pobox.com>2012-03-22 15:21:20 +0000
commit0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2 (patch)
tree6709ddd6071a9c238ba69233540bbcfe560c6a44 /libbb
parent67758035a4fe040c6ac69b39d61bcd6bddd7b827 (diff)
parent56a3b82e9692a25ef9c9269e88feac0d579ce8e8 (diff)
downloadbusybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.tar.gz
busybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.tar.bz2
busybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.zip
Merge commit '56a3b82e9692a25ef9c9269e88feac0d579ce8e8' into merge
Conflicts: coreutils/ls.c include/platform.h libbb/bb_basename.c
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Kbuild.src1
-rw-r--r--libbb/appletlib.c213
-rw-r--r--libbb/bb_basename.c23
-rw-r--r--libbb/dump.c7
-rw-r--r--libbb/get_last_path_component.c15
-rw-r--r--libbb/getopt32.c4
-rw-r--r--libbb/lineedit.c24
-rw-r--r--libbb/llist.c2
-rw-r--r--libbb/pw_encrypt.c25
-rw-r--r--libbb/read_printf.c17
10 files changed, 165 insertions, 166 deletions
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 3c9493f7e..d110a3265 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -13,7 +13,6 @@ INSERT
13lib-y += appletlib.o 13lib-y += appletlib.o
14lib-y += ask_confirmation.o 14lib-y += ask_confirmation.o
15lib-y += bb_askpass.o 15lib-y += bb_askpass.o
16lib-y += bb_basename.o
17lib-y += bb_bswap_64.o 16lib-y += bb_bswap_64.o
18lib-y += bb_do_delay.o 17lib-y += bb_do_delay.o
19lib-y += bb_pwd.o 18lib-y += bb_pwd.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index a934f11bb..d4025b9c7 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -27,12 +27,13 @@
27 * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :( 27 * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
28 */ 28 */
29#include "busybox.h" 29#include "busybox.h"
30#include <assert.h> 30
31#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ 31#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
32 || defined(__APPLE__) \ 32 || defined(__APPLE__) \
33 ) 33 )
34# include <malloc.h> /* for mallopt */ 34# include <malloc.h> /* for mallopt */
35#endif 35#endif
36
36/* Try to pull in PAGE_SIZE */ 37/* Try to pull in PAGE_SIZE */
37#ifdef __linux__ 38#ifdef __linux__
38# include <sys/user.h> 39# include <sys/user.h>
@@ -40,6 +41,9 @@
40#ifdef __GNU__ /* Hurd */ 41#ifdef __GNU__ /* Hurd */
41# include <mach/vm_param.h> 42# include <mach/vm_param.h>
42#endif 43#endif
44#ifndef PAGE_SIZE
45# define PAGE_SIZE (4*1024) /* guess */
46#endif
43 47
44 48
45/* Declare <applet>_main() */ 49/* Declare <applet>_main() */
@@ -47,7 +51,6 @@
47#include "applets.h" 51#include "applets.h"
48#undef PROTOTYPES 52#undef PROTOTYPES
49 53
50
51/* Include generated applet names, pointers to <applet>_main, etc */ 54/* Include generated applet names, pointers to <applet>_main, etc */
52#include "applet_tables.h" 55#include "applet_tables.h"
53/* ...and if applet_tables generator says we have only one applet... */ 56/* ...and if applet_tables generator says we have only one applet... */
@@ -58,9 +61,9 @@
58# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__ 61# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
59#endif 62#endif
60 63
61
62#include "usage_compressed.h" 64#include "usage_compressed.h"
63 65
66
64#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE 67#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
65static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; 68static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
66#else 69#else
@@ -233,13 +236,12 @@ IF_FEATURE_SUID(static uid_t ruid;) /* real uid */
233 236
234# if ENABLE_FEATURE_SUID_CONFIG 237# if ENABLE_FEATURE_SUID_CONFIG
235 238
236/* applets[] is const, so we have to define this "override" structure */ 239static struct suid_config_t {
237static struct BB_suid_config { 240 /* next ptr must be first: this struct needs to be llist-compatible */
241 struct suid_config_t *m_next;
242 struct bb_uidgid_t m_ugid;
238 int m_applet; 243 int m_applet;
239 uid_t m_uid;
240 gid_t m_gid;
241 mode_t m_mode; 244 mode_t m_mode;
242 struct BB_suid_config *m_next;
243} *suid_config; 245} *suid_config;
244 246
245static bool suid_cfg_readable; 247static bool suid_cfg_readable;
@@ -248,13 +250,10 @@ static bool suid_cfg_readable;
248static int ingroup(uid_t u, gid_t g) 250static int ingroup(uid_t u, gid_t g)
249{ 251{
250 struct group *grp = getgrgid(g); 252 struct group *grp = getgrgid(g);
251
252 if (grp) { 253 if (grp) {
253 char **mem; 254 char **mem;
254
255 for (mem = grp->gr_mem; *mem; mem++) { 255 for (mem = grp->gr_mem; *mem; mem++) {
256 struct passwd *pwd = getpwnam(*mem); 256 struct passwd *pwd = getpwnam(*mem);
257
258 if (pwd && (pwd->pw_uid == u)) 257 if (pwd && (pwd->pw_uid == u))
259 return 1; 258 return 1;
260 } 259 }
@@ -262,9 +261,7 @@ static int ingroup(uid_t u, gid_t g)
262 return 0; 261 return 0;
263} 262}
264 263
265/* This should probably be a libbb routine. In that case, 264/* libbb candidate */
266 * I'd probably rename it to something like bb_trimmed_slice.
267 */
268static char *get_trimmed_slice(char *s, char *e) 265static char *get_trimmed_slice(char *s, char *e)
269{ 266{
270 /* First, consider the value at e to be nul and back up until we 267 /* First, consider the value at e to be nul and back up until we
@@ -282,38 +279,19 @@ static char *get_trimmed_slice(char *s, char *e)
282 return skip_whitespace(s); 279 return skip_whitespace(s);
283} 280}
284 281
285/* Don't depend on the tools to combine strings. */
286static const char config_file[] ALIGN1 = "/etc/busybox.conf";
287
288/* We don't supply a value for the nul, so an index adjustment is
289 * necessary below. Also, we use unsigned short here to save some
290 * space even though these are really mode_t values. */
291static const unsigned short mode_mask[] ALIGN2 = {
292 /* SST sst xxx --- */
293 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */
294 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */
295 0, S_IXOTH, S_IXOTH, 0 /* other */
296};
297
298#define parse_error(x) do { errmsg = x; goto pe_label; } while (0)
299
300static void parse_config_file(void) 282static void parse_config_file(void)
301{ 283{
302 struct BB_suid_config *sct_head; 284 /* Don't depend on the tools to combine strings. */
303 struct BB_suid_config *sct; 285 static const char config_file[] ALIGN1 = "/etc/busybox.conf";
286
287 struct suid_config_t *sct_head;
304 int applet_no; 288 int applet_no;
305 FILE *f; 289 FILE *f;
306 const char *errmsg; 290 const char *errmsg;
307 char *s;
308 char *e;
309 int i;
310 unsigned lc; 291 unsigned lc;
311 smallint section; 292 smallint section;
312 char buffer[256];
313 struct stat st; 293 struct stat st;
314 294
315 assert(!suid_config); /* Should be set to NULL by bss init. */
316
317 ruid = getuid(); 295 ruid = getuid();
318 if (ruid == 0) /* run by root - don't need to even read config file */ 296 if (ruid == 0) /* run by root - don't need to even read config file */
319 return; 297 return;
@@ -322,7 +300,7 @@ static void parse_config_file(void)
322 || !S_ISREG(st.st_mode) /* Not a regular file? */ 300 || !S_ISREG(st.st_mode) /* Not a regular file? */
323 || (st.st_uid != 0) /* Not owned by root? */ 301 || (st.st_uid != 0) /* Not owned by root? */
324 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */ 302 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */
325 || !(f = fopen_for_read(config_file)) /* Cannot open? */ 303 || !(f = fopen_for_read(config_file)) /* Cannot open? */
326 ) { 304 ) {
327 return; 305 return;
328 } 306 }
@@ -332,18 +310,21 @@ static void parse_config_file(void)
332 section = lc = 0; 310 section = lc = 0;
333 311
334 while (1) { 312 while (1) {
335 s = buffer; 313 char buffer[256];
336 314 char *s;
337 if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */ 315
338// why? 316 if (!fgets(buffer, sizeof(buffer), f)) { /* Are we done? */
339 if (ferror(f)) { /* Make sure it wasn't a read error. */ 317 // Looks like bloat
340 parse_error("reading"); 318 //if (ferror(f)) { /* Make sure it wasn't a read error. */
341 } 319 // errmsg = "reading";
320 // goto pe_label;
321 //}
342 fclose(f); 322 fclose(f);
343 suid_config = sct_head; /* Success, so set the pointer. */ 323 suid_config = sct_head; /* Success, so set the pointer. */
344 return; 324 return;
345 } 325 }
346 326
327 s = buffer;
347 lc++; /* Got a (partial) line. */ 328 lc++; /* Got a (partial) line. */
348 329
349 /* If a line is too long for our buffer, we consider it an error. 330 /* If a line is too long for our buffer, we consider it an error.
@@ -355,7 +336,8 @@ static void parse_config_file(void)
355 * we do err on the side of caution. Besides, the line would be 336 * we do err on the side of caution. Besides, the line would be
356 * too long if it did end with a newline. */ 337 * too long if it did end with a newline. */
357 if (!strchr(s, '\n') && !feof(f)) { 338 if (!strchr(s, '\n') && !feof(f)) {
358 parse_error("line too long"); 339 errmsg = "line too long";
340 goto pe_label;
359 } 341 }
360 342
361 /* Trim leading and trailing whitespace, ignoring comments, and 343 /* Trim leading and trailing whitespace, ignoring comments, and
@@ -371,12 +353,13 @@ static void parse_config_file(void)
371 /* Unlike the old code, we ignore leading and trailing 353 /* Unlike the old code, we ignore leading and trailing
372 * whitespace for the section name. We also require that 354 * whitespace for the section name. We also require that
373 * there are no stray characters after the closing bracket. */ 355 * there are no stray characters after the closing bracket. */
374 e = strchr(s, ']'); 356 char *e = strchr(s, ']');
375 if (!e /* Missing right bracket? */ 357 if (!e /* Missing right bracket? */
376 || e[1] /* Trailing characters? */ 358 || e[1] /* Trailing characters? */
377 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */ 359 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
378 ) { 360 ) {
379 parse_error("section header"); 361 errmsg = "section header";
362 goto pe_label;
380 } 363 }
381 /* Right now we only have one section so just check it. 364 /* Right now we only have one section so just check it.
382 * If more sections are added in the future, please don't 365 * If more sections are added in the future, please don't
@@ -401,12 +384,13 @@ static void parse_config_file(void)
401 * where both key and value could contain inner whitespace. */ 384 * where both key and value could contain inner whitespace. */
402 385
403 /* First get the key (an applet name in our case). */ 386 /* First get the key (an applet name in our case). */
404 e = strchr(s, '='); 387 char *e = strchr(s, '=');
405 if (e) { 388 if (e) {
406 s = get_trimmed_slice(s, e); 389 s = get_trimmed_slice(s, e);
407 } 390 }
408 if (!e || !*s) { /* Missing '=' or empty key. */ 391 if (!e || !*s) { /* Missing '=' or empty key. */
409 parse_error("keyword"); 392 errmsg = "keyword";
393 goto pe_label;
410 } 394 }
411 395
412 /* Ok, we have an applet name. Process the rhs if this 396 /* Ok, we have an applet name. Process the rhs if this
@@ -415,13 +399,16 @@ static void parse_config_file(void)
415 * up when the busybox configuration is changed. */ 399 * up when the busybox configuration is changed. */
416 applet_no = find_applet_by_name(s); 400 applet_no = find_applet_by_name(s);
417 if (applet_no >= 0) { 401 if (applet_no >= 0) {
402 unsigned i;
403 struct suid_config_t *sct;
404
418 /* Note: We currently don't check for duplicates! 405 /* Note: We currently don't check for duplicates!
419 * The last config line for each applet will be the 406 * The last config line for each applet will be the
420 * one used since we insert at the head of the list. 407 * one used since we insert at the head of the list.
421 * I suppose this could be considered a feature. */ 408 * I suppose this could be considered a feature. */
422 sct = xmalloc(sizeof(struct BB_suid_config)); 409 sct = xzalloc(sizeof(*sct));
423 sct->m_applet = applet_no; 410 sct->m_applet = applet_no;
424 sct->m_mode = 0; 411 /*sct->m_mode = 0;*/
425 sct->m_next = sct_head; 412 sct->m_next = sct_head;
426 sct_head = sct; 413 sct_head = sct;
427 414
@@ -430,48 +417,41 @@ static void parse_config_file(void)
430 e = skip_whitespace(e+1); 417 e = skip_whitespace(e+1);
431 418
432 for (i = 0; i < 3; i++) { 419 for (i = 0; i < 3; i++) {
433 /* There are 4 chars + 1 nul for each of user/group/other. */ 420 /* There are 4 chars for each of user/group/other.
434 static const char mode_chars[] ALIGN1 = "Ssx-\0" "Ssx-\0" "Ttx-"; 421 * "x-xx" instead of "x-" are to make
435 422 * "idx > 3" check catch invalid chars.
436 const char *q; 423 */
437 q = strchrnul(mode_chars + 5*i, *e++); 424 static const char mode_chars[] ALIGN1 = "Ssx-" "Ssx-" "x-xx";
438 if (!*q) { 425 static const unsigned short mode_mask[] ALIGN2 = {
439 parse_error("mode"); 426 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* Ssx- */
427 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* Ssx- */
428 S_IXOTH, 0 /* x- */
429 };
430 const char *q = strchrnul(mode_chars + 4*i, *e);
431 unsigned idx = q - (mode_chars + 4*i);
432 if (idx > 3) {
433 errmsg = "mode";
434 goto pe_label;
440 } 435 }
441 /* Adjust by -i to account for nul. */ 436 sct->m_mode |= mode_mask[q - mode_chars];
442 sct->m_mode |= mode_mask[(q - mode_chars) - i]; 437 e++;
443 } 438 }
444 439
445 /* Now get the user/group info. */ 440 /* Now get the user/group info. */
446 441
447 s = skip_whitespace(e); 442 s = skip_whitespace(e);
448 443 /* Default is 0.0, else parse USER.GROUP: */
449 /* Note: we require whitespace between the mode and the 444 if (*s) {
450 * user/group info. */ 445 /* We require whitespace between mode and USER.GROUP */
451 if ((s == e) || !(e = strchr(s, '.'))) { 446 if ((s == e) || !(e = strchr(s, '.'))) {
452 parse_error("<uid>.<gid>"); 447 errmsg = "uid.gid";
453 } 448 goto pe_label;
454 *e++ = '\0';
455
456 /* We can't use get_ug_id here since it would exit()
457 * if a uid or gid was not found. Oh well... */
458 sct->m_uid = bb_strtoul(s, NULL, 10);
459 if (errno) {
460 struct passwd *pwd = getpwnam(s);
461 if (!pwd) {
462 parse_error("user");
463 } 449 }
464 sct->m_uid = pwd->pw_uid; 450 *e = ':'; /* get_uidgid needs USER:GROUP syntax */
465 } 451 if (get_uidgid(&sct->m_ugid, s, /*allow_numeric:*/ 1) == 0) {
466 452 errmsg = "unknown user/group";
467 sct->m_gid = bb_strtoul(e, NULL, 10); 453 goto pe_label;
468 if (errno) {
469 struct group *grp;
470 grp = getgrnam(e);
471 if (!grp) {
472 parse_error("group");
473 } 454 }
474 sct->m_gid = grp->gr_gid;
475 } 455 }
476 } 456 }
477 continue; 457 continue;
@@ -485,22 +465,18 @@ static void parse_config_file(void)
485 * We may want to simply ignore such lines in case they 465 * We may want to simply ignore such lines in case they
486 * are used in some future version of busybox. */ 466 * are used in some future version of busybox. */
487 if (!section) { 467 if (!section) {
488 parse_error("keyword outside section"); 468 errmsg = "keyword outside section";
469 goto pe_label;
489 } 470 }
490 471
491 } /* while (1) */ 472 } /* while (1) */
492 473
493 pe_label: 474 pe_label:
494 fprintf(stderr, "Parse error in %s, line %d: %s\n",
495 config_file, lc, errmsg);
496
497 fclose(f); 475 fclose(f);
476 bb_error_msg("parse error in %s, line %u: %s", config_file, lc, errmsg);
477
498 /* Release any allocated memory before returning. */ 478 /* Release any allocated memory before returning. */
499 while (sct_head) { 479 llist_free((llist_t*)sct_head, NULL);
500 sct = sct_head->m_next;
501 free(sct_head);
502 sct_head = sct;
503 }
504} 480}
505# else 481# else
506static inline void parse_config_file(void) 482static inline void parse_config_file(void)
@@ -522,7 +498,7 @@ static void check_suid(int applet_no)
522# if ENABLE_FEATURE_SUID_CONFIG 498# if ENABLE_FEATURE_SUID_CONFIG
523 if (suid_cfg_readable) { 499 if (suid_cfg_readable) {
524 uid_t uid; 500 uid_t uid;
525 struct BB_suid_config *sct; 501 struct suid_config_t *sct;
526 mode_t m; 502 mode_t m;
527 503
528 for (sct = suid_config; sct; sct = sct->m_next) { 504 for (sct = suid_config; sct; sct = sct->m_next) {
@@ -531,36 +507,40 @@ static void check_suid(int applet_no)
531 } 507 }
532 goto check_need_suid; 508 goto check_need_suid;
533 found: 509 found:
510 /* Is this user allowed to run this applet? */
534 m = sct->m_mode; 511 m = sct->m_mode;
535 if (sct->m_uid == ruid) 512 if (sct->m_ugid.uid == ruid)
536 /* same uid */ 513 /* same uid */
537 m >>= 6; 514 m >>= 6;
538 else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid)) 515 else if ((sct->m_ugid.gid == rgid) || ingroup(ruid, sct->m_ugid.gid))
539 /* same group / in group */ 516 /* same group / in group */
540 m >>= 3; 517 m >>= 3;
541 518 if (!(m & S_IXOTH)) /* is x bit not set? */
542 if (!(m & S_IXOTH)) /* is x bit not set ? */ 519 bb_error_msg_and_die("you have no permission to run this applet");
543 bb_error_msg_and_die("you have no permission to run this applet!");
544
545 /* _both_ sgid and group_exec have to be set for setegid */
546 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
547 rgid = sct->m_gid;
548 /* else (no setegid) we will set egid = rgid */
549 520
550 /* We set effective AND saved ids. If saved-id is not set 521 /* We set effective AND saved ids. If saved-id is not set
551 * like we do below, seteiud(0) can still later succeed! */ 522 * like we do below, seteuid(0) can still later succeed! */
523
524 /* Are we directed to change gid
525 * (APPLET = *s* USER.GROUP or APPLET = *S* USER.GROUP)?
526 */
527 if (sct->m_mode & S_ISGID)
528 rgid = sct->m_ugid.gid;
529 /* else: we will set egid = rgid, thus dropping sgid effect */
552 if (setresgid(-1, rgid, rgid)) 530 if (setresgid(-1, rgid, rgid))
553 bb_perror_msg_and_die("setresgid"); 531 bb_perror_msg_and_die("setresgid");
554 532
555 /* do we have to set effective uid? */ 533 /* Are we directed to change uid
534 * (APPLET = s** USER.GROUP or APPLET = S** USER.GROUP)?
535 */
556 uid = ruid; 536 uid = ruid;
557 if (sct->m_mode & S_ISUID) 537 if (sct->m_mode & S_ISUID)
558 uid = sct->m_uid; 538 uid = sct->m_ugid.uid;
559 /* else (no seteuid) we will set euid = ruid */ 539 /* else: we will set euid = ruid, thus dropping suid effect */
560
561 if (setresuid(-1, uid, uid)) 540 if (setresuid(-1, uid, uid))
562 bb_perror_msg_and_die("setresuid"); 541 bb_perror_msg_and_die("setresuid");
563 return; 542
543 goto ret;
564 } 544 }
565# if !ENABLE_FEATURE_SUID_CONFIG_QUIET 545# if !ENABLE_FEATURE_SUID_CONFIG_QUIET
566 { 546 {
@@ -568,7 +548,7 @@ static void check_suid(int applet_no)
568 548
569 if (!onetime) { 549 if (!onetime) {
570 onetime = 1; 550 onetime = 1;
571 fprintf(stderr, "Using fallback suid method\n"); 551 bb_error_msg("using fallback suid method");
572 } 552 }
573 } 553 }
574# endif 554# endif
@@ -583,6 +563,10 @@ static void check_suid(int applet_no)
583 xsetgid(rgid); /* drop all privileges */ 563 xsetgid(rgid); /* drop all privileges */
584 xsetuid(ruid); 564 xsetuid(ruid);
585 } 565 }
566# if ENABLE_FEATURE_SUID_CONFIG
567 ret: ;
568 llist_free((llist_t*)suid_config, NULL);
569# endif
586} 570}
587# else 571# else
588# define check_suid(x) ((void)0) 572# define check_suid(x) ((void)0)
@@ -799,9 +783,6 @@ int main(int argc UNUSED_PARAM, char **argv)
799#endif 783#endif
800{ 784{
801 /* Tweak malloc for reduced memory consumption */ 785 /* Tweak malloc for reduced memory consumption */
802#ifndef PAGE_SIZE
803# define PAGE_SIZE (4*1024) /* guess */
804#endif
805#ifdef M_TRIM_THRESHOLD 786#ifdef M_TRIM_THRESHOLD
806 /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory 787 /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory
807 * to keep before releasing to the OS 788 * to keep before releasing to the OS
diff --git a/libbb/bb_basename.c b/libbb/bb_basename.c
deleted file mode 100644
index 92fdb6545..000000000
--- a/libbb/bb_basename.c
+++ /dev/null
@@ -1,23 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2007 Denys Vlasenko
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9
10#include "libbb.h"
11
12const char* FAST_FUNC bb_basename(const char *name)
13{
14 const char *cp = strrchr(name, '/');
15 if (cp)
16 return cp + 1;
17 if (ENABLE_PLATFORM_MINGW32) {
18 cp = strrchr(name, '\\');
19 if (cp)
20 return cp + 1;
21 }
22 return name;
23}
diff --git a/libbb/dump.c b/libbb/dump.c
index 1b1d03a66..919fe135c 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -99,7 +99,7 @@ static NOINLINE int bb_dump_size(FS *fs)
99static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) 99static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
100{ 100{
101 enum { NOTOKAY, USEBCNT, USEPREC } sokay; 101 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
102 PR *pr, **nextpr = NULL; 102 PR *pr;
103 FU *fu; 103 FU *fu;
104 char *p1, *p2, *p3; 104 char *p1, *p2, *p3;
105 char savech, *fmtp; 105 char savech, *fmtp;
@@ -111,15 +111,12 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
111 * break each format unit into print units; each 111 * break each format unit into print units; each
112 * conversion character gets its own. 112 * conversion character gets its own.
113 */ 113 */
114 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { 114 for (nconv = 0, fmtp = fu->fmt; *fmtp; ) {
115 /* NOSTRICT */ 115 /* NOSTRICT */
116 /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/ 116 /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/
117 pr = xzalloc(sizeof(PR)); 117 pr = xzalloc(sizeof(PR));
118 if (!fu->nextpr) 118 if (!fu->nextpr)
119 fu->nextpr = pr; 119 fu->nextpr = pr;
120 /* ignore nextpr -- its unused inside the loop and is
121 * uninitialized 1st time through.
122 */
123 120
124 /* skip preceding text and up to the next % sign */ 121 /* skip preceding text and up to the next % sign */
125 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1) 122 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1)
diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c
index 72598d22e..db4be68ad 100644
--- a/libbb/get_last_path_component.c
+++ b/libbb/get_last_path_component.c
@@ -6,8 +6,21 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9
10#include "libbb.h" 9#include "libbb.h"
10
11const char* FAST_FUNC bb_basename(const char *name)
12{
13 const char *cp = strrchr(name, '/');
14 if (cp)
15 return cp + 1;
16#if ENABLE_PLATFORM_MINGW32
17 cp = strrchr(name, '\\');
18 if (cp)
19 return cp + 1;
20#endif
21 return name;
22}
23
11/* 24/*
12 * "/" -> "/" 25 * "/" -> "/"
13 * "abc" -> "abc" 26 * "abc" -> "abc"
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 8087b3ba6..02cbefec9 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -7,7 +7,9 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9 9
10#include <getopt.h> 10#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
11# include <getopt.h>
12#endif
11#include "libbb.h" 13#include "libbb.h"
12 14
13/* Documentation 15/* Documentation
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 67c5e0baa..e443c7a3e 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -41,6 +41,10 @@
41 */ 41 */
42#include "libbb.h" 42#include "libbb.h"
43#include "unicode.h" 43#include "unicode.h"
44#ifndef _POSIX_VDISABLE
45# define _POSIX_VDISABLE '\0'
46#endif
47
44 48
45#ifdef TEST 49#ifdef TEST
46# define ENABLE_FEATURE_EDITING 0 50# define ENABLE_FEATURE_EDITING 0
@@ -184,6 +188,7 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
184 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \ 188 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
185 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ 189 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
186} while (0) 190} while (0)
191
187static void deinit_S(void) 192static void deinit_S(void)
188{ 193{
189#if ENABLE_FEATURE_EDITING_FANCY_PROMPT 194#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
@@ -1684,7 +1689,7 @@ static void ask_terminal(void)
1684 * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33 1689 * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33
1685 * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists 1690 * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists
1686 * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick! 1691 * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick!
1687 * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}]) 1692 * poll([{fd=0, events=POLLIN}], 1, -1) = 1 ([{fd=0, revents=POLLIN}])
1688 * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first 1693 * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first
1689 */ 1694 */
1690 struct pollfd pfd; 1695 struct pollfd pfd;
@@ -1842,10 +1847,11 @@ static void win_changed(int nsig)
1842{ 1847{
1843 int sv_errno = errno; 1848 int sv_errno = errno;
1844 unsigned width; 1849 unsigned width;
1850
1845 get_terminal_width_height(0, &width, NULL); 1851 get_terminal_width_height(0, &width, NULL);
1846 cmdedit_setwidth(width, nsig /* - just a yes/no flag */); 1852//FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!)
1847 if (nsig == SIGWINCH) 1853 cmdedit_setwidth(width, /*redraw_flg:*/ nsig);
1848 signal(SIGWINCH, win_changed); /* rearm ourself */ 1854
1849 errno = sv_errno; 1855 errno = sv_errno;
1850} 1856}
1851 1857
@@ -2031,14 +2037,9 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2031 new_settings.c_cc[VMIN] = 1; 2037 new_settings.c_cc[VMIN] = 1;
2032 new_settings.c_cc[VTIME] = 0; 2038 new_settings.c_cc[VTIME] = 0;
2033 /* Turn off CTRL-C, so we can trap it */ 2039 /* Turn off CTRL-C, so we can trap it */
2034#ifndef _POSIX_VDISABLE
2035# define _POSIX_VDISABLE '\0'
2036#endif
2037 new_settings.c_cc[VINTR] = _POSIX_VDISABLE; 2040 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
2038 tcsetattr_stdin_TCSANOW(&new_settings); 2041 tcsetattr_stdin_TCSANOW(&new_settings);
2039 2042
2040 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
2041 win_changed(0); /* do initial resizing */
2042#if ENABLE_USERNAME_OR_HOMEDIR 2043#if ENABLE_USERNAME_OR_HOMEDIR
2043 { 2044 {
2044 struct passwd *entry; 2045 struct passwd *entry;
@@ -2061,6 +2062,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2061 parse_and_put_prompt(prompt); 2062 parse_and_put_prompt(prompt);
2062 ask_terminal(); 2063 ask_terminal();
2063 2064
2065 /* Install window resize handler (NB: after *all* init is complete) */
2066//FIXME: save entire sigaction!
2067 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
2068 win_changed(0); /* get initial window size */
2069
2064 read_key_buffer[0] = 0; 2070 read_key_buffer[0] = 0;
2065 while (1) { 2071 while (1) {
2066 /* 2072 /*
diff --git a/libbb/llist.c b/libbb/llist.c
index ed84e6472..032e9fac8 100644
--- a/libbb/llist.c
+++ b/libbb/llist.c
@@ -62,7 +62,7 @@ void FAST_FUNC llist_unlink(llist_t **head, llist_t *elm)
62 62
63/* Recursively free all elements in the linked list. If freeit != NULL 63/* Recursively free all elements in the linked list. If freeit != NULL
64 * call it on each datum in the list */ 64 * call it on each datum in the list */
65void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data)) 65void FAST_FUNC llist_free(llist_t *elm, void (*freeit)(void *data))
66{ 66{
67 while (elm) { 67 while (elm) {
68 void *data = llist_pop(&elm); 68 void *data = llist_pop(&elm);
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index c6c04d44a..39ffa084f 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -27,9 +27,10 @@ static int i64c(int i)
27 return ('a' - 38 + i); 27 return ('a' - 38 + i);
28} 28}
29 29
30int FAST_FUNC crypt_make_salt(char *p, int cnt, int x) 30int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */)
31{ 31{
32 x += getpid() + time(NULL); 32 /* was: x += ... */
33 int x = getpid() + monotonic_us();
33 do { 34 do {
34 /* x = (x*1664525 + 1013904223) % 2^32 generator is lame 35 /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
35 * (low-order bit is not "random", etc...), 36 * (low-order bit is not "random", etc...),
@@ -47,6 +48,26 @@ int FAST_FUNC crypt_make_salt(char *p, int cnt, int x)
47 return x; 48 return x;
48} 49}
49 50
51char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo)
52{
53 int len = 2/2;
54 char *salt_ptr = salt;
55 if (algo[0] != 'd') { /* not des */
56 len = 8/2; /* so far assuming md5 */
57 *salt_ptr++ = '$';
58 *salt_ptr++ = '1';
59 *salt_ptr++ = '$';
60#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
61 if (algo[0] == 's') { /* sha */
62 salt[1] = '5' + (strcmp(algo, "sha512") == 0);
63 len = 16/2;
64 }
65#endif
66 }
67 crypt_make_salt(salt_ptr, len);
68 return salt_ptr;
69}
70
50#if ENABLE_USE_BB_CRYPT 71#if ENABLE_USE_BB_CRYPT
51 72
52static char* 73static char*
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 8664bc625..192f83d6e 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -55,32 +55,35 @@
55 * which detects EAGAIN and uses poll() to wait on the fd. 55 * which detects EAGAIN and uses poll() to wait on the fd.
56 * Thankfully, poll() doesn't care about O_NONBLOCK flag. 56 * Thankfully, poll() doesn't care about O_NONBLOCK flag.
57 */ 57 */
58ssize_t FAST_FUNC nonblock_safe_read(int fd, void *buf, size_t count) 58ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR)
59{ 59{
60 struct pollfd pfd[1]; 60 struct pollfd pfd[1];
61 ssize_t n; 61 ssize_t n;
62 62
63 while (1) { 63 while (1) {
64 n = safe_read(fd, buf, count); 64 n = loop_on_EINTR ? safe_read(fd, buf, count) : read(fd, buf, count);
65 if (n >= 0 || errno != EAGAIN) 65 if (n >= 0 || errno != EAGAIN)
66 return n; 66 return n;
67 /* fd is in O_NONBLOCK mode. Wait using poll and repeat */ 67 /* fd is in O_NONBLOCK mode. Wait using poll and repeat */
68 pfd[0].fd = fd; 68 pfd[0].fd = fd;
69 pfd[0].events = POLLIN; 69 pfd[0].events = POLLIN;
70 safe_poll(pfd, 1, -1); /* note: this pulls in printf */ 70 /* note: safe_poll pulls in printf */
71 loop_on_EINTR ? safe_poll(pfd, 1, -1) : poll(pfd, 1, -1);
71 } 72 }
72} 73}
73 74
74// Reads one line a-la fgets (but doesn't save terminating '\n'). 75// Reads one line a-la fgets (but doesn't save terminating '\n').
75// Reads byte-by-byte. Useful when it is important to not read ahead. 76// Reads byte-by-byte. Useful when it is important to not read ahead.
76// Bytes are appended to pfx (which must be malloced, or NULL). 77// Bytes are appended to pfx (which must be malloced, or NULL).
77char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p) 78char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p)
78{ 79{
79 char *p; 80 char *p;
80 size_t sz = buf ? strlen(buf) : 0; 81 char *buf = NULL;
82 size_t sz = 0;
81 size_t maxsz = maxsz_p ? *maxsz_p : (INT_MAX - 4095); 83 size_t maxsz = maxsz_p ? *maxsz_p : (INT_MAX - 4095);
82 84
83 goto jump_in; 85 goto jump_in;
86
84 while (sz < maxsz) { 87 while (sz < maxsz) {
85 if ((size_t)(p - buf) == sz) { 88 if ((size_t)(p - buf) == sz) {
86 jump_in: 89 jump_in:
@@ -88,8 +91,8 @@ char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p)
88 p = buf + sz; 91 p = buf + sz;
89 sz += 128; 92 sz += 128;
90 } 93 }
91 /* nonblock_safe_read() because we are used by e.g. shells */ 94 if (nonblock_immune_read(fd, p, 1, /*loop_on_EINTR:*/ 1) != 1) {
92 if (nonblock_safe_read(fd, p, 1) != 1) { /* EOF/error */ 95 /* EOF/error */
93 if (p == buf) { /* we read nothing */ 96 if (p == buf) { /* we read nothing */
94 free(buf); 97 free(buf);
95 return NULL; 98 return NULL;