last_patch63 from vodz: add in crond and crontab applets
This commit is contained in:
parent
44608e9693
commit
f6f7bfb8e0
2
AUTHORS
2
AUTHORS
@ -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.
|
||||
|
||||
|
@ -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 $
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
1146
miscutils/crond.c
Normal file
File diff suppressed because it is too large
Load Diff
393
miscutils/crontab.c
Normal file
393
miscutils/crontab.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user