aboutsummaryrefslogtreecommitdiff
path: root/miscutils
diff options
context:
space:
mode:
authormbartlett21 <29034492+mbartlett21@users.noreply.github.com>2026-05-03 18:53:07 +1000
committerGitHub <noreply@github.com>2026-05-03 09:53:07 +0100
commitc23112c3a0bbf1d07f03b3c07fe96b5b4c5271f1 (patch)
tree7e14fca560a2e729f90e97282f9eea60769064da /miscutils
parent750a5e863cc04584ba50722d8b003e279cd67d24 (diff)
downloadbusybox-w32-c23112c3a0bbf1d07f03b3c07fe96b5b4c5271f1.tar.gz
busybox-w32-c23112c3a0bbf1d07f03b3c07fe96b5b4c5271f1.tar.bz2
busybox-w32-c23112c3a0bbf1d07f03b3c07fe96b5b4c5271f1.zip
Add crond and crontab (#561)
* Enable crontab * Enable crond * Allow sendmail to be used in crond This also adds another option to the mingw_popen_fd function to capture stderr as well. And also added the options to support WNOHANG as well as an unused status in mingw_wait3 * Check current uid when running crond * Only show tail for mailto jobs * Use system drive for cron * crond: add missing feature check * crond: use spawn_detach for background operation
Diffstat (limited to 'miscutils')
-rw-r--r--miscutils/crond.c183
-rw-r--r--miscutils/crontab.c29
2 files changed, 204 insertions, 8 deletions
diff --git a/miscutils/crond.c b/miscutils/crond.c
index 6a384fdfb..bbb312882 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -11,7 +11,7 @@
11//config:config CROND 11//config:config CROND
12//config: bool "crond (15 kb)" 12//config: bool "crond (15 kb)"
13//config: default y 13//config: default y
14//config: select FEATURE_SYSLOG 14//config: depends on FEATURE_SYSLOG || PLATFORM_MINGW32
15//config: help 15//config: help
16//config: Crond is a background daemon that parses individual crontab 16//config: Crond is a background daemon that parses individual crontab
17//config: files and executes commands on behalf of the users in question. 17//config: files and executes commands on behalf of the users in question.
@@ -77,7 +77,12 @@
77 77
78#include "libbb.h" 78#include "libbb.h"
79#include "common_bufsiz.h" 79#include "common_bufsiz.h"
80#if ENABLE_PLATFORM_MINGW32
81#include <unistd.h>
82#include "BB_VER.h"
83#else
80#include <syslog.h> 84#include <syslog.h>
85#endif
81 86
82#if 0 87#if 0
83/* If libc tracks and reuses setenv()-allocated memory, ok to set this to 0 */ 88/* If libc tracks and reuses setenv()-allocated memory, ok to set this to 0 */
@@ -123,6 +128,9 @@ typedef struct CronLine {
123#if ENABLE_FEATURE_CROND_CALL_SENDMAIL 128#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
124 int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ 129 int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */
125 char *cl_mailto; /* whom to mail results, may be NULL */ 130 char *cl_mailto; /* whom to mail results, may be NULL */
131#if ENABLE_PLATFORM_MINGW32
132 int randomint; /* appended to the file rather than the child's pid */
133#endif
126#endif 134#endif
127 char *cl_shell; 135 char *cl_shell;
128 char *cl_path; 136 char *cl_path;
@@ -153,6 +161,9 @@ struct globals {
153 time_t crontab_dir_mtime; 161 time_t crontab_dir_mtime;
154 const char *log_filename; 162 const char *log_filename;
155 const char *crontab_dir_name; /* = CRONTABS; */ 163 const char *crontab_dir_name; /* = CRONTABS; */
164#if ENABLE_PLATFORM_MINGW32
165 const char *crondir_name; /* = CRON_DIR; */
166#endif
156 CronFile *cron_files; 167 CronFile *cron_files;
157 char *default_shell; 168 char *default_shell;
158#if SETENV_LEAKS 169#if SETENV_LEAKS
@@ -163,6 +174,8 @@ struct globals {
163#endif 174#endif
164} FIX_ALIASING; 175} FIX_ALIASING;
165#define G (*(struct globals*)bb_common_bufsiz1) 176#define G (*(struct globals*)bb_common_bufsiz1)
177
178/* crondir_name and crontab_dir_name are initialised outside this in mingw */
166#define INIT_G() do { \ 179#define INIT_G() do { \
167 setup_common_bufsiz(); \ 180 setup_common_bufsiz(); \
168 G.log_level = 8; \ 181 G.log_level = 8; \
@@ -424,20 +437,39 @@ static void load_crontab(const char *fileName)
424 char *shell = NULL; 437 char *shell = NULL;
425 char *path = NULL; 438 char *path = NULL;
426 439
440#if ENABLE_PLATFORM_MINGW32
441 struct passwd *p;
442#endif
443
427 delete_cronfile(fileName); 444 delete_cronfile(fileName);
428 445
429 if (!getpwnam(fileName)) { 446 if (!(
447#if ENABLE_PLATFORM_MINGW32
448 p =
449#endif
450 getpwnam(fileName))) {
430 log7("ignoring file '%s' (no such user)", fileName); 451 log7("ignoring file '%s' (no such user)", fileName);
431 return; 452 return;
432 } 453 }
433 454
455#if ENABLE_PLATFORM_MINGW32
456 if (p->pw_uid != getuid()) {
457 log7("ignoring file '%s' (not current user)", fileName);
458 return;
459 }
460#endif
461
434 parser = config_open(fileName); 462 parser = config_open(fileName);
435 if (!parser) 463 if (!parser)
436 return; 464 return;
437 465
438 maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES; 466 maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES;
439 467
440 if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DAEMON_UID) { 468 if (fstat(fileno(parser->fp), &sbuf) == 0
469#if !ENABLE_PLATFORM_MINGW32
470 && sbuf.st_uid == DAEMON_UID
471#endif
472 ) {
441 CronFile *file = xzalloc(sizeof(CronFile)); 473 CronFile *file = xzalloc(sizeof(CronFile));
442 CronLine **pline; 474 CronLine **pline;
443 int n; 475 int n;
@@ -680,6 +712,7 @@ static void set_env_vars(struct passwd *pas, const char *shell, const char *path
680#endif 712#endif
681} 713}
682 714
715#if !ENABLE_PLATFORM_MINGW32
683static void change_user(struct passwd *pas) 716static void change_user(struct passwd *pas)
684{ 717{
685 /* careful: we're after vfork! */ 718 /* careful: we're after vfork! */
@@ -688,6 +721,7 @@ static void change_user(struct passwd *pas)
688 xchdir(CRON_DIR); 721 xchdir(CRON_DIR);
689 } 722 }
690} 723}
724#endif
691 725
692// TODO: sendmail should be _run-time_ option, not compile-time! 726// TODO: sendmail should be _run-time_ option, not compile-time!
693#if ENABLE_FEATURE_CROND_CALL_SENDMAIL 727#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
@@ -697,8 +731,16 @@ fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail)
697{ 731{
698 struct passwd *pas; 732 struct passwd *pas;
699 const char *shell, *prog; 733 const char *shell, *prog;
734#if !ENABLE_PLATFORM_MINGW32
700 smallint sv_logmode; 735 smallint sv_logmode;
736#endif
701 pid_t pid; 737 pid_t pid;
738#if ENABLE_PLATFORM_MINGW32
739 char *args[4];
740 char *cl_cmd_quoted;
741 char *shell_arg;
742 int fdpipe;
743#endif
702 744
703 /* prepare things before vfork */ 745 /* prepare things before vfork */
704 pas = getpwnam(user); 746 pas = getpwnam(user);
@@ -712,6 +754,37 @@ fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail)
712 754
713 set_env_vars(pas, shell, NULL); /* don't use crontab's PATH for sendmail */ 755 set_env_vars(pas, shell, NULL); /* don't use crontab's PATH for sendmail */
714 756
757#if ENABLE_PLATFORM_MINGW32
758 args[0] = (char *)prog;
759 if (run_sendmail) {
760 /* mailFd >= 0 */
761 /* Using the fd as input doesn't appear to work with external programs */
762 shell_arg = (char *)"sh -c \""SENDMAIL" "SENDMAIL_ARGS"\"";
763 if ((fdpipe = mingw_popen_fd("sh", shell_arg, "w", -1, &pid)) == -1)
764 bb_perror_msg("can't execute '%s'", "sh");
765
766 bb_copyfd_eof(mailFd, fdpipe);
767 close(fdpipe);
768 } else if (mailFd >= 0) {
769 /* run and pipe stdout and stderr */
770 cl_cmd_quoted = quote_arg(line->cl_cmd);
771 shell_arg = xasprintf("sh -c %s", cl_cmd_quoted);
772
773 if ((fdpipe = mingw_popen_fd("sh", shell_arg, "W", mailFd, &pid)) == -1)
774 bb_perror_msg("can't execute '%s'", "sh");
775
776 close(fdpipe);
777 free(shell_arg);
778 free(cl_cmd_quoted);
779 } else {
780 /* no redirection = we can just spawn it */
781 args[1] = (char *)"-c";
782 args[2] = line->cl_cmd;
783 args[3] = NULL;
784 pid = !(option_mask32 & OPT_f) ?
785 mingw_spawn_detach(args) : mingw_spawn(args);
786 }
787#else
715 sv_logmode = logmode; 788 sv_logmode = logmode;
716 pid = vfork(); 789 pid = vfork();
717 if (pid == 0) { 790 if (pid == 0) {
@@ -737,6 +810,7 @@ fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail)
737 bb_error_msg_and_die("can't execute '%s' for user %s", prog, user); 810 bb_error_msg_and_die("can't execute '%s' for user %s", prog, user);
738 } 811 }
739 logmode = sv_logmode; 812 logmode = sv_logmode;
813#endif
740 814
741 if (pid < 0) { 815 if (pid < 0) {
742 bb_simple_perror_msg("vfork"); 816 bb_simple_perror_msg("vfork");
@@ -758,13 +832,20 @@ static pid_t start_one_job(const char *user, CronLine *line)
758{ 832{
759 char mailFile[128]; 833 char mailFile[128];
760 int mailFd = -1; 834 int mailFd = -1;
761 835#if ENABLE_PLATFORM_MINGW32
836 line->randomint = 0;
837#endif
762 line->cl_pid = 0; 838 line->cl_pid = 0;
763 line->cl_empty_mail_size = 0; 839 line->cl_empty_mail_size = 0;
764 840
765 if (line->cl_mailto) { 841 if (line->cl_mailto) {
766 /* Open mail file (owner is root so nobody can screw with it) */ 842 /* Open mail file (owner is root so nobody can screw with it) */
843#if ENABLE_PLATFORM_MINGW32
844 MINGW_SPECIAL(open_read_close)("/dev/urandom", (char *)(&line->randomint), sizeof(int));
845 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d.%u", G.crondir_name, user, getpid(), line->randomint);
846#else
767 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", CRON_DIR, user, getpid()); 847 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", CRON_DIR, user, getpid());
848#endif
768 mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); 849 mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
769 850
770 if (mailFd >= 0) { 851 if (mailFd >= 0) {
@@ -782,10 +863,13 @@ static pid_t start_one_job(const char *user, CronLine *line)
782 if (line->cl_pid <= 0) { 863 if (line->cl_pid <= 0) {
783 unlink(mailFile); 864 unlink(mailFile);
784 } else { 865 } else {
866 /* on Windows open files can't be renamed */
867#if !ENABLE_PLATFORM_MINGW32
785 /* rename mail-file based on pid of process */ 868 /* rename mail-file based on pid of process */
786 char *mailFile2 = xasprintf("%s/cron.%s.%d", CRON_DIR, user, (int)line->cl_pid); 869 char *mailFile2 = xasprintf("%s/cron.%s.%d", CRON_DIR, user, (int)line->cl_pid);
787 rename(mailFile, mailFile2); // TODO: xrename? 870 rename(mailFile, mailFile2); // TODO: xrename?
788 free(mailFile2); 871 free(mailFile2);
872#endif
789 } 873 }
790 } 874 }
791 875
@@ -817,25 +901,45 @@ static void process_finished_job(const char *user, CronLine *line)
817 * End of primary job - check for mail file. 901 * End of primary job - check for mail file.
818 * If size has changed and the file is still valid, we send it. 902 * If size has changed and the file is still valid, we send it.
819 */ 903 */
904#if ENABLE_PLATFORM_MINGW32
905 /* on Windows, the files are all just named with the pid of the parent and a random id */
906 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d.%u", G.crondir_name, user, getpid(), line->randomint);
907#else
820 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", CRON_DIR, user, (int)pid); 908 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", CRON_DIR, user, (int)pid);
821 mailFd = open(mailFile, O_RDONLY); 909#endif
910 mailFd = open(mailFile, O_RDONLY
911#if ENABLE_PLATFORM_MINGW32
912 | O_BINARY | _O_NOINHERIT
913#endif
914 );
915#if !ENABLE_PLATFORM_MINGW32
822 unlink(mailFile); 916 unlink(mailFile);
917#endif
823 if (mailFd < 0) { 918 if (mailFd < 0) {
824 return; 919 return;
825 } 920 }
826 921
827 if (fstat(mailFd, &sbuf) < 0 922 if (fstat(mailFd, &sbuf) < 0
923#if !ENABLE_PLATFORM_MINGW32
828 || sbuf.st_uid != DAEMON_UID 924 || sbuf.st_uid != DAEMON_UID
829 || sbuf.st_nlink != 0 925 || sbuf.st_nlink != 0
926#endif
830 || sbuf.st_size == line->cl_empty_mail_size 927 || sbuf.st_size == line->cl_empty_mail_size
831 || !S_ISREG(sbuf.st_mode) 928 || !S_ISREG(sbuf.st_mode)
832 ) { 929 ) {
833 close(mailFd); 930 close(mailFd);
931#if ENABLE_PLATFORM_MINGW32
932 unlink(mailFile);
933#endif
834 return; 934 return;
835 } 935 }
836 line->cl_empty_mail_size = 0; 936 line->cl_empty_mail_size = 0;
837 /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */ 937 /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */
838 line->cl_pid = fork_job(user, mailFd, line, /*sendmail?*/ 1); 938 line->cl_pid = fork_job(user, mailFd, line, /*sendmail?*/ 1);
939#if ENABLE_PLATFORM_MINGW32
940 /* delay until here, when we have the mailFd closed again */
941 unlink(mailFile);
942#endif
839} 943}
840 944
841#else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ 945#else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */
@@ -845,6 +949,9 @@ static pid_t start_one_job(const char *user, CronLine *line)
845 const char *shell; 949 const char *shell;
846 struct passwd *pas; 950 struct passwd *pas;
847 pid_t pid; 951 pid_t pid;
952#if ENABLE_PLATFORM_MINGW32
953 char *args[4];
954#endif
848 955
849 pas = getpwnam(user); 956 pas = getpwnam(user);
850 if (!pas) { 957 if (!pas) {
@@ -856,6 +963,16 @@ static pid_t start_one_job(const char *user, CronLine *line)
856 shell = line->cl_shell ? line->cl_shell : G.default_shell; 963 shell = line->cl_shell ? line->cl_shell : G.default_shell;
857 set_env_vars(pas, shell, line->cl_path); 964 set_env_vars(pas, shell, line->cl_path);
858 965
966#if ENABLE_PLATFORM_MINGW32
967 args[0] = (char *)shell;
968 args[1] = (char *)"-c";
969 args[2] = line->cl_cmd;
970 args[3] = NULL;
971 pid = !(option_mask32 & OPT_f) ?
972 mingw_spawn_detach(args) : mingw_spawn(args);
973 if (pid < 0)
974 bb_error_msg("can't execute '%s' for user %s", shell, user);
975#else
859 /* Fork as the user in question and run program */ 976 /* Fork as the user in question and run program */
860 pid = vfork(); 977 pid = vfork();
861 if (pid == 0) { 978 if (pid == 0) {
@@ -868,6 +985,7 @@ static pid_t start_one_job(const char *user, CronLine *line)
868 execl(shell, shell, "-c", line->cl_cmd, (char *) NULL); 985 execl(shell, shell, "-c", line->cl_cmd, (char *) NULL);
869 bb_error_msg_and_die("can't execute '%s' for user %s", shell, user); 986 bb_error_msg_and_die("can't execute '%s' for user %s", shell, user);
870 } 987 }
988#endif
871 if (pid < 0) { 989 if (pid < 0) {
872 bb_simple_perror_msg("vfork"); 990 bb_simple_perror_msg("vfork");
873 err: 991 err:
@@ -956,8 +1074,14 @@ static void start_jobs(int wants_start)
956 continue; 1074 continue;
957 1075
958 pid = start_one_job(file->cf_username, line); 1076 pid = start_one_job(file->cf_username, line);
959 log8("USER %s pid %3d cmd %s", 1077#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_CROND_CALL_SENDMAIL
960 file->cf_username, (int)pid, line->cl_cmd); 1078 if (line->cl_mailto)
1079 log8("USER %s pid %3d tail %u cmd %s",
1080 file->cf_username, (int)pid, line->randomint, line->cl_cmd);
1081 else
1082#endif
1083 log8("USER %s pid %3d cmd %s",
1084 file->cf_username, (int)pid, line->cl_cmd);
961 if (pid < 0) { 1085 if (pid < 0) {
962 file->cf_wants_starting = 1; 1086 file->cf_wants_starting = 1;
963 } 1087 }
@@ -1025,6 +1149,29 @@ static void reopen_logfile_to_stderr(void)
1025 } 1149 }
1026} 1150}
1027 1151
1152#if ENABLE_PLATFORM_MINGW32
1153/* see similar function in networking/httpd.c */
1154static void mingw_daemonize(char **argv)
1155{
1156 char **new_argv;
1157 int fd;
1158
1159 new_argv = grow_argv(argv + 1, 3);
1160 new_argv[0] = (char *)bb_busybox_exec_path;
1161 new_argv[1] = (char *)"--busybox";
1162 // don't daemonise in main(), we explicitly detach below
1163 new_argv[2] = (char *)"-crond";
1164
1165 fd = xopen(bb_dev_null, O_RDWR);
1166 xdup2(fd, 0);
1167 xdup2(fd, 1);
1168 xdup2(fd, 2);
1169 close(fd);
1170
1171 exit(mingw_spawn_detach(new_argv) == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
1172}
1173#endif
1174
1028int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1175int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1029int crond_main(int argc UNUSED_PARAM, char **argv) 1176int crond_main(int argc UNUSED_PARAM, char **argv)
1030{ 1177{
@@ -1035,6 +1182,12 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
1035 1182
1036 INIT_G(); 1183 INIT_G();
1037 1184
1185#if ENABLE_PLATFORM_MINGW32
1186 /* crontab dirname should be different */
1187 G.crontab_dir_name = concat_path_file(get_system_drive(), CRONTABS);
1188 G.crondir_name = concat_path_file(get_system_drive(), CRON_DIR);
1189#endif
1190
1038 opts = getopt32(argv, "^" 1191 opts = getopt32(argv, "^"
1039 "l:L:fbSc:" IF_FEATURE_CROND_D("d:") 1192 "l:L:fbSc:" IF_FEATURE_CROND_D("d:")
1040 "\0" 1193 "\0"
@@ -1048,17 +1201,30 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
1048 ); 1201 );
1049 /* both -d N and -l N set the same variable: G.log_level */ 1202 /* both -d N and -l N set the same variable: G.log_level */
1050 1203
1204#if ENABLE_PLATFORM_MINGW32
1205 if (!(opts & OPT_d) && G.log_filename == NULL) {
1206 bb_error_msg_and_die("syslog isn't supported on Windows");
1207 }
1208#endif
1209
1051 if (!(opts & OPT_f)) { 1210 if (!(opts & OPT_f)) {
1052 /* close stdin, stdout, stderr. 1211 /* close stdin, stdout, stderr.
1053 * close unused descriptors - don't need them. */ 1212 * close unused descriptors - don't need them. */
1213#if ENABLE_PLATFORM_MINGW32
1214 if (argv[0][0] != '-')
1215 mingw_daemonize(argv);
1216#else
1054 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); 1217 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
1218#endif
1055 } 1219 }
1056 1220
1221#if !ENABLE_PLATFORM_MINGW32
1057 if (!(opts & OPT_d) && G.log_filename == NULL) { 1222 if (!(opts & OPT_d) && G.log_filename == NULL) {
1058 /* logging to syslog */ 1223 /* logging to syslog */
1059 openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); 1224 openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);
1060 logmode = LOGMODE_SYSLOG; 1225 logmode = LOGMODE_SYSLOG;
1061 } 1226 }
1227#endif
1062 1228
1063 //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ 1229 //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */
1064 1230
@@ -1069,6 +1235,9 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
1069 G.default_shell = xstrdup(get_shell_name()); 1235 G.default_shell = xstrdup(get_shell_name());
1070 1236
1071 log8("crond (busybox "BB_VER") started, log level %d", G.log_level); 1237 log8("crond (busybox "BB_VER") started, log level %d", G.log_level);
1238#if ENABLE_PLATFORM_MINGW32
1239 log5("crond pid %3d", getpid());
1240#endif
1072 rescan_crontab_dir(); 1241 rescan_crontab_dir();
1073 write_pidfile_std_path_and_ext("crond"); 1242 write_pidfile_std_path_and_ext("crond");
1074#if ENABLE_FEATURE_CROND_SPECIAL_TIMES 1243#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
diff --git a/miscutils/crontab.c b/miscutils/crontab.c
index 1111f4d54..e59b1e49b 100644
--- a/miscutils/crontab.c
+++ b/miscutils/crontab.c
@@ -44,6 +44,10 @@ static void edit_file(const struct passwd *pas, const char *file)
44{ 44{
45 const char *ptr; 45 const char *ptr;
46 pid_t pid; 46 pid_t pid;
47#if ENABLE_PLATFORM_MINGW32
48 char *args[3];
49 (void) pas;
50#else
47 51
48 pid = xvfork(); 52 pid = xvfork();
49 if (pid) { /* parent */ 53 if (pid) { /* parent */
@@ -57,6 +61,7 @@ static void edit_file(const struct passwd *pas, const char *file)
57 setup_environment(pas->pw_shell, 61 setup_environment(pas->pw_shell,
58 SETUP_ENV_CHANGEENV | SETUP_ENV_TO_TMP | SETUP_ENV_CHDIR, 62 SETUP_ENV_CHANGEENV | SETUP_ENV_TO_TMP | SETUP_ENV_CHDIR,
59 pas); 63 pas);
64#endif
60 ptr = getenv("VISUAL"); 65 ptr = getenv("VISUAL");
61 if (!ptr) { 66 if (!ptr) {
62 ptr = getenv("EDITOR"); 67 ptr = getenv("EDITOR");
@@ -64,7 +69,18 @@ static void edit_file(const struct passwd *pas, const char *file)
64 ptr = "vi"; 69 ptr = "vi";
65 } 70 }
66 71
72#if !ENABLE_PLATFORM_MINGW32
67 BB_EXECLP(ptr, ptr, file, NULL); 73 BB_EXECLP(ptr, ptr, file, NULL);
74#else
75 args[0] = (char *)ptr;
76 args[1] = (char *)file;
77 args[2] = NULL;
78 pid = mingw_spawn(args);
79 if (pid == -1)
80 bb_perror_msg_and_die("can't execute '%s'", ptr);
81 wait4pid(pid);
82 return;
83#endif
68 bb_perror_msg_and_die("can't execute '%s'", ptr); 84 bb_perror_msg_and_die("can't execute '%s'", ptr);
69} 85}
70 86
@@ -99,16 +115,22 @@ int crontab_main(int argc UNUSED_PARAM, char **argv)
99 OPT_ler = OPT_l + OPT_e + OPT_r, 115 OPT_ler = OPT_l + OPT_e + OPT_r,
100 }; 116 };
101 117
118#if ENABLE_PLATFORM_MINGW32
119 crontab_dir = concat_path_file(get_system_drive(), CRONTABS);
120#endif
121
102 opt_ler = getopt32(argv, "^" "u:c:lerd" "\0" "?1:dr"/*max one arg; -d implies -r*/, 122 opt_ler = getopt32(argv, "^" "u:c:lerd" "\0" "?1:dr"/*max one arg; -d implies -r*/,
103 &user_name, &crontab_dir 123 &user_name, &crontab_dir
104 ); 124 );
105 argv += optind; 125 argv += optind;
106 126
127#if !ENABLE_PLATFORM_MINGW32
107 if (sanitize_env_if_suid()) { /* Clears dangerous stuff, sets PATH */ 128 if (sanitize_env_if_suid()) { /* Clears dangerous stuff, sets PATH */
108 /* Run by non-root */ 129 /* Run by non-root */
109 if (opt_ler & (OPT_u|OPT_c)) 130 if (opt_ler & (OPT_u|OPT_c))
110 bb_simple_error_msg_and_die(bb_msg_you_must_be_root); 131 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
111 } 132 }
133#endif
112 134
113 if (opt_ler & OPT_u) { 135 if (opt_ler & OPT_u) {
114 pas = xgetpwnam(user_name); 136 pas = xgetpwnam(user_name);
@@ -184,8 +206,13 @@ int crontab_main(int argc UNUSED_PARAM, char **argv)
184 bb_error_msg("can't create %s/%s", 206 bb_error_msg("can't create %s/%s",
185 crontab_dir, new_fname); 207 crontab_dir, new_fname);
186 } 208 }
187 if (tmp_fname) 209 if (tmp_fname) {
210#if ENABLE_PLATFORM_MINGW32
211 /* can't delete open files on Windows */
212 close(src_fd);
213#endif
188 unlink(tmp_fname); 214 unlink(tmp_fname);
215 }
189 /*free(tmp_fname);*/ 216 /*free(tmp_fname);*/
190 /*free(new_fname);*/ 217 /*free(new_fname);*/
191 } /* switch */ 218 } /* switch */