Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/cron/cron/cron.c
/* Copyright 1988,1990,1993,1994 by Paul Vixie | /* Copyright 1988,1990,1993,1994 by Paul Vixie | ||||
* All rights reserved | * All rights reserved | ||||
*/ | |||||
/* | |||||
* Copyright (c) 1997 by Internet Software Consortium | |||||
* | * | ||||
* Distribute freely, except: don't remove my name from the source or | * Permission to use, copy, modify, and distribute this software for any | ||||
* documentation (don't take credit for my work), mark your changes (don't | * purpose with or without fee is hereby granted, provided that the above | ||||
* get me blamed for your possible bugs), don't alter or remove this | * copyright notice and this permission notice appear in all copies. | ||||
* notice. May be sold if buildable source is provided to buyer. No | |||||
* warrantee of any kind, express or implied, is included with this | |||||
* software; use at your own risk, responsibility for damages (if any) to | |||||
* anyone resulting from the use of this software rests entirely with the | |||||
* user. | |||||
* | * | ||||
* Send bug reports, bug fixes, enhancements, requests, flames, etc., and | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | ||||
* I'll try to keep a version up to date. I can be reached as follows: | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | ||||
* Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | ||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |||||
* SOFTWARE. | |||||
*/ | */ | ||||
#if !defined(lint) && !defined(LINT) | #if !defined(lint) && !defined(LINT) | ||||
static const char rcsid[] = | static const char rcsid[] = | ||||
"$FreeBSD$"; | "$Id: cron.c,v 1.3 1998/08/14 00:32:36 vixie Exp $"; | ||||
#endif | #endif | ||||
#define MAIN_PROGRAM | #define MAIN_PROGRAM | ||||
#include "cron.h" | #include "cron.h" | ||||
#include <sys/mman.h> | #include <sys/mman.h> | ||||
#include <sys/signal.h> | |||||
#if SYS_TIME_H | |||||
# include <sys/time.h> | |||||
#else | |||||
# include <time.h> | |||||
#endif | |||||
static void usage(void), | static void usage(void), | ||||
run_reboot_jobs(cron_db *), | run_reboot_jobs(cron_db *), | ||||
cron_tick(cron_db *, int), | cron_tick(cron_db *, int), | ||||
cron_sync(int), | cron_sync(int), | ||||
cron_sleep(cron_db *, int), | cron_sleep(cron_db *, int), | ||||
cron_clean(cron_db *), | cron_clean(cron_db *), | ||||
#ifdef USE_SIGCHLD | |||||
sigchld_handler(int), | sigchld_handler(int), | ||||
#endif | |||||
sighup_handler(int), | sighup_handler(int), | ||||
parse_args(int c, char *v[]); | parse_args(int c, char *v[]); | ||||
static int run_at_secres(cron_db *); | static int run_at_secres(cron_db *); | ||||
static void find_interval_entry(pid_t); | static void find_interval_entry(pid_t); | ||||
static cron_db database; | static cron_db database; | ||||
static time_t last_time = 0; | static time_t last_time = 0; | ||||
static int dst_enabled = 0; | static int dst_enabled = 0; | ||||
static int dont_daemonize = 0; | static int dont_daemonize = 0; | ||||
struct pidfh *pfh; | struct pidfh *pfh; | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
#if DEBUGGING | #if DEBUGGING | ||||
char **dflags; | const char **dflags; | ||||
#endif | #endif | ||||
fprintf(stderr, "usage: cron [-j jitter] [-J rootjitter] " | fprintf(stderr, "usage: cron [-j jitter] [-J rootjitter] " | ||||
"[-m mailto] [-n] [-s] [-o] [-x debugflag[,...]]\n"); | "[-m mailto] [-n] [-s] [-o] [-x debugflag[,...]]\n"); | ||||
#if DEBUGGING | #if DEBUGGING | ||||
fprintf(stderr, "\ndebugflags: "); | fprintf(stderr, "\ndebugflags: "); | ||||
for(dflags = DebugFlagNames; *dflags; dflags++) { | for (dflags = DebugFlagNames; *dflags; dflags++) { | ||||
fprintf(stderr, "%s ", *dflags); | fprintf(stderr, "%s ", *dflags); | ||||
} | } | ||||
fprintf(stderr, "\n"); | fprintf(stderr, "\n"); | ||||
#endif | #endif | ||||
exit(ERROR_EXIT); | exit(ERROR_EXIT); | ||||
} | } | ||||
static void | static void | ||||
open_pidfile(void) | open_pidfile(void) | ||||
{ | { | ||||
char pidfile[MAX_FNAME]; | const char *pidfile = PIDDIR PIDFILE; | ||||
char buf[MAX_TEMPSTR]; | char buf[MAX_TEMPSTR]; | ||||
int otherpid; | int otherpid; | ||||
(void) snprintf(pidfile, sizeof(pidfile), PIDFILE, PIDDIR); | |||||
pfh = pidfile_open(pidfile, 0600, &otherpid); | pfh = pidfile_open(pidfile, 0600, &otherpid); | ||||
if (pfh == NULL) { | if (pfh == NULL) { | ||||
if (errno == EEXIST) { | if (errno == EEXIST) { | ||||
snprintf(buf, sizeof(buf), | snprintf(buf, sizeof(buf), | ||||
"cron already running, pid: %d", otherpid); | "cron already running, pid: %d", otherpid); | ||||
} else { | } else { | ||||
snprintf(buf, sizeof(buf), | snprintf(buf, sizeof(buf), | ||||
"can't open or create %s: %s", pidfile, | "can't open or create %s: %s", pidfile, | ||||
Show All 15 Lines | |||||
#if defined(BSD) | #if defined(BSD) | ||||
setlinebuf(stdout); | setlinebuf(stdout); | ||||
setlinebuf(stderr); | setlinebuf(stderr); | ||||
#endif | #endif | ||||
parse_args(argc, argv); | parse_args(argc, argv); | ||||
#ifdef USE_SIGCHLD | |||||
(void) signal(SIGCHLD, sigchld_handler); | (void) signal(SIGCHLD, sigchld_handler); | ||||
#else | |||||
(void) signal(SIGCLD, SIG_IGN); | |||||
#endif | |||||
(void) signal(SIGHUP, sighup_handler); | (void) signal(SIGHUP, sighup_handler); | ||||
open_pidfile(); | open_pidfile(); | ||||
set_cron_uid(); | set_cron_uid(); | ||||
set_cron_cwd(); | set_cron_cwd(); | ||||
#if defined(POSIX) | putenv("PATH="_PATH_DEFPATH); | ||||
setenv("PATH", _PATH_DEFPATH, 1); | |||||
#endif | |||||
/* if there are no debug flags turned on, fork as a daemon should. | /* if there are no debug flags turned on, fork as a daemon should. | ||||
*/ | */ | ||||
# if DEBUGGING | # if DEBUGGING | ||||
if (DebugFlags) { | if (DebugFlags) { | ||||
# else | # else | ||||
if (0) { | if (0) { | ||||
# endif | # endif | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | # endif /*DEBUGGING*/ | ||||
/* sleep 1 or 60 seconds | /* sleep 1 or 60 seconds | ||||
*/ | */ | ||||
TargetTime += (secres1 != 0) ? 1 : 60; | TargetTime += (secres1 != 0) ? 1 : 60; | ||||
runnum += 1; | runnum += 1; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
run_reboot_jobs(cron_db *db) | run_reboot_jobs(cron_db *db) | ||||
{ | { | ||||
register user *u; | user *u; | ||||
register entry *e; | entry *e; | ||||
for (u = db->head; u != NULL; u = u->next) { | for (u = db->head; u != NULL; u = u->next) { | ||||
for (e = u->crontab; e != NULL; e = e->next) { | for (e = u->crontab; e != NULL; e = e->next) { | ||||
if (e->flags & WHEN_REBOOT) { | if (e->flags & WHEN_REBOOT) { | ||||
job_add(e, u); | job_add(e, u); | ||||
} | } | ||||
if (e->flags & INTERVAL) { | if (e->flags & INTERVAL) { | ||||
e->lastexit = TargetTime; | e->lastexit = TargetTime; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
(void) job_runqueue(); | (void) job_runqueue(); | ||||
} | } | ||||
static void | static void | ||||
cron_tick(cron_db *db, int secres) | cron_tick(cron_db *db, int secres) | ||||
{ | { | ||||
static struct tm lasttm; | static struct tm lasttm; | ||||
static time_t diff = 0, /* time difference in seconds from the last offset change */ | /* time difference in seconds from the last offset change */ | ||||
difflimit = 0; /* end point for the time zone correction */ | static time_t diff = 0; | ||||
struct tm otztm; /* time in the old time zone */ | /* end point for the time zone correction */ | ||||
static time_t difflimit = 0; | |||||
/* time in the old time zone */ | |||||
struct tm otztm; | |||||
int otzsecond, otzminute, otzhour, otzdom, otzmonth, otzdow; | int otzsecond, otzminute, otzhour, otzdom, otzmonth, otzdow; | ||||
register struct tm *tm = localtime(&TargetTime); | struct tm *tm = localtime(&TargetTime); | ||||
register int second, minute, hour, dom, month, dow; | int second, minute, hour, dom, month, dow; | ||||
register user *u; | user *u; | ||||
register entry *e; | entry *e; | ||||
/* make 0-based values out of these so we can use them as indices | /* make 0-based values out of these so we can use them as indices | ||||
*/ | */ | ||||
second = (secres == 0) ? 0 : tm->tm_sec -FIRST_SECOND; | second = (secres == 0) ? 0 : tm->tm_sec -FIRST_SECOND; | ||||
minute = tm->tm_min -FIRST_MINUTE; | minute = tm->tm_min -FIRST_MINUTE; | ||||
hour = tm->tm_hour -FIRST_HOUR; | hour = tm->tm_hour -FIRST_HOUR; | ||||
dom = tm->tm_mday -FIRST_DOM; | dom = tm->tm_mday -FIRST_DOM; | ||||
month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH; | month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH; | ||||
dow = tm->tm_wday -FIRST_DOW; | dow = tm->tm_wday -FIRST_DOW; | ||||
Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d,%d)\n", | Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d,%d)\n", | ||||
getpid(), second, minute, hour, dom, month, dow)) | getpid(), second, minute, hour, dom, month, dow)) | ||||
if (dst_enabled && last_time != 0 | if (dst_enabled && last_time != 0 | ||||
&& TargetTime > last_time /* exclude stepping back */ | && TargetTime > last_time /* exclude stepping back */ | ||||
&& tm->tm_gmtoff != lasttm.tm_gmtoff ) { | && tm->tm_gmtoff != lasttm.tm_gmtoff ) { | ||||
diff = tm->tm_gmtoff - lasttm.tm_gmtoff; | diff = tm->tm_gmtoff - lasttm.tm_gmtoff; | ||||
if ( diff > 0 ) { /* ST->DST */ | if ( diff > 0 ) { /* ST->DST */ | ||||
/* mark jobs for an earlier run */ | /* mark jobs for an earlier run */ | ||||
difflimit = TargetTime + diff; | difflimit = TargetTime + diff; | ||||
for (u = db->head; u != NULL; u = u->next) { | for (u = db->head; u != NULL; u = u->next) { | ||||
for (e = u->crontab; e != NULL; e = e->next) { | for (e = u->crontab; e != NULL; e = e->next) { | ||||
e->flags &= ~NOT_UNTIL; | e->flags &= ~NOT_UNTIL; | ||||
if ( e->lastrun >= TargetTime ) | if ( e->lastrun >= TargetTime ) | ||||
e->lastrun = 0; | e->lastrun = 0; | ||||
/* not include the ends of hourly ranges */ | /* not include the ends of hourly ranges */ | ||||
if ( e->lastrun < TargetTime - 3600 ) | if ( e->lastrun < TargetTime - 3600 ) | ||||
e->flags |= RUN_AT; | e->flags |= RUN_AT; | ||||
else | else | ||||
e->flags &= ~RUN_AT; | e->flags &= ~RUN_AT; | ||||
} | } | ||||
} | } | ||||
} else { /* diff < 0 : DST->ST */ | } else { /* diff < 0 : DST->ST */ | ||||
/* mark jobs for skipping */ | /* mark jobs for skipping */ | ||||
difflimit = TargetTime - diff; | difflimit = TargetTime - diff; | ||||
for (u = db->head; u != NULL; u = u->next) { | for (u = db->head; u != NULL; u = u->next) { | ||||
for (e = u->crontab; e != NULL; e = e->next) { | for (e = u->crontab; e != NULL; e = e->next) { | ||||
e->flags |= NOT_UNTIL; | e->flags |= NOT_UNTIL; | ||||
e->flags &= ~RUN_AT; | e->flags &= ~RUN_AT; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (diff != 0) { | if (diff != 0) { | ||||
/* if the time was reset of the end of special zone is reached */ | /* if the time was reset of the end of special zone is reached */ | ||||
if (last_time == 0 || TargetTime >= difflimit) { | if (last_time == 0 || TargetTime >= difflimit) { | ||||
/* disable the TZ switch checks */ | /* disable the TZ switch checks */ | ||||
diff = 0; | diff = 0; | ||||
difflimit = 0; | difflimit = 0; | ||||
for (u = db->head; u != NULL; u = u->next) { | for (u = db->head; u != NULL; u = u->next) { | ||||
for (e = u->crontab; e != NULL; e = e->next) { | for (e = u->crontab; e != NULL; e = e->next) { | ||||
e->flags &= ~(RUN_AT|NOT_UNTIL); | e->flags &= ~(RUN_AT|NOT_UNTIL); | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
/* get the time in the old time zone */ | /* get the time in the old time zone */ | ||||
time_t difftime = TargetTime + tm->tm_gmtoff - diff; | time_t difftime = TargetTime + tm->tm_gmtoff - diff; | ||||
gmtime_r(&difftime, &otztm); | gmtime_r(&difftime, &otztm); | ||||
Show All 9 Lines | cron_tick(cron_db *db, int secres) | ||||
} | } | ||||
/* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the | /* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the | ||||
* first and fifteenth AND every Sunday; '* * * * Sun' will run *only* | * first and fifteenth AND every Sunday; '* * * * Sun' will run *only* | ||||
* on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this | * on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this | ||||
* is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre. | * is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre. | ||||
* like many bizarre things, it's the standard. | * like many bizarre things, it's the standard. | ||||
*/ | */ | ||||
for (u = db->head; u != NULL; u = u->next) { | for (u = db->head; u != NULL; u = u->next) { | ||||
for (e = u->crontab; e != NULL; e = e->next) { | for (e = u->crontab; e != NULL; e = e->next) { | ||||
Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n", | Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n", | ||||
env_get("LOGNAME", e->envp), | env_get("LOGNAME", e->envp), | ||||
e->uid, e->gid, e->cmd)) | e->uid, e->gid, e->cmd)) | ||||
if (e->flags & INTERVAL) { | if (e->flags & INTERVAL) { | ||||
if (e->lastexit > 0 && | if (e->lastexit > 0 && | ||||
TargetTime >= e->lastexit + e->interval) | TargetTime >= e->lastexit + e->interval) | ||||
job_add(e, u); | job_add(e, u); | ||||
continue; | continue; | ||||
} | } | ||||
if ( diff != 0 && (e->flags & (RUN_AT|NOT_UNTIL)) ) { | if ( diff != 0 && (e->flags & (RUN_AT|NOT_UNTIL)) ) { | ||||
if (bit_test(e->second, otzsecond) | if (bit_test(e->second, otzsecond) && | ||||
&& bit_test(e->minute, otzminute) | bit_test(e->minute, otzminute) && | ||||
&& bit_test(e->hour, otzhour) | bit_test(e->hour, otzhour) && | ||||
&& bit_test(e->month, otzmonth) | bit_test(e->month, otzmonth) && | ||||
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR)) | ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR)) | ||||
? (bit_test(e->dow,otzdow) && bit_test(e->dom,otzdom)) | ? (bit_test(e->dow,otzdow) && bit_test(e->dom,otzdom)) | ||||
: (bit_test(e->dow,otzdow) || bit_test(e->dom,otzdom)) | : (bit_test(e->dow,otzdow) || bit_test(e->dom,otzdom)) | ||||
) | ) | ||||
) { | ) { | ||||
if ( e->flags & RUN_AT ) { | if ( e->flags & RUN_AT ) { | ||||
e->flags &= ~RUN_AT; | e->flags &= ~RUN_AT; | ||||
e->lastrun = TargetTime; | e->lastrun = TargetTime; | ||||
job_add(e, u); | job_add(e, u); | ||||
continue; | continue; | ||||
} else | } else | ||||
e->flags &= ~NOT_UNTIL; | e->flags &= ~NOT_UNTIL; | ||||
} else if ( e->flags & NOT_UNTIL ) | } else if ( e->flags & NOT_UNTIL ) | ||||
continue; | continue; | ||||
} | } | ||||
if (bit_test(e->second, second) | if (bit_test(e->second, second) && | ||||
&& bit_test(e->minute, minute) | bit_test(e->minute, minute) && | ||||
&& bit_test(e->hour, hour) | bit_test(e->hour, hour) && | ||||
&& bit_test(e->month, month) | bit_test(e->month, month) && | ||||
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR)) | ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR)) | ||||
? (bit_test(e->dow,dow) && bit_test(e->dom,dom)) | ? (bit_test(e->dow,dow) && bit_test(e->dom,dom)) | ||||
: (bit_test(e->dow,dow) || bit_test(e->dom,dom)) | : (bit_test(e->dow,dow) || bit_test(e->dom,dom)) | ||||
) | ) | ||||
) { | ) { | ||||
e->flags &= ~RUN_AT; | e->flags &= ~RUN_AT; | ||||
e->lastrun = TargetTime; | e->lastrun = TargetTime; | ||||
job_add(e, u); | job_add(e, u); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
last_time = TargetTime; | last_time = TargetTime; | ||||
lasttm = *tm; | lasttm = *tm; | ||||
} | } | ||||
/* the task here is to figure out how long it's going to be until :00 of the | /* the task here is to figure out how long it's going to be until :00 of the | ||||
* following minute and initialize TargetTime to this value. TargetTime | * following minute and initialize TargetTime to this value. TargetTime | ||||
* will subsequently slide 60 seconds at a time, with correction applied | * will subsequently slide 60 seconds at a time, with correction applied | ||||
* implicitly in cron_sleep(). it would be nice to let cron execute in | * implicitly in cron_sleep(). it would be nice to let cron execute in | ||||
* the "current minute" before going to sleep, but by restarting cron you | * the "current minute" before going to sleep, but by restarting cron you | ||||
* could then get it to execute a given minute's jobs more than once. | * could then get it to execute a given minute's jobs more than once. | ||||
* instead we have the chance of missing a minute's jobs completely, but | * instead we have the chance of missing a minute's jobs completely, but | ||||
* that's something sysadmin's know to expect what with crashing computers.. | * that's something sysadmin's know to expect what with crashing computers.. | ||||
*/ | */ | ||||
static void | static void | ||||
cron_sync(int secres) { | cron_sync(int secres) { | ||||
struct tm *tm; | struct tm *tm; | ||||
TargetTime = time((time_t*)0); | TargetTime = time((time_t*)0); | ||||
if (secres != 0) { | if (secres != 0) { | ||||
TargetTime += 1; | TargetTime += 1; | ||||
} else { | } else { | ||||
tm = localtime(&TargetTime); | tm = localtime(&TargetTime); | ||||
TargetTime += (60 - tm->tm_sec); | TargetTime += (60 - tm->tm_sec); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | cron_clean(cron_db *db) | ||||
for (u = db->head; u != NULL; u = u->next) { | for (u = db->head; u != NULL; u = u->next) { | ||||
for (e = u->crontab; e != NULL; e = e->next) { | for (e = u->crontab; e != NULL; e = e->next) { | ||||
e->flags &= ~(RUN_AT|NOT_UNTIL); | e->flags &= ~(RUN_AT|NOT_UNTIL); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#ifdef USE_SIGCHLD | |||||
static void | static void | ||||
sigchld_handler(int x) | sigchld_handler(int x) | ||||
{ | { | ||||
WAIT_T waiter; | WAIT_T waiter; | ||||
PID_T pid; | PID_T pid; | ||||
for (;;) { | for (;;) { | ||||
#ifdef POSIX | |||||
pid = waitpid(-1, &waiter, WNOHANG); | pid = waitpid(-1, &waiter, WNOHANG); | ||||
#else | |||||
pid = wait3(&waiter, WNOHANG, (struct rusage *)0); | |||||
#endif | |||||
switch (pid) { | switch (pid) { | ||||
case -1: | case -1: | ||||
Debug(DPROC, | Debug(DPROC, | ||||
("[%d] sigchld...no children\n", getpid())) | ("[%d] sigchld...no children\n", getpid())) | ||||
return; | return; | ||||
case 0: | case 0: | ||||
Debug(DPROC, | Debug(DPROC, | ||||
("[%d] sigchld...no dead kids\n", getpid())) | ("[%d] sigchld...no dead kids\n", getpid())) | ||||
return; | return; | ||||
default: | default: | ||||
find_interval_entry(pid); | find_interval_entry(pid); | ||||
Debug(DPROC, | Debug(DPROC, | ||||
("[%d] sigchld...pid #%d died, stat=%d\n", | ("[%d] sigchld...pid #%d died, stat=%d\n", | ||||
getpid(), pid, WEXITSTATUS(waiter))) | getpid(), pid, WEXITSTATUS(waiter))) | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#endif /*USE_SIGCHLD*/ | |||||
static void | static void | ||||
sighup_handler(int x) | sighup_handler(int x) | ||||
{ | { | ||||
log_close(); | log_close(); | ||||
} | } | ||||
static void | static void | ||||
parse_args(int argc, char *argv[]) | parse_args(int argc, char *argv[]) | ||||
{ | { | ||||
int argch; | int argch; | ||||
char *endp; | char *endp; | ||||
while ((argch = getopt(argc, argv, "j:J:m:nosx:")) != -1) { | while ((argch = getopt(argc, argv, "j:J:m:nosx:")) != -1) { | ||||
switch (argch) { | switch (argch) { | ||||
case 'j': | case 'j': | ||||
Jitter = strtoul(optarg, &endp, 10); | Jitter = strtoul(optarg, &endp, 10); | ||||
if (*optarg == '\0' || *endp != '\0' || Jitter > 60) | if (*optarg == '\0' || *endp != '\0' || Jitter > 60) | ||||
errx(ERROR_EXIT, | errx(ERROR_EXIT, | ||||
"bad value for jitter: %s", optarg); | "bad value for jitter: %s", optarg); | ||||
▲ Show 20 Lines • Show All 60 Lines • Show Last 20 Lines |