259 lines
5.4 KiB
C
259 lines
5.4 KiB
C
/* crontab 1.2 - user crontab manipulation Author: Kees J. Bot
|
|
* 12 Jan 1997
|
|
*/
|
|
#define nil ((void*)0)
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <sys/stat.h>
|
|
#include "misc.h"
|
|
#include "tab.h"
|
|
|
|
#if __minix && !__minix_vmd
|
|
#define seteuid(uid) ((uid),0) /* Minix can't fiddle with uids. */
|
|
#endif
|
|
|
|
static int opentab(int uid, char *file, int how)
|
|
/* Open a crontab file under the given uid. How is 'r' or 'w'. Return
|
|
* the result of open(2).
|
|
*/
|
|
{
|
|
uid_t safe_uid;
|
|
int flags, r, err;
|
|
|
|
switch (how) {
|
|
case 'r': flags= O_RDONLY; break;
|
|
case 'w': flags= O_WRONLY | O_CREAT | O_TRUNC; break;
|
|
default: errno= EINVAL; return -1;
|
|
}
|
|
|
|
#if __minix && !__minix_vmd
|
|
/* Standard Minix has no saved uid, so use the lousy old access(). */
|
|
if (uid != 0) {
|
|
if (access(file, how == 'r' ? R_OK : W_OK) < 0) return -1;
|
|
}
|
|
#endif
|
|
|
|
safe_uid= geteuid();
|
|
seteuid(uid);
|
|
r= open(file, flags, 0666);
|
|
err= errno;
|
|
seteuid(safe_uid);
|
|
errno= err;
|
|
return r;
|
|
}
|
|
|
|
static void copytab(int fd_in, char *file_in, int fd_out, char *file_out)
|
|
/* Copy one open file to another. Complain and exit on errors. */
|
|
{
|
|
ssize_t r, w;
|
|
char buf[1024];
|
|
|
|
while ((r= read(fd_in, buf, sizeof(buf))) > 0) {
|
|
w= 0;
|
|
while (w < r) {
|
|
if ((r= write(fd_out, buf+w, r-w)) <= 0) {
|
|
fprintf(stderr,
|
|
"%s: Write error on %s: %s\n",
|
|
prog_name,
|
|
file_out,
|
|
r == 0 ? "End of file"
|
|
: strerror(errno));
|
|
exit(1);
|
|
}
|
|
w+= r;
|
|
}
|
|
}
|
|
if (r < 0) {
|
|
fprintf(stderr, "%s: Read error on %s: %s\n",
|
|
prog_name, file_in, strerror(errno));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s -c [user] file # Change crontab\n"
|
|
" %s -l [user] # List crontab\n"
|
|
" %s -r [user] # Remove crontab\n"
|
|
" %s -p # Tell cron to reload\n",
|
|
prog_name, prog_name, prog_name, prog_name);
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i;
|
|
int cflag, lflag, rflag, pflag;
|
|
uid_t uid;
|
|
char *user, *file;
|
|
struct passwd *pw;
|
|
static char SPOOLDIR[]= "/usr/spool/crontabs";
|
|
char tabfile[sizeof(SPOOLDIR) + NAME_MAX];
|
|
|
|
prog_name= strrchr(argv[0], '/');
|
|
if (prog_name == nil) prog_name= argv[0]; else prog_name++;
|
|
|
|
cflag= lflag= rflag= pflag= 0;
|
|
i= 1;
|
|
while (i < argc && argv[i][0] == '-') {
|
|
char *opt= argv[i++] + 1;
|
|
|
|
if (opt[0] == '-' && opt[1] == 0) break; /* -- */
|
|
|
|
while (*opt != 0) switch (*opt++) {
|
|
case 'c': cflag= 1; break;
|
|
case 'l': lflag= 1; break;
|
|
case 'r': rflag= 1; break;
|
|
case 'p': pflag= 1; break;
|
|
default: usage();
|
|
}
|
|
}
|
|
if (cflag + lflag + rflag + pflag != 1) usage();
|
|
|
|
user= file= nil;
|
|
if (!pflag && i < argc) user= argv[i++];
|
|
if (cflag) {
|
|
if (user == nil) usage();
|
|
if (i < argc) {
|
|
file= argv[i++];
|
|
} else {
|
|
file= user;
|
|
user= nil;
|
|
}
|
|
}
|
|
if (i != argc) usage();
|
|
|
|
if (geteuid() != 0) {
|
|
fprintf(stderr, "%s: No root privileges?\n", prog_name);
|
|
}
|
|
uid= getuid();
|
|
if (user == nil) {
|
|
if ((pw= getpwuid(uid)) == nil) {
|
|
fprintf(stderr,
|
|
"%s: Don't know who you (uid %lu) are!\n",
|
|
prog_name, (unsigned long) uid);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if ((pw= getpwnam(user)) == nil) {
|
|
fprintf(stderr,
|
|
"%s: Don't know who you (%s) are!\n",
|
|
prog_name, user);
|
|
exit(1);
|
|
}
|
|
}
|
|
if (uid != 0 && pw->pw_uid != uid) {
|
|
fprintf(stderr,
|
|
"%s: Only root can change the crontabs of others!\n",
|
|
prog_name);
|
|
exit(1);
|
|
}
|
|
user= pw->pw_name;
|
|
uid= pw->pw_uid;
|
|
seteuid(uid);
|
|
umask(0077);
|
|
|
|
selectlog(STDERR);
|
|
sprintf(tabfile, "%s/%s", SPOOLDIR, user);
|
|
|
|
if (lflag) {
|
|
int fd;
|
|
|
|
if ((fd= opentab(0, tabfile, 'r')) < 0) {
|
|
fprintf(stderr, "%s: Can't open %s: %s\n",
|
|
prog_name, tabfile, strerror(errno));
|
|
exit(1);
|
|
}
|
|
copytab(fd, tabfile, 1, "stdout");
|
|
close(fd);
|
|
}
|
|
|
|
if (rflag) {
|
|
seteuid(0);
|
|
if (unlink(tabfile) < 0) {
|
|
fprintf(stderr, "%s: Can't remove %s: %s\n",
|
|
prog_name, tabfile, strerror(errno));
|
|
exit(1);
|
|
}
|
|
seteuid(uid);
|
|
printf("Crontab of %s removed\n", user);
|
|
pflag= 1;
|
|
}
|
|
|
|
/* Initialize current Time */
|
|
time(&now);
|
|
|
|
if (cflag) {
|
|
int fd1, fd2;
|
|
|
|
if ((fd1= opentab(uid, file, 'r')) < 0) {
|
|
fprintf(stderr, "%s: Can't open %s: %s\n",
|
|
prog_name, file, strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
/* Try to parse the new crontab file. If the parsing
|
|
* succeeds then 'crontabs' will be non-null.
|
|
*/
|
|
tab_parse(file, user);
|
|
tab_purge();
|
|
if (crontabs == nil) exit(1);
|
|
|
|
if ((fd2= opentab(0, tabfile, 'w')) < 0) {
|
|
fprintf(stderr, "%s: Can't open %s: %s\n",
|
|
prog_name, tabfile, strerror(errno));
|
|
exit(1);
|
|
}
|
|
copytab(fd1, file, fd2, tabfile);
|
|
close(fd1);
|
|
close(fd2);
|
|
printf("New crontab for %s installed\n", user);
|
|
pflag= 1;
|
|
}
|
|
|
|
if (pflag) {
|
|
/* Alert cron to the new situation. */
|
|
FILE *fp;
|
|
|
|
seteuid(0);
|
|
if ((fp= fopen(PIDFILE, "r")) != NULL) {
|
|
unsigned long pid;
|
|
int c;
|
|
|
|
pid= 0;
|
|
while ((c= fgetc(fp)) != EOF && c != '\n') {
|
|
if ((unsigned) (c - '0') >= 10) {
|
|
pid= 0; break;
|
|
}
|
|
pid= 10*pid + (c - '0');
|
|
if (pid >= 30000) { pid= 0; break; }
|
|
}
|
|
if (pid > 1 && kill((pid_t) pid, SIGHUP) == 0) {
|
|
pflag= 0;
|
|
}
|
|
}
|
|
seteuid(uid);
|
|
if (pflag) {
|
|
fprintf(stderr,
|
|
"%s: Alerting cron has failed; cron still running?\n",
|
|
prog_name);
|
|
exit(1);
|
|
}
|
|
printf("Cron signalled to reload tables\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* $PchId: crontab.c,v 1.4 2000/07/17 18:54:50 philip Exp $
|
|
*/
|