Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/cron/lib/entry.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: entry.c,v 1.3 1998/08/14 00:32:39 vixie Exp $"; | ||||
#endif | #endif | ||||
/* vix 26jan87 [RCS'd; rest of log is in RCS file] | /* vix 26jan87 [RCS'd; rest of log is in RCS file] | ||||
* vix 01jan87 [added line-level error recovery] | * vix 01jan87 [added line-level error recovery] | ||||
* vix 31dec86 [added /step to the from-to range, per bob@acornrc] | * vix 31dec86 [added /step to the from-to range, per bob@acornrc] | ||||
* vix 30dec86 [written] | * vix 30dec86 [written] | ||||
*/ | */ | ||||
#include "cron.h" | #include "cron.h" | ||||
#include <grp.h> | #include <grp.h> | ||||
#ifdef LOGIN_CAP | #ifdef LOGIN_CAP | ||||
#include <login_cap.h> | #include <login_cap.h> | ||||
#endif | #endif | ||||
typedef enum ecode { | typedef enum ecode { | ||||
e_none, e_minute, e_hour, e_dom, e_month, e_dow, | e_none, e_minute, e_hour, e_dom, e_month, e_dow, | ||||
e_cmd, e_timespec, e_username, e_group, e_option, | e_cmd, e_timespec, e_username, e_group, e_option, | ||||
e_mem | e_mem | ||||
#ifdef LOGIN_CAP | #ifdef LOGIN_CAP | ||||
, e_class | , e_class | ||||
#endif | #endif | ||||
} ecode_e; | } ecode_e; | ||||
static char get_list(bitstr_t *, int, int, char *[], int, FILE *), | static const char *ecodes[] = | ||||
get_range(bitstr_t *, int, int, char *[], int, FILE *), | |||||
get_number(int *, int, char *[], int, FILE *); | |||||
static int set_element(bitstr_t *, int, int, int); | |||||
static char *ecodes[] = | |||||
{ | { | ||||
"no error", | "no error", | ||||
"bad minute", | "bad minute", | ||||
"bad hour", | "bad hour", | ||||
"bad day-of-month", | "bad day-of-month", | ||||
"bad month", | "bad month", | ||||
"bad day-of-week", | "bad day-of-week", | ||||
"bad command", | "bad command", | ||||
"bad time specifier", | "bad time specifier", | ||||
"bad username", | "bad username", | ||||
"bad group name", | "bad group name", | ||||
"bad option", | "bad option", | ||||
"out of memory", | "out of memory", | ||||
#ifdef LOGIN_CAP | #ifdef LOGIN_CAP | ||||
"bad class name", | "bad class name", | ||||
#endif | #endif | ||||
}; | }; | ||||
static char get_list(bitstr_t *, int, int, const char *[], int, FILE *), | |||||
get_range(bitstr_t *, int, int, const char *[], int, FILE *), | |||||
get_number(int *, int, const char *[], int, FILE *); | |||||
static int set_element(bitstr_t *, int, int, int); | |||||
void | void | ||||
free_entry(entry *e) | free_entry(entry *e) | ||||
{ | { | ||||
#ifdef LOGIN_CAP | #ifdef LOGIN_CAP | ||||
if (e->class != NULL) | if (e->class != NULL) | ||||
free(e->class); | free(e->class); | ||||
#endif | #endif | ||||
if (e->cmd != NULL) | if (e->cmd != NULL) | ||||
free(e->cmd); | free(e->cmd); | ||||
if (e->envp != NULL) | if (e->envp != NULL) | ||||
env_free(e->envp); | env_free(e->envp); | ||||
free(e); | free(e); | ||||
} | } | ||||
/* return NULL if eof or syntax error occurs; | /* return NULL if eof or syntax error occurs; | ||||
* otherwise return a pointer to a new entry. | * otherwise return a pointer to a new entry. | ||||
*/ | */ | ||||
entry * | entry * | ||||
load_entry(FILE *file, void (*error_func)(char *), struct passwd *pw, | load_entry(FILE *file, void (*error_func)(const char *), struct passwd *pw, | ||||
char **envp) | char **envp) | ||||
{ | { | ||||
/* this function reads one crontab entry -- the next -- from a file. | /* this function reads one crontab entry -- the next -- from a file. | ||||
* it skips any leading blank lines, ignores comments, and returns | * it skips any leading blank lines, ignores comments, and returns | ||||
* EOF if for any reason the entry can't be read and parsed. | * EOF if for any reason the entry can't be read and parsed. | ||||
* | * | ||||
* the entry is also parsed here. | * the entry is also parsed here. | ||||
* | * | ||||
* syntax: | * syntax: | ||||
* user crontab: | * user crontab: | ||||
* minutes hours doms months dows cmd\n | * minutes hours doms months dows cmd\n | ||||
* system crontab (/etc/crontab): | * system crontab (/etc/crontab): | ||||
* minutes hours doms months dows USERNAME cmd\n | * minutes hours doms months dows USERNAME cmd\n | ||||
*/ | */ | ||||
ecode_e ecode = e_none; | ecode_e ecode = e_none; | ||||
entry *e; | entry *e; | ||||
int ch; | int ch; | ||||
int len; | |||||
char cmd[MAX_COMMAND]; | char cmd[MAX_COMMAND]; | ||||
char envstr[MAX_ENVSTR]; | char envstr[MAX_ENVSTR]; | ||||
char **prev_env; | char **prev_env; | ||||
Debug(DPARS, ("load_entry()...about to eat comments\n")) | Debug(DPARS, ("load_entry()...about to eat comments\n")) | ||||
skip_comments(file); | skip_comments(file); | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | #endif /* !PAM */ | ||||
e->envp = env_copy(envp); | e->envp = env_copy(envp); | ||||
if (e->envp == NULL) { | if (e->envp == NULL) { | ||||
warn("env_copy"); | warn("env_copy"); | ||||
ecode = e_mem; | ecode = e_mem; | ||||
goto eof; | goto eof; | ||||
} | } | ||||
if (!env_get("SHELL", e->envp)) { | if (!env_get("SHELL", e->envp)) { | ||||
prev_env = e->envp; | prev_env = e->envp; | ||||
sprintf(envstr, "SHELL=%s", _PATH_BSHELL); | e->envp = env_set(e->envp, "SHELL=" _PATH_BSHELL); | ||||
e->envp = env_set(e->envp, envstr); | |||||
if (e->envp == NULL) { | if (e->envp == NULL) { | ||||
warn("env_set(%s)", envstr); | warn("env_set(%s)", "SHELL=" _PATH_BSHELL); | ||||
env_free(prev_env); | env_free(prev_env); | ||||
ecode = e_mem; | ecode = e_mem; | ||||
goto eof; | goto eof; | ||||
} | } | ||||
} | } | ||||
/* If LOGIN_CAP, this is deferred to do_command where the login class | /* If LOGIN_CAP, this is deferred to do_command where the login class | ||||
* is processed. If !LOGIN_CAP, do it here. | * is processed. If !LOGIN_CAP, do it here. | ||||
*/ | */ | ||||
#ifndef LOGIN_CAP | #ifndef LOGIN_CAP | ||||
if (!env_get("HOME", e->envp)) { | if (!env_get("HOME", e->envp)) { | ||||
prev_env = e->envp; | prev_env = e->envp; | ||||
sprintf(envstr, "HOME=%s", pw->pw_dir); | len = snprintf(envstr, sizeof(envstr), "HOME=%s", pw->pw_dir); | ||||
if (len < sizeof(envstr)) | |||||
e->envp = env_set(e->envp, envstr); | e->envp = env_set(e->envp, envstr); | ||||
if (e->envp == NULL) { | if (len >= sizeof(envstr) || e->envp == NULL) { | ||||
warn("env_set(%s)", envstr); | warn("env_set(%s)", envstr); | ||||
env_free(prev_env); | env_free(prev_env); | ||||
ecode = e_mem; | ecode = e_mem; | ||||
goto eof; | goto eof; | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
prev_env = e->envp; | prev_env = e->envp; | ||||
sprintf(envstr, "%s=%s", "LOGNAME", pw->pw_name); | len = snprintf(envstr, sizeof(envstr), "LOGNAME=%s", pw->pw_name); | ||||
if (len < (int)sizeof(envstr)) | |||||
e->envp = env_set(e->envp, envstr); | e->envp = env_set(e->envp, envstr); | ||||
if (e->envp == NULL) { | if (len >= (int)sizeof(envstr) || e->envp == NULL) { | ||||
warn("env_set(%s)", envstr); | warn("env_set(%s)", envstr); | ||||
env_free(prev_env); | env_free(prev_env); | ||||
ecode = e_mem; | ecode = e_mem; | ||||
goto eof; | goto eof; | ||||
} | } | ||||
#if defined(BSD) | #if defined(BSD) | ||||
prev_env = e->envp; | prev_env = e->envp; | ||||
sprintf(envstr, "%s=%s", "USER", pw->pw_name); | len = snprintf(envstr, sizeof(envstr), "USER=%s", pw->pw_name); | ||||
if (len < (int)sizeof(envstr)) | |||||
e->envp = env_set(e->envp, envstr); | e->envp = env_set(e->envp, envstr); | ||||
if (e->envp == NULL) { | if (len >= (int)sizeof(envstr) || e->envp == NULL) { | ||||
warn("env_set(%s)", envstr); | warn("env_set(%s)", envstr); | ||||
env_free(prev_env); | env_free(prev_env); | ||||
ecode = e_mem; | ecode = e_mem; | ||||
goto eof; | goto eof; | ||||
} | } | ||||
#endif | #endif | ||||
Debug(DPARS, ("load_entry()...checking for command options\n")) | Debug(DPARS, ("load_entry()...checking for command options\n")) | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | #endif | ||||
unget_char(ch, file); | unget_char(ch, file); | ||||
Debug(DPARS, ("load_entry()...about to parse command\n")) | Debug(DPARS, ("load_entry()...about to parse command\n")) | ||||
/* Everything up to the next \n or EOF is part of the command... | /* Everything up to the next \n or EOF is part of the command... | ||||
* too bad we don't know in advance how long it will be, since we | * too bad we don't know in advance how long it will be, since we | ||||
* need to malloc a string for it... so, we limit it to MAX_COMMAND. | * need to malloc a string for it... so, we limit it to MAX_COMMAND. | ||||
* XXX - should use realloc(). | |||||
*/ | */ | ||||
ch = get_string(cmd, MAX_COMMAND, file, "\n"); | ch = get_string(cmd, MAX_COMMAND, file, "\n"); | ||||
/* a file without a \n before the EOF is rude, so we'll complain... | /* a file without a \n before the EOF is rude, so we'll complain... | ||||
*/ | */ | ||||
if (ch == EOF) { | if (ch == EOF) { | ||||
ecode = e_cmd; | ecode = e_cmd; | ||||
goto eof; | goto eof; | ||||
Show All 18 Lines | eof: | ||||
if (ecode != e_none && error_func) | if (ecode != e_none && error_func) | ||||
(*error_func)(ecodes[(int)ecode]); | (*error_func)(ecodes[(int)ecode]); | ||||
while (ch != EOF && ch != '\n') | while (ch != EOF && ch != '\n') | ||||
ch = get_char(file); | ch = get_char(file); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
/* | |||||
* bits one bit per flag, default=FALSE | |||||
* low, high bounds, impl. offset for bitstr | |||||
* names NULL or names for these elements | |||||
* ch current character being processed | |||||
* file file being read | |||||
*/ | |||||
static char | static char | ||||
get_list(bitstr_t *bits, int low, int high, char *names[], int ch, FILE *file) | get_list(bitstr_t *bits, int low, int high, const char *names[], int ch, | ||||
FILE *file) | |||||
{ | { | ||||
register int done; | int done; | ||||
/* we know that we point to a non-blank character here; | /* we know that we point to a non-blank character here; | ||||
* must do a Skip_Blanks before we exit, so that the | * must do a Skip_Blanks before we exit, so that the | ||||
* next call (or the code that picks up the cmd) can | * next call (or the code that picks up the cmd) can | ||||
* assume the same thing. | * assume the same thing. | ||||
*/ | */ | ||||
Debug(DPARS|DEXT, ("get_list()...entered\n")) | Debug(DPARS|DEXT, ("get_list()...entered\n")) | ||||
Show All 22 Lines | get_list(bitstr_t *bits, int low, int high, const char *names[], int ch, | ||||
Skip_Blanks(ch, file) | Skip_Blanks(ch, file) | ||||
Debug(DPARS|DEXT, ("get_list()...exiting w/ %02x\n", ch)) | Debug(DPARS|DEXT, ("get_list()...exiting w/ %02x\n", ch)) | ||||
return ch; | return ch; | ||||
} | } | ||||
/* | |||||
* bits one bit per flag, default=FALSE | |||||
* low, high bounds, impl. offset for bitstr | |||||
* names NULL or names for these elements | |||||
* ch current character being processed | |||||
* file file being read | |||||
*/ | |||||
static char | static char | ||||
get_range(bitstr_t *bits, int low, int high, char *names[], int ch, FILE *file) | get_range(bitstr_t *bits, int low, int high, const char *names[], int ch, | ||||
FILE *file) | |||||
{ | { | ||||
/* range = number | number "-" number [ "/" number ] | /* range = number | number "-" number [ "/" number ] | ||||
*/ | */ | ||||
register int i; | int i, num1, num2, num3; | ||||
auto int num1, num2, num3; | |||||
Debug(DPARS|DEXT, ("get_range()...entering, exit won't show\n")) | Debug(DPARS|DEXT, ("get_range()...entering, exit won't show\n")) | ||||
if (ch == '*') { | if (ch == '*') { | ||||
/* '*' means "first-last" but can still be modified by /step | /* '*' means "first-last" but can still be modified by /step | ||||
*/ | */ | ||||
num1 = low; | num1 = low; | ||||
num2 = high; | num2 = high; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | get_range(bitstr_t *bits, int low, int high, const char *names[], int ch, | ||||
for (i = num1; i <= num2; i += num3) | for (i = num1; i <= num2; i += num3) | ||||
if (EOF == set_element(bits, low, high, i)) | if (EOF == set_element(bits, low, high, i)) | ||||
return EOF; | return EOF; | ||||
return ch; | return ch; | ||||
} | } | ||||
/* | |||||
* numptr where does the result go? | |||||
* low offset applied to enum result | |||||
* names symbolic names, if any, for enums | |||||
* ch current character | |||||
* file source | |||||
*/ | |||||
static char | static char | ||||
get_number(int *numptr, int low, char *names[], int ch, FILE *file) | get_number(int *numptr, int low, const char *names[], int ch, FILE *file) | ||||
{ | { | ||||
char temp[MAX_TEMPSTR], *pc; | char temp[MAX_TEMPSTR], *pc; | ||||
int len, i, all_digits; | int len, i, all_digits; | ||||
/* collect alphanumerics into our fixed-size temp array | /* collect alphanumerics into our fixed-size temp array | ||||
*/ | */ | ||||
pc = temp; | pc = temp; | ||||
len = 0; | len = 0; | ||||
▲ Show 20 Lines • Show All 53 Lines • Show Last 20 Lines |