Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/miscutils/crond.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/miscutils/crond.c
r3232 r3621 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * crond -d[#] -c <crondir> -f -b4 *5 3 * run as root, but NOT setuid root 6 4 * … … 11 9 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 12 10 */ 11 //config:config CROND 12 //config: bool "crond" 13 //config: default y 14 //config: select FEATURE_SYSLOG 15 //config: help 16 //config: Crond is a background daemon that parses individual crontab 17 //config: files and executes commands on behalf of the users in question. 18 //config: This is a port of dcron from slackware. It uses files of the 19 //config: format /var/spool/cron/crontabs/<username> files, for example: 20 //config: $ cat /var/spool/cron/crontabs/root 21 //config: # Run daily cron jobs at 4:40 every day: 22 //config: 40 4 * * * /etc/cron/daily > /dev/null 2>&1 23 //config: 24 //config:config FEATURE_CROND_D 25 //config: bool "Support option -d to redirect output to stderr" 26 //config: depends on CROND 27 //config: default y 28 //config: help 29 //config: -d N sets loglevel (0:most verbose) and directs all output to stderr. 30 //config: 31 //config:config FEATURE_CROND_CALL_SENDMAIL 32 //config: bool "Report command output via email (using sendmail)" 33 //config: default y 34 //config: depends on CROND 35 //config: help 36 //config: Command output will be sent to corresponding user via email. 37 //config: 38 //config:config FEATURE_CROND_DIR 39 //config: string "crond spool directory" 40 //config: default "/var/spool/cron" 41 //config: depends on CROND || CRONTAB 42 //config: help 43 //config: Location of crond spool. 44 45 //applet:IF_CROND(APPLET(crond, BB_DIR_USR_SBIN, BB_SUID_DROP)) 46 47 //kbuild:lib-$(CONFIG_CROND) += crond.o 13 48 14 49 //usage:#define crond_trivial_usage … … 18 53 //usage: "\n -b Background (default)" 19 54 //usage: "\n -S Log to syslog (default)" 20 //usage: "\n -l Set log level. 0 is the most verbose, default8"55 //usage: "\n -l N Set log level. Most verbose:0, default:8" 21 56 //usage: IF_FEATURE_CROND_D( 22 //usage: "\n -d Set log level, log to stderr"57 //usage: "\n -d N Set log level, log to stderr" 23 58 //usage: ) 24 //usage: "\n -L Log to file"25 //usage: "\n -c Working dir"59 //usage: "\n -L FILE Log to FILE" 60 //usage: "\n -c DIR Cron dir. Default:"CONFIG_FEATURE_CROND_DIR"/crontabs" 26 61 27 62 #include "libbb.h" 63 #include "common_bufsiz.h" 28 64 #include <syslog.h> 29 65 … … 37 73 38 74 39 #define TMPDIRCONFIG_FEATURE_CROND_DIR75 #define CRON_DIR CONFIG_FEATURE_CROND_DIR 40 76 #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" 41 77 #ifndef SENDMAIL … … 70 106 char *cl_mailto; /* whom to mail results, may be NULL */ 71 107 #endif 108 char *cl_shell; 72 109 /* ordered by size, not in natural order. makes code smaller: */ 73 110 char cl_Dow[7]; /* 0-6, beginning sunday */ … … 91 128 OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D, 92 129 }; 93 #if ENABLE_FEATURE_CROND_D94 # define DebugOpt (option_mask32 & OPT_d)95 #else96 # define DebugOpt 097 #endif98 99 130 100 131 struct globals { … … 107 138 char *env_var_user; 108 139 char *env_var_home; 140 char *env_var_shell; 141 char *env_var_logname; 109 142 #endif 110 143 } FIX_ALIASING; 111 #define G (*(struct globals*) &bb_common_bufsiz1)144 #define G (*(struct globals*)bb_common_bufsiz1) 112 145 #define INIT_G() do { \ 146 setup_common_bufsiz(); \ 113 147 G.log_level = 8; \ 114 148 G.crontab_dir_name = CRONTABS; \ 115 149 } while (0) 116 150 117 118 /* 0 is the most verbose, default 8 */ 119 #define LVL5 "\x05" 120 #define LVL7 "\x07" 121 #define LVL8 "\x08" 122 #define WARN9 "\x49" 123 #define DIE9 "\xc9" 124 /* level >= 20 is "error" */ 125 #define ERR20 "\x14" 126 127 static void crondlog(const char *ctl, ...) __attribute__ ((format (printf, 1, 2))); 128 static void crondlog(const char *ctl, ...) 151 /* Log levels: 152 * 0 is the most verbose, default 8. 153 * For some reason, in fact only 5, 7 and 8 are used. 154 */ 155 static void crondlog(unsigned level, const char *msg, va_list va) 156 { 157 if (level >= G.log_level) { 158 /* 159 * We are called only for info meesages. 160 * Warnings/errors use plain bb_[p]error_msg's, which 161 * need not touch syslog_level 162 * (they are ok with LOG_ERR default). 163 */ 164 syslog_level = LOG_INFO; 165 bb_verror_msg(msg, va, /* strerr: */ NULL); 166 syslog_level = LOG_ERR; 167 } 168 } 169 170 static void log5(const char *msg, ...) 129 171 { 130 172 va_list va; 131 int level = (ctl[0] & 0x1f); 132 133 va_start(va, ctl); 134 if (level >= (int)G.log_level) { 135 /* Debug mode: all to (non-redirected) stderr, */ 136 /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ 137 if (!DebugOpt && G.log_filename) { 138 /* Otherwise (log to file): we reopen log file at every write: */ 139 int logfd = open_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND); 140 if (logfd >= 0) 141 xmove_fd(logfd, STDERR_FILENO); 142 } 143 /* When we log to syslog, level > 8 is logged at LOG_ERR 144 * syslog level, level <= 8 is logged at LOG_INFO. */ 145 if (level > 8) { 146 bb_verror_msg(ctl + 1, va, /* strerr: */ NULL); 147 } else { 148 char *msg = NULL; 149 vasprintf(&msg, ctl + 1, va); 150 bb_info_msg("%s: %s", applet_name, msg); 151 free(msg); 152 } 153 } 173 va_start(va, msg); 174 crondlog(4, msg, va); 154 175 va_end(va); 155 if (ctl[0] & 0x80) 156 exit(20); 157 } 176 } 177 178 static void log7(const char *msg, ...) 179 { 180 va_list va; 181 va_start(va, msg); 182 crondlog(7, msg, va); 183 va_end(va); 184 } 185 186 static void log8(const char *msg, ...) 187 { 188 va_list va; 189 va_start(va, msg); 190 crondlog(8, msg, va); 191 va_end(va); 192 } 193 158 194 159 195 static const char DowAry[] ALIGN1 = 160 196 "sun""mon""tue""wed""thu""fri""sat" 161 /* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */162 197 ; 163 198 164 199 static const char MonAry[] ALIGN1 = 165 200 "jan""feb""mar""apr""may""jun""jul""aug""sep""oct""nov""dec" 166 /* "Jan""Feb""Mar""Apr""May""Jun""Jul""Aug""Sep""Oct""Nov""Dec" */167 201 ; 168 202 … … 268 302 if (*ptr) { 269 303 err: 270 crondlog(WARN9"user %s: parse error at %s", user, base);304 bb_error_msg("user %s: parse error at %s", user, base); 271 305 return; 272 306 } 273 307 274 if (DebugOpt && (G.log_level <= 5)) { /* like LVL5*/275 /* can't use crondlog, it inserts '\n' */308 /* can't use log5 (it inserts newlines), open-coding it */ 309 if (G.log_level <= 5 && logmode != LOGMODE_SYSLOG) { 276 310 int i; 277 311 for (i = 0; i < modvalue; ++i) … … 369 403 char *mailTo = NULL; 370 404 #endif 405 char *shell = NULL; 371 406 372 407 delete_cronfile(fileName); 373 408 374 409 if (!getpwnam(fileName)) { 375 crondlog(LVL7"ignoring file '%s' (no such user)", fileName);410 log7("ignoring file '%s' (no such user)", fileName); 376 411 return; 377 412 } … … 394 429 CronLine *line; 395 430 396 if (!--maxLines) 431 if (!--maxLines) { 432 bb_error_msg("user %s: too many lines", fileName); 397 433 break; 434 } 435 398 436 n = config_read(parser, tokens, 6, 1, "# \t", PARSE_NORMAL | PARSE_KEEP_COPY); 399 437 if (!n) 400 438 break; 401 439 402 if (DebugOpt) 403 crondlog(LVL5 "user:%s entry:%s", fileName, parser->data); 440 log5("user:%s entry:%s", fileName, parser->data); 404 441 405 442 /* check if line is setting MAILTO= */ 406 if ( 0 == strncmp(tokens[0], "MAILTO=", 7)) {443 if (is_prefixed_with(tokens[0], "MAILTO=")) { 407 444 #if ENABLE_FEATURE_CROND_CALL_SENDMAIL 408 445 free(mailTo); … … 411 448 continue; 412 449 } 450 if (is_prefixed_with(tokens[0], "SHELL=")) { 451 free(shell); 452 shell = xstrdup(&tokens[0][6]); 453 continue; 454 } 455 //TODO: handle HOME= too? "man crontab" says: 456 //name = value 457 // 458 //where the spaces around the equal-sign (=) are optional, and any subsequent 459 //non-leading spaces in value will be part of the value assigned to name. 460 //The value string may be placed in quotes (single or double, but matching) 461 //to preserve leading or trailing blanks. 462 // 463 //Several environment variables are set up automatically by the cron(8) daemon. 464 //SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd 465 //line of the crontab's owner. HOME and SHELL may be overridden by settings 466 //in the crontab; LOGNAME may not. 467 413 468 /* check if a minimum of tokens is specified */ 414 469 if (n < 6) … … 430 485 line->cl_mailto = xstrdup(mailTo); 431 486 #endif 487 line->cl_shell = xstrdup(shell); 432 488 /* copy command */ 433 489 line->cl_cmd = xstrdup(tokens[5]); 434 if (DebugOpt) {435 crondlog(LVL5 " command:%s", tokens[5]);436 }437 490 pline = &line->cl_next; 438 491 //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]); … … 442 495 file->cf_next = G.cron_files; 443 496 G.cron_files = file; 444 445 if (maxLines == 0) {446 crondlog(WARN9 "user %s: too many lines", fileName);447 }448 497 } 449 498 config_close(parser); 499 #if ENABLE_FEATURE_CROND_CALL_SENDMAIL 500 free(mailTo); 501 #endif 502 free(shell); 450 503 } 451 504 … … 483 536 unlink(CRONUPDATE); 484 537 /* Re-chdir, in case directory was renamed & deleted */ 485 if (chdir(G.crontab_dir_name) < 0) { 486 crondlog(DIE9 "chdir(%s)", G.crontab_dir_name); 487 } 538 xchdir(G.crontab_dir_name); 488 539 489 540 /* Scan directory and add associated users */ … … 492 543 struct dirent *den; 493 544 545 /* xopendir exists, but "can't open '.'" is not informative */ 494 546 if (!dir) 495 crondlog(DIE9 "chdir(%s)", "."); /* exits */547 bb_error_msg_and_die("can't open '%s'", G.crontab_dir_name); 496 548 while ((den = readdir(dir)) != NULL) { 497 549 if (strchr(den->d_name, '.') != NULL) { … … 520 572 #endif 521 573 522 static void set_env_vars(struct passwd *pas) 523 { 574 static void set_env_vars(struct passwd *pas, const char *shell) 575 { 576 /* POSIX requires crond to set up at least HOME, LOGNAME, PATH, SHELL. 577 * We assume crond inherited suitable PATH. 578 */ 524 579 #if SETENV_LEAKS 580 safe_setenv(&G.env_var_logname, "LOGNAME", pas->pw_name); 525 581 safe_setenv(&G.env_var_user, "USER", pas->pw_name); 526 582 safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); 527 /* if we want to set user's shell instead: */ 528 /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ 583 safe_setenv(&G.env_var_shell, "SHELL", shell); 529 584 #else 585 xsetenv("LOGNAME", pas->pw_name); 530 586 xsetenv("USER", pas->pw_name); 531 587 xsetenv("HOME", pas->pw_dir); 532 #endif 533 /* currently, we use constant one: */ 534 /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ 588 xsetenv("SHELL", shell); 589 #endif 535 590 } 536 591 … … 540 595 change_identity(pas); /* - initgroups, setgid, setuid */ 541 596 if (chdir(pas->pw_dir) < 0) { 542 crondlog(WARN9 "chdir(%s)", pas->pw_dir); 543 if (chdir(TMPDIR) < 0) { 544 crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */ 545 } 597 bb_error_msg("can't change directory to '%s'", pas->pw_dir); 598 xchdir(CRON_DIR); 546 599 } 547 600 } … … 551 604 552 605 static pid_t 553 fork_job(const char *user, int mailFd, 554 const char *prog, 555 const char *shell_cmd /* if NULL, we run sendmail */ 556 ) { 606 fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail) 607 { 557 608 struct passwd *pas; 609 const char *shell, *prog; 610 smallint sv_logmode; 558 611 pid_t pid; 559 612 … … 561 614 pas = getpwnam(user); 562 615 if (!pas) { 563 crondlog(WARN9"can't get uid for %s", user);616 bb_error_msg("can't get uid for %s", user); 564 617 goto err; 565 618 } 566 set_env_vars(pas); 567 619 620 shell = line->cl_shell ? line->cl_shell : DEFAULT_SHELL; 621 prog = run_sendmail ? SENDMAIL : shell; 622 623 set_env_vars(pas, shell); 624 625 sv_logmode = logmode; 568 626 pid = vfork(); 569 627 if (pid == 0) { 570 628 /* CHILD */ 571 /* initgroups, setgid, setuid, and chdir to home or TMPDIR */629 /* initgroups, setgid, setuid, and chdir to home or CRON_DIR */ 572 630 change_user(pas); 573 if (DebugOpt) { 574 crondlog(LVL5 "child running %s", prog); 575 } 631 log5("child running %s", prog); 576 632 if (mailFd >= 0) { 577 xmove_fd(mailFd, shell_cmd ? 1 : 0);633 xmove_fd(mailFd, run_sendmail ? 0 : 1); 578 634 dup2(1, 2); 579 635 } 580 636 /* crond 3.0pl1-100 puts tasks in separate process groups */ 581 637 bb_setpgrp(); 582 execlp(prog, prog, (shell_cmd ? "-c" : SENDMAIL_ARGS), shell_cmd, (char *) NULL); 583 crondlog(ERR20 "can't execute '%s' for user %s", prog, user); 584 if (shell_cmd) { 585 fdprintf(1, "Exec failed: %s -c %s\n", prog, shell_cmd); 586 } 587 _exit(EXIT_SUCCESS); 588 } 638 if (!run_sendmail) 639 execlp(prog, prog, "-c", line->cl_cmd, (char *) NULL); 640 else 641 execlp(prog, prog, SENDMAIL_ARGS, (char *) NULL); 642 /* 643 * I want this error message on stderr too, 644 * even if other messages go only to syslog: 645 */ 646 logmode |= LOGMODE_STDIO; 647 bb_error_msg_and_die("can't execute '%s' for user %s", prog, user); 648 } 649 logmode = sv_logmode; 589 650 590 651 if (pid < 0) { 591 /* FORK FAILED */ 592 crondlog(ERR20 "can't vfork"); 652 bb_perror_msg("vfork"); 593 653 err: 594 654 pid = 0; … … 615 675 if (line->cl_mailto) { 616 676 /* Open mail file (owner is root so nobody can screw with it) */ 617 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid());677 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", CRON_DIR, user, getpid()); 618 678 mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); 619 679 … … 623 683 line->cl_empty_mail_size = lseek(mailFd, 0, SEEK_CUR); 624 684 } else { 625 crondlog(ERR20"can't create mail file %s for user %s, "685 bb_error_msg("can't create mail file %s for user %s, " 626 686 "discarding output", mailFile, user); 627 687 } 628 688 } 629 689 630 line->cl_pid = fork_job(user, mailFd, DEFAULT_SHELL, line->cl_cmd);690 line->cl_pid = fork_job(user, mailFd, line, /*sendmail?*/ 0); 631 691 if (mailFd >= 0) { 632 692 if (line->cl_pid <= 0) { … … 634 694 } else { 635 695 /* rename mail-file based on pid of process */ 636 char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)line->cl_pid);696 char *mailFile2 = xasprintf("%s/cron.%s.%d", CRON_DIR, user, (int)line->cl_pid); 637 697 rename(mailFile, mailFile2); // TODO: xrename? 638 698 free(mailFile2); … … 666 726 * If size has changed and the file is still valid, we send it. 667 727 */ 668 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, (int)pid);728 snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", CRON_DIR, user, (int)pid); 669 729 mailFd = open(mailFile, O_RDONLY); 670 730 unlink(mailFile); … … 684 744 line->cl_empty_mail_size = 0; 685 745 /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */ 686 line->cl_pid = fork_job(user, mailFd, SENDMAIL, NULL);746 line->cl_pid = fork_job(user, mailFd, line, /*sendmail?*/ 1); 687 747 } 688 748 … … 691 751 static void start_one_job(const char *user, CronLine *line) 692 752 { 753 const char *shell; 693 754 struct passwd *pas; 694 755 pid_t pid; … … 696 757 pas = getpwnam(user); 697 758 if (!pas) { 698 crondlog(WARN9"can't get uid for %s", user);759 bb_error_msg("can't get uid for %s", user); 699 760 goto err; 700 761 } 701 762 702 763 /* Prepare things before vfork */ 703 set_env_vars(pas); 764 shell = line->cl_shell ? line->cl_shell : DEFAULT_SHELL; 765 set_env_vars(pas, shell); 704 766 705 767 /* Fork as the user in question and run program */ … … 707 769 if (pid == 0) { 708 770 /* CHILD */ 709 /* initgroups, setgid, setuid, and chdir to home or TMPDIR */771 /* initgroups, setgid, setuid, and chdir to home or CRON_DIR */ 710 772 change_user(pas); 711 if (DebugOpt) { 712 crondlog(LVL5 "child running %s", DEFAULT_SHELL); 713 } 773 log5("child running %s", shell); 714 774 /* crond 3.0pl1-100 puts tasks in separate process groups */ 715 775 bb_setpgrp(); 716 execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_cmd, (char *) NULL); 717 crondlog(ERR20 "can't execute '%s' for user %s", DEFAULT_SHELL, user); 718 _exit(EXIT_SUCCESS); 776 execl(shell, shell, "-c", line->cl_cmd, (char *) NULL); 777 bb_error_msg_and_die("can't execute '%s' for user %s", shell, user); 719 778 } 720 779 if (pid < 0) { 721 /* FORK FAILED */ 722 crondlog(ERR20 "can't vfork"); 780 bb_perror_msg("vfork"); 723 781 err: 724 782 pid = 0; … … 752 810 ptm = localtime(&t); 753 811 for (file = G.cron_files; file; file = file->cf_next) { 754 if (DebugOpt) 755 crondlog(LVL5 "file %s:", file->cf_username); 812 log5("file %s:", file->cf_username); 756 813 if (file->cf_deleted) 757 814 continue; 758 815 for (line = file->cf_lines; line; line = line->cl_next) { 759 if (DebugOpt) 760 crondlog(LVL5 " line %s", line->cl_cmd); 816 log5(" line %s", line->cl_cmd); 761 817 if (line->cl_Mins[ptm->tm_min] 762 818 && line->cl_Hrs[ptm->tm_hour] … … 764 820 && line->cl_Mons[ptm->tm_mon] 765 821 ) { 766 if (DebugOpt) { 767 crondlog(LVL5 " job: %d %s", 822 log5(" job: %d %s", 768 823 (int)line->cl_pid, line->cl_cmd); 769 }770 824 if (line->cl_pid > 0) { 771 crondlog(LVL8"user %s: process already running: %s",825 log8("user %s: process already running: %s", 772 826 file->cf_username, line->cl_cmd); 773 827 } else if (line->cl_pid == 0) { … … 798 852 start_one_job(file->cf_username, line); 799 853 pid = line->cl_pid; 800 crondlog(LVL8"USER %s pid %3d cmd %s",854 log8("USER %s pid %3d cmd %s", 801 855 file->cf_username, (int)pid, line->cl_cmd); 802 856 if (pid < 0) { … … 850 904 } 851 905 906 static void reopen_logfile_to_stderr(void) 907 { 908 if (G.log_filename) { 909 int logfd = open_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND); 910 if (logfd >= 0) 911 xmove_fd(logfd, STDERR_FILENO); 912 } 913 } 914 852 915 int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 853 916 int crond_main(int argc UNUSED_PARAM, char **argv) 854 917 { 855 918 time_t t2; 856 intrescan;857 intsleep_time;919 unsigned rescan; 920 unsigned sleep_time; 858 921 unsigned opts; 859 922 … … 881 944 } 882 945 946 //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ 947 948 reopen_logfile_to_stderr(); 883 949 xchdir(G.crontab_dir_name); 884 //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ 885 xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ 886 crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.log_level); 950 log8("crond (busybox "BB_VER") started, log level %d", G.log_level); 887 951 rescan_crontab_dir(); 888 952 write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); … … 897 961 long dt; 898 962 963 /* Synchronize to 1 minute, minimum 1 second */ 899 964 t1 = t2; 900 901 /* Synchronize to 1 minute, minimum 1 second */ 902 sleep(sleep_time - (time(NULL) % sleep_time) + 1); 903 965 sleep(sleep_time - (time(NULL) % sleep_time)); 904 966 t2 = time(NULL); 905 967 dt = (long)t2 - (long)t1; 968 969 reopen_logfile_to_stderr(); 906 970 907 971 /* … … 932 996 } 933 997 process_cron_update_file(); 934 if (DebugOpt) 935 crondlog(LVL5 "wakeup dt=%ld", dt); 998 log5("wakeup dt=%ld", dt); 936 999 if (dt < -60 * 60 || dt > 60 * 60) { 937 crondlog(WARN9"time disparity of %ld minutes detected", dt / 60);1000 bb_error_msg("time disparity of %ld minutes detected", dt / 60); 938 1001 /* and we do not run any jobs in this case */ 939 1002 } else if (dt > 0) { … … 941 1004 flag_starting_jobs(t1, t2); 942 1005 start_jobs(); 1006 sleep_time = 60; 943 1007 if (check_completions() > 0) { 944 1008 /* some jobs are still running */ 945 1009 sleep_time = 10; 946 } else {947 sleep_time = 60;948 1010 } 949 1011 }
Note:
See TracChangeset
for help on using the changeset viewer.