last_patch63 from vodz: add in crond and crontab applets

This commit is contained in:
Eric Andersen 2002-10-22 12:24:59 +00:00
parent 44608e9693
commit f6f7bfb8e0
9 changed files with 1588 additions and 15 deletions

View File

@ -55,7 +55,7 @@ Glenn McGrath <bug1@optushome.com.au>
ar, dpkg, dpkg-deb
Vladimir Oleynik <dzo@simtreas.ru>
cmdedit; ports: ash, stty, traceroute, telnetd, top;
cmdedit; ports: ash, crond, stty, traceroute, telnetd, top;
locale, various fixes
and irreconcilable critic of everything not perfect.

View File

@ -113,7 +113,7 @@ Glenn McGrath <bug1@netconnect.com.au>
Vladimir Oleynik <dzo@simtreas.ru>
cmdedit; ports: ash, stty, traceroute, telnetd, top;
cmdedit; ports: ash, crond, stty, traceroute, telnetd, top;
locale, various fixes
and irreconcilable critic of everything not perfect.
@ -167,4 +167,4 @@ Enrique Zanardi <ezanardi@ull.es>
=cut
# $Id: busybox_footer.pod,v 1.6 2002/09/30 20:52:08 andersen Exp $
# $Id: busybox_footer.pod,v 1.7 2002/10/22 12:24:56 andersen Exp $

View File

@ -56,18 +56,18 @@ terse runtime description of their behavior.
Currently defined functions include:
addgroup, adduser, adjtimex, ar, awk, basename, busybox, cat, chgrp,
chmod, chown, chroot, chvt, clear, cmp, cp, cpio, cut, date, dc, dd,
deallocvt, deluser, df, dirname, dmesg, dos2unix, dpkg, dpkg-deb, du,
dumpkmap, dutmp, echo, expr, false, fbset, fdflush, find, free,
freeramdisk, fsck.minix, getopt, getty, grep, gunzip, gzip, halt, head,
hostid, hostname, id, ifconfig, init, insmod, kill, killall, klogd, length,
ln, loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, makedevs,
md5sum, mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, more, mount, mt,
mv, nc, netstat, nslookup, ping, pivot_root, poweroff, printf, ps, pwd,
rdate, readlink, reboot, renice, reset, rm, rmdir, rmmod, route, rpm2cpio,
sed, setkeycodes, sh, sleep, sort, stty, swapoff, swapon, sync, syslogd,
tail, tar, tee, telnet, telnetd, test, tftp, time, top, touch, tr, true,
tty, umount, uname, uniq, unix2dos, update, uptime, usleep, uudecode,
chmod, chown, chroot, chvt, clear, cmp, cp, cpio, crond, crontab, cut,
date, dc, dd, deallocvt, deluser, df, dirname, dmesg, dos2unix, dpkg,
dpkg-deb, du, dumpkmap, dutmp, echo, expr, false, fbset, fdflush, find,
free, freeramdisk, fsck.minix, getopt, getty, grep, gunzip, gzip, halt,
head, hostid, hostname, id, ifconfig, init, insmod, kill, killall, klogd,
length, ln, loadacm, loadfont, loadkmap, logger, logname, ls, lsmod,
makedevs, md5sum, mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, more,
mount, mt, mv, nc, netstat, nslookup, ping, pivot_root, poweroff, printf,
ps, pwd, rdate, readlink, reboot, renice, reset, rm, rmdir, rmmod, route,
rpm2cpio, sed, setkeycodes, sh, sleep, sort, stty, swapoff, swapon, sync,
syslogd, tail, tar, tee, telnet, telnetd, test, tftp, time, top, touch, tr,
true, tty, umount, uname, uniq, unix2dos, update, uptime, usleep, uudecode,
uuencode, watchdog, wc, wget, which, whoami, xargs, yes, zcat, [
=over 4

View File

@ -107,6 +107,12 @@
#ifdef CONFIG_CPIO
APPLET(cpio, cpio_main, _BB_DIR_BIN, _BB_SUID_NEVER)
#endif
#ifdef BB_CROND
APPLET(crond, crond_main, _BB_DIR_USR_SBIN)
#endif
#ifdef BB_CRONTAB
APPLET(crontab, crontab_main, _BB_DIR_USR_BIN)
#endif
#ifdef CONFIG_CUT
APPLET(cut, cut_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
#endif

View File

@ -186,6 +186,30 @@
"\tu\t\tunconditional overwrite\n" \
"\tF\t\tinput from file"
#define crond_trivial_usage \
"-d[#] -c <crondir> -f -b"
#define crond_full_usage \
"\t-d [#] -l [#] -S -L logfile -f -b -c dir\n" \
"\t-d num\tdebug level\n" \
"\t-l num\tlog level (8 - default)\n" \
"\t-S\tlog to syslod (defualt)\n" \
"\t-L file\tlog to file\n" \
"\t-f\trun in fordeground\n" \
"\t-b\trun in background (default)\n" \
"\t-c dir\tworking dir"
#define crontab_trivial_usage \
"crontab [-c dir] {file|-}|[-u|-l|-e|-d user]"
#define crontab_full_usage \
"\tfile <opts> replace crontab from file\n" \
"\t- <opts> replace crontab from stdin\n" \
"\t-u user specify user\n" \
"\t-l [user] list crontab for user\n" \
"\t-e [user] edit crontab for user\n" \
"\t-d [user] delete crontab for user\n" \
"\t-c dir specify crontab directory"
#define cut_trivial_usage \
"[OPTION]... [FILE]..."
#define cut_full_usage \

View File

@ -25,6 +25,8 @@ endif
MISCUTILS-y:=
MISCUTILS-$(CONFIG_ADJTIMEX) += adjtimex.o
MISCUTILS-$(CONFIG_CROND) += crond.o
MISCUTILS-$(CONFIG_CRONTAB) += crontab.o
MISCUTILS-$(CONFIG_DC) += dc.o
MISCUTILS-$(CONFIG_DUTMP) += dutmp.o
MISCUTILS-$(CONFIG_MAKEDEVS) += makedevs.o

View File

@ -7,6 +7,8 @@ mainmenu_option next_comment
comment 'Miscellaneous Utilities'
bool 'adjtimex' CONFIG_ADJTIMEX
bool 'crond' CONFIG_CROND
bool 'crontab' CONFIG_CRONTAB
bool 'dc' CONFIG_DC
bool 'dutmp' CONFIG_DUTMP
bool 'makedevs' CONFIG_MAKEDEVS

1146
miscutils/crond.c Normal file

File diff suppressed because it is too large Load Diff

393
miscutils/crontab.c Normal file
View File

@ -0,0 +1,393 @@
/*
* CRONTAB
*
* usually setuid root, -c option only works if getuid() == geteuid()
*
* Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com)
* May be distributed under the GNU General Public License
*
* Vladimir Oleynik <dzo@simtreas.ru> (C) 2002 to be used in busybox
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <pwd.h>
#include <unistd.h>
#include <grp.h>
#include <syslog.h>
#include <signal.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/resource.h>
#ifndef CRONTABS
#define CRONTABS "/var/spool/cron/crontabs"
#endif
#ifndef TMPDIR
#define TMPDIR "/var/spool/cron"
#endif
#ifndef CRONUPDATE
#define CRONUPDATE "cron.update"
#endif
#ifndef PATH_VI
#define PATH_VI "/usr/bin/vi" /* location of vi */
#endif
#include "busybox.h"
static const char *CDir = CRONTABS;
static void EditFile(const char *user, const char *file);
static int GetReplaceStream(const char *user, const char *file);
static int ChangeUser(const char *user, short dochdir);
int
crontab_main(int ac, char **av)
{
enum { NONE, EDIT, LIST, REPLACE, DELETE } option = NONE;
const struct passwd *pas;
const char *repFile = NULL;
int repFd = 0;
int i;
char caller[256]; /* user that ran program */
int UserId;
UserId = getuid();
if ((pas = getpwuid(UserId)) == NULL)
perror_msg_and_die("getpwuid");
strncpy(caller, pas->pw_name, sizeof(caller));
i = 1;
if (ac > 1) {
if (av[1][0] == '-' && av[1][1] == 0) {
option = REPLACE;
++i;
} else if (av[1][0] != '-') {
option = REPLACE;
++i;
repFile = av[1];
}
}
for (; i < ac; ++i) {
char *ptr = av[i];
if (*ptr != '-')
break;
ptr += 2;
switch(ptr[-1]) {
case 'l':
if (ptr[-1] == 'l')
option = LIST;
/* fall through */
case 'e':
if (ptr[-1] == 'e')
option = EDIT;
/* fall through */
case 'd':
if (ptr[-1] == 'd')
option = DELETE;
/* fall through */
case 'u':
if (i + 1 < ac && av[i+1][0] != '-') {
++i;
if (getuid() == geteuid()) {
pas = getpwnam(av[i]);
if (pas) {
UserId = pas->pw_uid;
} else {
error_msg_and_die("user %s unknown", av[i]);
}
} else {
error_msg_and_die("only the superuser may specify a user");
}
}
break;
case 'c':
if (getuid() == geteuid()) {
CDir = (*ptr) ? ptr : av[++i];
} else {
error_msg_and_die("-c option: superuser only");
}
break;
default:
i = ac;
break;
}
}
if (i != ac || option == NONE)
show_usage();
/*
* Get password entry
*/
if ((pas = getpwuid(UserId)) == NULL)
perror_msg_and_die("getpwuid");
/*
* If there is a replacement file, obtain a secure descriptor to it.
*/
if (repFile) {
repFd = GetReplaceStream(caller, repFile);
if (repFd < 0)
error_msg_and_die("unable to read replacement file");
}
/*
* Change directory to our crontab directory
*/
if (chdir(CDir) < 0)
perror_msg_and_die("cannot change dir to %s", CDir);
/*
* Handle options as appropriate
*/
switch(option) {
case LIST:
{
FILE *fi;
char buf[1024];
if ((fi = fopen(pas->pw_name, "r"))) {
while (fgets(buf, sizeof(buf), fi) != NULL)
fputs(buf, stdout);
fclose(fi);
} else {
error_msg("no crontab for %s", pas->pw_name);
}
}
break;
case EDIT:
{
FILE *fi;
int fd;
int n;
char tmp[128];
char buf[1024];
snprintf(tmp, sizeof(tmp), TMPDIR "/crontab.%d", getpid());
if ((fd = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) >= 0) {
chown(tmp, getuid(), getgid());
if ((fi = fopen(pas->pw_name, "r"))) {
while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
write(fd, buf, n);
}
EditFile(caller, tmp);
remove(tmp);
lseek(fd, 0L, 0);
repFd = fd;
} else {
error_msg_and_die("unable to create %s", tmp);
}
}
option = REPLACE;
/* fall through */
case REPLACE:
{
char buf[1024];
char path[1024];
int fd;
int n;
snprintf(path, sizeof(path), "%s.new", pas->pw_name);
if ((fd = open(path, O_CREAT|O_TRUNC|O_EXCL|O_APPEND|O_WRONLY, 0600)) >= 0) {
while ((n = read(repFd, buf, sizeof(buf))) > 0) {
write(fd, buf, n);
}
close(fd);
rename(path, pas->pw_name);
} else {
error_msg("unable to create %s/%s", CDir, buf);
}
close(repFd);
}
break;
case DELETE:
remove(pas->pw_name);
break;
case NONE:
default:
break;
}
/*
* Bump notification file. Handle window where crond picks file up
* before we can write our entry out.
*/
if (option == REPLACE || option == DELETE) {
FILE *fo;
struct stat st;
while ((fo = fopen(CRONUPDATE, "a"))) {
fprintf(fo, "%s\n", pas->pw_name);
fflush(fo);
if (fstat(fileno(fo), &st) != 0 || st.st_nlink != 0) {
fclose(fo);
break;
}
fclose(fo);
/* loop */
}
if (fo == NULL) {
error_msg("unable to append to %s/%s", CDir, CRONUPDATE);
}
}
return 0;
}
static int
GetReplaceStream(const char *user, const char *file)
{
int filedes[2];
int pid;
int fd;
int n;
char buf[1024];
if (pipe(filedes) < 0) {
perror("pipe");
return(-1);
}
if ((pid = fork()) < 0) {
perror("fork");
return(-1);
}
if (pid > 0) {
/*
* PARENT
*/
close(filedes[1]);
if (read(filedes[0], buf, 1) != 1) {
close(filedes[0]);
filedes[0] = -1;
}
return(filedes[0]);
}
/*
* CHILD
*/
close(filedes[0]);
if (ChangeUser(user, 0) < 0)
exit(0);
fd = open(file, O_RDONLY);
if (fd < 0) {
error_msg("unable to open %s", file);
exit(0);
}
buf[0] = 0;
write(filedes[1], buf, 1);
while ((n = read(fd, buf, sizeof(buf))) > 0) {
write(filedes[1], buf, n);
}
exit(0);
}
static void
EditFile(const char *user, const char *file)
{
int pid;
if ((pid = fork()) == 0) {
/*
* CHILD - change user and run editor
*/
char *ptr;
char visual[1024];
if (ChangeUser(user, 1) < 0)
exit(0);
if ((ptr = getenv("VISUAL")) == NULL || strlen(ptr) > 256)
ptr = PATH_VI;
snprintf(visual, sizeof(visual), "%s %s", ptr, file);
execl("/bin/sh", "/bin/sh", "-c", visual, NULL);
perror("exec");
exit(0);
}
if (pid < 0) {
/*
* PARENT - failure
*/
perror_msg_and_die("fork");
}
wait4(pid, NULL, 0, NULL);
}
static void
log(const char *ctl, ...)
{
va_list va;
char buf[1024];
va_start(va, ctl);
vsnprintf(buf, sizeof(buf), ctl, va);
syslog(LOG_NOTICE, "%s",buf );
va_end(va);
}
static int
ChangeUser(const char *user, short dochdir)
{
struct passwd *pas;
/*
* Obtain password entry and change privilages
*/
if ((pas = getpwnam(user)) == 0) {
log("failed to get uid for %s", user);
return(-1);
}
setenv("USER", pas->pw_name, 1);
setenv("HOME", pas->pw_dir, 1);
setenv("SHELL", "/bin/sh", 1);
/*
* Change running state to the user in question
*/
if (initgroups(user, pas->pw_gid) < 0) {
log("initgroups failed: %s %m", user);
return(-1);
}
if (setregid(pas->pw_gid, pas->pw_gid) < 0) {
log("setregid failed: %s %d", user, pas->pw_gid);
return(-1);
}
if (setreuid(pas->pw_uid, pas->pw_uid) < 0) {
log("setreuid failed: %s %d", user, pas->pw_uid);
return(-1);
}
if (dochdir) {
if (chdir(pas->pw_dir) < 0) {
if (chdir(TMPDIR) < 0) {
log("chdir failed: %s %s", user, pas->pw_dir);
log("chdir failed: %s " TMPDIR, user);
return(-1);
}
}
}
return(pas->pw_uid);
}