aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2014-04-30 17:38:27 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2014-04-30 17:38:27 +0200
commit43b8a1cc3825eedb85e10cbe2f91a20fbe7c4434 (patch)
tree62bc18ff75268f611a0b97320f036dc32bfbccaf
parentd5929d602ee952d2f2468b4957a4ebd219108b2f (diff)
downloadbusybox-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>
-rw-r--r--miscutils/crond.c72
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
489static void process_cron_update_file(void) 503static 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
558static void set_env_vars(struct passwd *pas) 572static 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
573static void change_user(struct passwd *pas) 590static 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
586static pid_t 603static pid_t
587fork_job(const char *user, int mailFd, 604fork_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
726static void start_one_job(const char *user, CronLine *line) 749static 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");