"Fossies" - the Fresh Open Source Software Archive

Member "anacron-2.5.3/main.c" (9 Dec 2007, 10390 Bytes) of package /linux/misc/old/anacron.2.5.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     Anacron - run commands periodically
    3     Copyright (C) 1998  Itai Tzur <itzur@actcom.co.il>
    4     Copyright (C) 1999  Sean 'Shaleh' Perry <shaleh@debian.org>
    5  
    6     This program is free software; you can redistribute it and/or modify
    7     it under the terms of the GNU General Public License as published by
    8     the Free Software Foundation; either version 2 of the License, or
    9     (at your option) any later version.
   10  
   11     This program is distributed in the hope that it will be useful,
   12     but WITHOUT ANY WARRANTY; without even the implied warranty of
   13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14     GNU General Public License for more details.
   15  
   16     You should have received a copy of the GNU General Public License
   17     along with this program; if not, write to the Free Software
   18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   19  
   20     The GNU General Public License can also be found in the file
   21     `COPYING' that comes with the Anacron source distribution.
   22 */
   23 
   24 
   25 #include <time.h>
   26 #include <stdio.h>
   27 #include <unistd.h>
   28 #include <signal.h>
   29 #include <fcntl.h>
   30 #include <sys/types.h>
   31 #include <sys/stat.h>
   32 #include <string.h>
   33 #include "global.h"
   34 #include "gregor.h"
   35 
   36 pid_t primary_pid;
   37 int day_now;
   38 int year, month, day_of_month;                 /* date anacron started */
   39 
   40 char *program_name;
   41 char *anacrontab;
   42 int serialize, force, update_only, now,
   43     no_daemon, quiet;                            /* command-line options */
   44 char **args;                       /* vector of "job" command-line arguments */
   45 int nargs;                                     /* number of these */
   46 char *defarg = "*";
   47 int in_background;                             /* are we in the background? */
   48 int old_umask;                                 /* umask when started */
   49 sigset_t old_sigmask;                          /* signal mask when started */
   50 
   51 job_rec *first_job_rec;
   52 env_rec *first_env_rec;
   53 
   54 static time_t start_sec;                       /* time anacron started */
   55 static volatile int got_sigalrm, got_sigchld, got_sigusr1;
   56 int running_jobs, running_mailers;              /* , number of */
   57 
   58 static void
   59 print_version()
   60 {
   61     printf("Anacron " RELEASE "\n"
   62        "Copyright (C) 1998  Itai Tzur <itzur@actcom.co.il>\n"
   63        "Copyright (C) 1999  Sean 'Shaleh' Perry <shaleh@debian.org>\n"
   64        "\n"
   65        "Mail comments, suggestions and bug reports to <shaleh@debian.org>."
   66        "\n\n");
   67 }
   68 
   69 static void
   70 print_usage()
   71 {
   72     printf("Usage:  anacron [-s] [-f] [-n] [-d] [-q] [-t anacrontab] [job] ...\n"
   73        "        anacron -u [job] ...\n"
   74        "        anacron [-V|-h]\n"
   75        "\n"
   76        " -s  Serialize execution of jobs\n"
   77        " -f  Force execution of jobs, even before their time\n"
   78        " -n  Run jobs with no delay, implies -s\n"
   79        " -d  Don't fork to the background\n"
   80        " -q  Suppress stderr messages, only applicable with -d\n"
   81        " -u  Update the timestamps without actually running anything\n"
   82        " -t  Use this anacrontab\n"
   83        " -V  Print version information\n"
   84        " -h  Print this message\n"
   85        "\n"
   86        "See the manpage for more details.\n"
   87        "\n");
   88 }
   89 
   90 static void
   91 parse_opts(int argc, char *argv[])
   92 /* Parse command-line options */
   93 {
   94     int opt;
   95 
   96     quiet = no_daemon = serialize = force = update_only = now = 0;
   97     opterr = 0;
   98     while ((opt = getopt(argc, argv, "sfundqt:Vh")) != EOF)
   99     {
  100     switch (opt)
  101     {
  102     case 's':
  103         serialize = 1;
  104         break;
  105     case 'f':
  106         force = 1;
  107         break;
  108     case 'u':
  109         update_only = 1;
  110         break;
  111     case 'n':
  112         now = serialize = 1;
  113         break;
  114     case 'd':
  115         no_daemon = 1;
  116         break;
  117     case 'q':
  118         quiet = 1;
  119         break;
  120     case 't':
  121         anacrontab = strdup(optarg);
  122         break;
  123     case 'V':
  124         print_version();
  125         exit(0);
  126     case 'h':
  127         print_usage();
  128         exit(0);
  129     case '?':
  130         fprintf(stderr, "%s: invalid option: %c\n",
  131             program_name, optopt);
  132         fprintf(stderr, "type: `%s -h' for more information\n",
  133             program_name);
  134         exit(FAILURE_EXIT);
  135     }
  136     }
  137     if (optind == argc)
  138     {
  139     /* no arguments. Equivalent to: `*' */
  140     nargs = 1;
  141     args = &defarg;
  142     }
  143     else
  144     {
  145     nargs = argc - optind;
  146     args = argv + optind;
  147     }
  148 }
  149 
  150 pid_t
  151 xfork()
  152 /* Like fork(), only never returns on failure */
  153 {
  154     pid_t pid;
  155 
  156     pid = fork();
  157     if (pid == -1) die_e("Can't fork");
  158     return pid;
  159 }
  160 
  161 int
  162 xopen(int fd, const char *file_name, int flags)
  163 /* Like open, only it:
  164  * a) never returns on failure, and
  165  * b) if "fd" is non-negative, expect the file to open
  166  *    on file-descriptor "fd".
  167  */
  168 {
  169     int rfd;
  170 
  171     rfd = open(file_name, flags);
  172     if (fd >= 0 && rfd != fd)
  173     die_e("Can't open %s on file-descriptor %d", file_name, fd);
  174     else if (rfd < 0)
  175     die_e("Can't open %s", file_name);
  176     return rfd;
  177 }
  178 
  179 void
  180 xclose(int fd)
  181 /* Like close(), only doesn't return on failure */
  182 {
  183     if (close(fd)) die_e("Can't close file descriptor %d", fd);
  184 }
  185 
  186 static void
  187 go_background()
  188 /* Become a daemon. The foreground process exits successfully. */
  189 {
  190     pid_t pid;
  191 
  192     /* stdin is already closed */
  193 
  194     if (fclose(stdout)) die_e("Can't close stdout");
  195     xopen(1, "/dev/null", O_WRONLY);
  196 
  197     if (fclose(stderr)) die_e("Can't close stderr");
  198     xopen(2, "/dev/null", O_WRONLY);
  199 
  200     pid = xfork();
  201     if (pid != 0)
  202     {
  203     /* parent */
  204     exit(0);
  205     }
  206     else
  207     {
  208     /* child */
  209     primary_pid = getpid();
  210     if (setsid() == -1) die_e("setsid() error");
  211     in_background = 1;
  212     }
  213 }
  214 
  215 void
  216 handle_sigalrm()
  217 {
  218     got_sigalrm = 1;
  219 }
  220 
  221 void
  222 handle_sigchld()
  223 {
  224     got_sigchld = 1;
  225 }
  226 
  227 void
  228 handle_sigusr1()
  229 {
  230     got_sigusr1 = 1;
  231 }
  232 
  233 static void
  234 set_signal_handling()
  235 /* We only use SIGALRM, SIGCHLD and SIGUSR1, and we unblock them only
  236  * in wait_signal().
  237  */
  238 {
  239     sigset_t ss;
  240     struct sigaction sa;
  241 
  242     got_sigalrm = got_sigchld = got_sigusr1 = 0;
  243 
  244     /* block SIGALRM, SIGCHLD and SIGUSR1 */
  245     if (sigemptyset(&ss) ||
  246     sigaddset(&ss, SIGALRM) ||
  247     sigaddset(&ss, SIGCHLD) ||
  248     sigaddset(&ss, SIGUSR1)) die_e("sigset error");
  249     if (sigprocmask(SIG_BLOCK, &ss, NULL)) die_e ("sigprocmask error");
  250 
  251     /* setup SIGALRM handler */
  252     sa.sa_handler = handle_sigalrm;
  253     sa.sa_mask = ss;
  254     sa.sa_flags = 0;
  255     if (sigaction(SIGALRM, &sa, NULL)) die_e("sigaction error");
  256 
  257     /* setup SIGCHLD handler */
  258     sa.sa_handler = handle_sigchld;
  259     sa.sa_mask = ss;
  260     sa.sa_flags = SA_NOCLDSTOP;
  261     if (sigaction(SIGCHLD, &sa, NULL)) die_e("sigaction error");
  262 
  263     /* setup SIGUSR1 handler */
  264     sa.sa_handler = handle_sigusr1;
  265     sa.sa_mask = ss;
  266     sa.sa_flags = 0;
  267     if (sigaction(SIGUSR1, &sa, NULL)) die_e("sigaction error");
  268 }
  269 
  270 static void
  271 wait_signal()
  272 /* Return after a signal is caught */
  273 {
  274     sigset_t ss;
  275 
  276     if (sigprocmask(0, NULL, &ss)) die_e("sigprocmask error");
  277     if (sigdelset(&ss, SIGALRM) ||
  278     sigdelset(&ss, SIGCHLD) ||
  279     sigdelset(&ss, SIGUSR1)) die_e("sigset error");
  280     sigsuspend(&ss);
  281 }
  282 
  283 static void
  284 wait_children()
  285 /* Wait until we have no more children (of any kind) */
  286 {
  287     while (running_jobs > 0 || running_mailers > 0)
  288     {
  289     wait_signal();
  290     if (got_sigchld) tend_children();
  291     got_sigchld = 0;
  292     if (got_sigusr1) explain("Received SIGUSR1");
  293     got_sigusr1 = 0;
  294     }
  295 }
  296 
  297 static void
  298 orderly_termination()
  299 /* Execution is diverted here, when we get SIGUSR1 */
  300 {
  301     explain("Received SIGUSR1");
  302     got_sigusr1 = 0;
  303     wait_children();
  304     explain("Exited");
  305     exit(0);
  306 }
  307 
  308 static void
  309 xsleep(unsigned int n)
  310 /* Sleep for n seconds, servicing SIGCHLDs and SIGUSR1s in the meantime.
  311  * If n=0, return immediately.
  312  */
  313 {
  314     if (n == 0) return;
  315     alarm(n);
  316     do
  317     {
  318     wait_signal();
  319     if (got_sigchld) tend_children();
  320     got_sigchld = 0;
  321     if (got_sigusr1) orderly_termination();
  322     }
  323     while (!got_sigalrm);
  324     got_sigalrm = 0;
  325 }
  326 
  327 static void
  328 wait_jobs()
  329 /* Wait until there are no running jobs,
  330  * servicing SIGCHLDs and SIGUSR1s in the meantime.
  331  */
  332 {
  333     while (running_jobs > 0)
  334     {
  335     wait_signal();
  336     if (got_sigchld) tend_children();
  337     got_sigchld = 0;
  338     if (got_sigusr1) orderly_termination();
  339     }
  340 }
  341 
  342 static void
  343 record_start_time()
  344 {
  345     struct tm *tm_now;
  346 
  347     start_sec = time(NULL);
  348     tm_now = localtime(&start_sec);
  349     year = tm_now->tm_year + 1900;
  350     month = tm_now->tm_mon + 1;
  351     day_of_month = tm_now->tm_mday;
  352     day_now = day_num(year, month, day_of_month);
  353     if (day_now == -1) die("Invalid date (this is really embarrassing)");
  354     if (!update_only)
  355     explain("Anacron " RELEASE " started on %04d-%02d-%02d",
  356         year, month, day_of_month);
  357 }
  358 
  359 static int
  360 time_till(job_rec *jr)
  361 /* Return the number of seconds that we have to wait until it's time
  362  * to start job jr.
  363  */
  364 {
  365     unsigned int tj, tn;
  366 
  367     if (now) return 0;
  368     tn = time(NULL);
  369     tj = start_sec + jr->delay * 60;
  370     if (tj < tn) return 0;
  371     return tj - tn;
  372 }
  373 
  374 static void
  375 fake_jobs()
  376 {
  377     int j;
  378 
  379     j = 0;
  380     while (j < njobs)
  381     {
  382     fake_job(job_array[j]);
  383     explain("Updated timestamp for job `%s' to %04d-%02d-%02d",
  384         job_array[j]->ident, year, month, day_of_month);
  385     j++;
  386     }
  387 }
  388 
  389 static void
  390 explain_intentions()
  391 {
  392     int j;
  393 
  394     j = 0;
  395     while (j < njobs)
  396     {
  397     if (now)
  398     {
  399         explain("Will run job `%s'", job_array[j]->ident);
  400     }
  401     else
  402     {
  403         explain("Will run job `%s' in %d min.",
  404             job_array[j]->ident, job_array[j]->delay);
  405     }
  406     j++;
  407     }
  408     if (serialize && njobs > 0)
  409     explain("Jobs will be executed sequentially");
  410 }
  411 
  412 int
  413 main(int argc, char *argv[])
  414 {
  415     int j;
  416 
  417     anacrontab = NULL;
  418 
  419     if((program_name = strrchr(argv[0], '/')) == NULL)
  420     program_name = argv[0];
  421     else
  422     ++program_name; /* move pointer to char after '/' */
  423 
  424     parse_opts(argc, argv);
  425 
  426     if (anacrontab == NULL)
  427     anacrontab = strdup(ANACRONTAB);
  428 
  429     in_background = 0;
  430 
  431     if (chdir(SPOOLDIR)) die_e("Can't chdir to " SPOOLDIR);
  432 
  433     old_umask = umask(0);
  434 
  435     if (sigprocmask(0, NULL, &old_sigmask)) die_e("sigset error");
  436 
  437     if (fclose(stdin)) die_e("Can't close stdin");
  438     xopen(0, "/dev/null", O_RDONLY);
  439 
  440     if (!no_daemon)
  441     go_background();
  442     else
  443     primary_pid = getpid();
  444 
  445     record_start_time();
  446     read_tab();
  447     arrange_jobs();
  448 
  449     if (update_only)
  450     {
  451     fake_jobs();
  452     exit(0);
  453     }
  454 
  455     explain_intentions();
  456     set_signal_handling();
  457     running_jobs = running_mailers = 0;
  458     for(j = 0; j < njobs; ++j)
  459     {
  460     xsleep(time_till(job_array[j]));
  461     if (serialize) wait_jobs();
  462     launch_job(job_array[j]);
  463     }
  464     wait_children();
  465     explain("Normal exit (%d jobs run)", njobs);
  466     exit(0);
  467 }