diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2014-04-30 17:38:27 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-04-30 17:38:27 +0200 |
| commit | 43b8a1cc3825eedb85e10cbe2f91a20fbe7c4434 (patch) | |
| tree | 62bc18ff75268f611a0b97320f036dc32bfbccaf /miscutils | |
| parent | d5929d602ee952d2f2468b4957a4ebd219108b2f (diff) | |
| download | busybox-w32-43b8a1cc3825eedb85e10cbe2f91a20fbe7c4434.tar.gz busybox-w32-43b8a1cc3825eedb85e10cbe2f91a20fbe7c4434.tar.bz2 busybox-w32-43b8a1cc3825eedb85e10cbe2f91a20fbe7c4434.zip | |
crond: implement "SHELL=prog" in crontab. Export LOGNAME as POSIX wants
function old new delta
fork_job 343 456 +113
load_crontab 688 777 +89
crond_main 1456 1434 -22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 202/-22) Total: 180 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'miscutils')
| -rw-r--r-- | miscutils/crond.c | 72 |
1 files changed, 48 insertions, 24 deletions
diff --git a/miscutils/crond.c b/miscutils/crond.c index 210da5f47..3659b9a6f 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
| @@ -104,6 +104,7 @@ typedef struct CronLine { | |||
| 104 | int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ | 104 | int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ |
| 105 | char *cl_mailto; /* whom to mail results, may be NULL */ | 105 | char *cl_mailto; /* whom to mail results, may be NULL */ |
| 106 | #endif | 106 | #endif |
| 107 | char *cl_shell; | ||
| 107 | /* ordered by size, not in natural order. makes code smaller: */ | 108 | /* ordered by size, not in natural order. makes code smaller: */ |
| 108 | char cl_Dow[7]; /* 0-6, beginning sunday */ | 109 | char cl_Dow[7]; /* 0-6, beginning sunday */ |
| 109 | char cl_Mons[12]; /* 0-11 */ | 110 | char cl_Mons[12]; /* 0-11 */ |
| @@ -135,6 +136,8 @@ struct globals { | |||
| 135 | #if SETENV_LEAKS | 136 | #if SETENV_LEAKS |
| 136 | char *env_var_user; | 137 | char *env_var_user; |
| 137 | char *env_var_home; | 138 | char *env_var_home; |
| 139 | char *env_var_shell; | ||
| 140 | char *env_var_logname; | ||
| 138 | #endif | 141 | #endif |
| 139 | } FIX_ALIASING; | 142 | } FIX_ALIASING; |
| 140 | #define G (*(struct globals*)&bb_common_bufsiz1) | 143 | #define G (*(struct globals*)&bb_common_bufsiz1) |
| @@ -397,6 +400,7 @@ static void load_crontab(const char *fileName) | |||
| 397 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | 400 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
| 398 | char *mailTo = NULL; | 401 | char *mailTo = NULL; |
| 399 | #endif | 402 | #endif |
| 403 | char *shell = NULL; | ||
| 400 | 404 | ||
| 401 | delete_cronfile(fileName); | 405 | delete_cronfile(fileName); |
| 402 | 406 | ||
| @@ -441,7 +445,12 @@ static void load_crontab(const char *fileName) | |||
| 441 | #endif /* otherwise just ignore such lines */ | 445 | #endif /* otherwise just ignore such lines */ |
| 442 | continue; | 446 | continue; |
| 443 | } | 447 | } |
| 444 | //TODO: handle SHELL=, HOME= too? "man crontab" says: | 448 | if (0 == strncmp(tokens[0], "SHELL=", 6)) { |
| 449 | free(shell); | ||
| 450 | shell = xstrdup(&tokens[0][6]); | ||
| 451 | continue; | ||
| 452 | } | ||
| 453 | //TODO: handle HOME= too? "man crontab" says: | ||
| 445 | //name = value | 454 | //name = value |
| 446 | // | 455 | // |
| 447 | //where the spaces around the equal-sign (=) are optional, and any subsequent | 456 | //where the spaces around the equal-sign (=) are optional, and any subsequent |
| @@ -453,6 +462,7 @@ static void load_crontab(const char *fileName) | |||
| 453 | //SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd | 462 | //SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd |
| 454 | //line of the crontab's owner. HOME and SHELL may be overridden by settings | 463 | //line of the crontab's owner. HOME and SHELL may be overridden by settings |
| 455 | //in the crontab; LOGNAME may not. | 464 | //in the crontab; LOGNAME may not. |
| 465 | |||
| 456 | /* check if a minimum of tokens is specified */ | 466 | /* check if a minimum of tokens is specified */ |
| 457 | if (n < 6) | 467 | if (n < 6) |
| 458 | continue; | 468 | continue; |
| @@ -472,9 +482,9 @@ static void load_crontab(const char *fileName) | |||
| 472 | /* copy mailto (can be NULL) */ | 482 | /* copy mailto (can be NULL) */ |
| 473 | line->cl_mailto = xstrdup(mailTo); | 483 | line->cl_mailto = xstrdup(mailTo); |
| 474 | #endif | 484 | #endif |
| 485 | line->cl_shell = xstrdup(shell); | ||
| 475 | /* copy command */ | 486 | /* copy command */ |
| 476 | line->cl_cmd = xstrdup(tokens[5]); | 487 | line->cl_cmd = xstrdup(tokens[5]); |
| 477 | log5(" command:%s", tokens[5]); | ||
| 478 | pline = &line->cl_next; | 488 | pline = &line->cl_next; |
| 479 | //bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); | 489 | //bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); |
| 480 | } | 490 | } |
| @@ -484,6 +494,10 @@ static void load_crontab(const char *fileName) | |||
| 484 | G.cron_files = file; | 494 | G.cron_files = file; |
| 485 | } | 495 | } |
| 486 | config_close(parser); | 496 | config_close(parser); |
| 497 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | ||
| 498 | free(mailTo); | ||
| 499 | #endif | ||
| 500 | free(shell); | ||
| 487 | } | 501 | } |
| 488 | 502 | ||
| 489 | static void process_cron_update_file(void) | 503 | static void process_cron_update_file(void) |
| @@ -555,19 +569,22 @@ static void safe_setenv(char **pvar_val, const char *var, const char *val) | |||
| 555 | } | 569 | } |
| 556 | #endif | 570 | #endif |
| 557 | 571 | ||
| 558 | static void set_env_vars(struct passwd *pas) | 572 | static void set_env_vars(struct passwd *pas, const char *shell) |
| 559 | { | 573 | { |
| 574 | /* POSIX requires crond to set up at least HOME, LOGNAME, PATH, SHELL. | ||
| 575 | * We assume crond inherited suitable PATH. | ||
| 576 | */ | ||
| 560 | #if SETENV_LEAKS | 577 | #if SETENV_LEAKS |
| 578 | safe_setenv(&G.env_var_logname, "LOGNAME", pas->pw_name); | ||
| 561 | safe_setenv(&G.env_var_user, "USER", pas->pw_name); | 579 | safe_setenv(&G.env_var_user, "USER", pas->pw_name); |
| 562 | safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); | 580 | safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); |
| 563 | /* if we want to set user's shell instead: */ | 581 | safe_setenv(&G.env_var_shell, "SHELL", shell); |
| 564 | /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ | ||
| 565 | #else | 582 | #else |
| 583 | xsetenv("LOGNAME", pas->pw_name); | ||
| 566 | xsetenv("USER", pas->pw_name); | 584 | xsetenv("USER", pas->pw_name); |
| 567 | xsetenv("HOME", pas->pw_dir); | 585 | xsetenv("HOME", pas->pw_dir); |
| 586 | xsetenv("SHELL", shell); | ||
| 568 | #endif | 587 | #endif |
| 569 | /* currently, we use constant one: */ | ||
| 570 | /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ | ||
| 571 | } | 588 | } |
| 572 | 589 | ||
| 573 | static void change_user(struct passwd *pas) | 590 | static void change_user(struct passwd *pas) |
| @@ -584,12 +601,11 @@ static void change_user(struct passwd *pas) | |||
| 584 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | 601 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
| 585 | 602 | ||
| 586 | static pid_t | 603 | static pid_t |
| 587 | fork_job(const char *user, int mailFd, | 604 | fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail) |
| 588 | const char *prog, | 605 | { |
| 589 | const char *shell_cmd /* if NULL, we run sendmail */ | ||
| 590 | ) { | ||
| 591 | smallint sv_logmode; | ||
| 592 | struct passwd *pas; | 606 | struct passwd *pas; |
| 607 | const char *shell, *prog; | ||
| 608 | smallint sv_logmode; | ||
| 593 | pid_t pid; | 609 | pid_t pid; |
| 594 | 610 | ||
| 595 | /* prepare things before vfork */ | 611 | /* prepare things before vfork */ |
| @@ -598,7 +614,11 @@ fork_job(const char *user, int mailFd, | |||
| 598 | bb_error_msg("can't get uid for %s", user); | 614 | bb_error_msg("can't get uid for %s", user); |
| 599 | goto err; | 615 | goto err; |
| 600 | } | 616 | } |
| 601 | set_env_vars(pas); | 617 | |
| 618 | shell = line->cl_shell ? line->cl_shell : DEFAULT_SHELL; | ||
| 619 | prog = run_sendmail ? SENDMAIL : shell; | ||
| 620 | |||
| 621 | set_env_vars(pas, shell); | ||
| 602 | 622 | ||
| 603 | sv_logmode = logmode; | 623 | sv_logmode = logmode; |
| 604 | pid = vfork(); | 624 | pid = vfork(); |
| @@ -608,12 +628,15 @@ fork_job(const char *user, int mailFd, | |||
| 608 | change_user(pas); | 628 | change_user(pas); |
| 609 | log5("child running %s", prog); | 629 | log5("child running %s", prog); |
| 610 | if (mailFd >= 0) { | 630 | if (mailFd >= 0) { |
| 611 | xmove_fd(mailFd, shell_cmd ? 1 : 0); | 631 | xmove_fd(mailFd, run_sendmail ? 0 : 1); |
| 612 | dup2(1, 2); | 632 | dup2(1, 2); |
| 613 | } | 633 | } |
| 614 | /* crond 3.0pl1-100 puts tasks in separate process groups */ | 634 | /* crond 3.0pl1-100 puts tasks in separate process groups */ |
| 615 | bb_setpgrp(); | 635 | bb_setpgrp(); |
| 616 | execlp(prog, prog, (shell_cmd ? "-c" : SENDMAIL_ARGS), shell_cmd, (char *) NULL); | 636 | if (!run_sendmail) |
| 637 | execlp(prog, prog, "-c", line->cl_cmd, (char *) NULL); | ||
| 638 | else | ||
| 639 | execlp(prog, prog, SENDMAIL_ARGS, (char *) NULL); | ||
| 617 | /* | 640 | /* |
| 618 | * I want this error message on stderr too, | 641 | * I want this error message on stderr too, |
| 619 | * even if other messages go only to syslog: | 642 | * even if other messages go only to syslog: |
| @@ -662,7 +685,7 @@ static void start_one_job(const char *user, CronLine *line) | |||
| 662 | } | 685 | } |
| 663 | } | 686 | } |
| 664 | 687 | ||
| 665 | line->cl_pid = fork_job(user, mailFd, DEFAULT_SHELL, line->cl_cmd); | 688 | line->cl_pid = fork_job(user, mailFd, line, /*sendmail?*/ 0); |
| 666 | if (mailFd >= 0) { | 689 | if (mailFd >= 0) { |
| 667 | if (line->cl_pid <= 0) { | 690 | if (line->cl_pid <= 0) { |
| 668 | unlink(mailFile); | 691 | unlink(mailFile); |
| @@ -718,13 +741,14 @@ static void process_finished_job(const char *user, CronLine *line) | |||
| 718 | } | 741 | } |
| 719 | line->cl_empty_mail_size = 0; | 742 | line->cl_empty_mail_size = 0; |
| 720 | /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */ | 743 | /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */ |
| 721 | line->cl_pid = fork_job(user, mailFd, SENDMAIL, NULL); | 744 | line->cl_pid = fork_job(user, mailFd, line, /*sendmail?*/ 1); |
| 722 | } | 745 | } |
| 723 | 746 | ||
| 724 | #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ | 747 | #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ |
| 725 | 748 | ||
| 726 | static void start_one_job(const char *user, CronLine *line) | 749 | static void start_one_job(const char *user, CronLine *line) |
| 727 | { | 750 | { |
| 751 | const char *shell; | ||
| 728 | struct passwd *pas; | 752 | struct passwd *pas; |
| 729 | pid_t pid; | 753 | pid_t pid; |
| 730 | 754 | ||
| @@ -735,7 +759,8 @@ static void start_one_job(const char *user, CronLine *line) | |||
| 735 | } | 759 | } |
| 736 | 760 | ||
| 737 | /* Prepare things before vfork */ | 761 | /* Prepare things before vfork */ |
| 738 | set_env_vars(pas); | 762 | shell = line->cl_shell ? line->cl_shell : DEFAULT_SHELL; |
| 763 | set_env_vars(pas, shell); | ||
| 739 | 764 | ||
| 740 | /* Fork as the user in question and run program */ | 765 | /* Fork as the user in question and run program */ |
| 741 | pid = vfork(); | 766 | pid = vfork(); |
| @@ -743,11 +768,11 @@ static void start_one_job(const char *user, CronLine *line) | |||
| 743 | /* CHILD */ | 768 | /* CHILD */ |
| 744 | /* initgroups, setgid, setuid, and chdir to home or CRON_DIR */ | 769 | /* initgroups, setgid, setuid, and chdir to home or CRON_DIR */ |
| 745 | change_user(pas); | 770 | change_user(pas); |
| 746 | log5("child running %s", DEFAULT_SHELL); | 771 | log5("child running %s", shell); |
| 747 | /* crond 3.0pl1-100 puts tasks in separate process groups */ | 772 | /* crond 3.0pl1-100 puts tasks in separate process groups */ |
| 748 | bb_setpgrp(); | 773 | bb_setpgrp(); |
| 749 | execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_cmd, (char *) NULL); | 774 | execl(shell, shell, "-c", line->cl_cmd, (char *) NULL); |
| 750 | bb_error_msg_and_die("can't execute '%s' for user %s", DEFAULT_SHELL, user); | 775 | bb_error_msg_and_die("can't execute '%s' for user %s", shell, user); |
| 751 | } | 776 | } |
| 752 | if (pid < 0) { | 777 | if (pid < 0) { |
| 753 | bb_perror_msg("vfork"); | 778 | bb_perror_msg("vfork"); |
| @@ -916,11 +941,10 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
| 916 | logmode = LOGMODE_SYSLOG; | 941 | logmode = LOGMODE_SYSLOG; |
| 917 | } | 942 | } |
| 918 | 943 | ||
| 919 | reopen_logfile_to_stderr(); | 944 | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ |
| 920 | 945 | ||
| 946 | reopen_logfile_to_stderr(); | ||
| 921 | xchdir(G.crontab_dir_name); | 947 | xchdir(G.crontab_dir_name); |
| 922 | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ | ||
| 923 | xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ | ||
| 924 | log8("crond (busybox "BB_VER") started, log level %d", G.log_level); | 948 | log8("crond (busybox "BB_VER") started, log level %d", G.log_level); |
| 925 | rescan_crontab_dir(); | 949 | rescan_crontab_dir(); |
| 926 | write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); | 950 | write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); |
