[comp.sources.unix] v20i007: Allow users to automatically run scripts at boot time

rsalz@uunet.uu.net (Rich Salz) (09/19/89)

Submitted-by: sgrimm@sun.com (Steven Grimm)
Posting-number: Volume 20, Issue 7
Archive-name: rc.user

This utility package allows users to run shell scripts automatically
at system boot time.  This is useful for everything from restarting
servers (in fact, I developed it for use with the superserver program
appearing here not too long ago) to sending mail notification of
system reboots.  The user interface is similar to Sun's crontab.

---
Steven Grimm				koreth@ssyx.ucsc.edu
Division of Social Sciences		uunet!ucbvax!ucscc!ssyx!koreth
University of California, Santa Cruz	"Pithy quotes are for losers."

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  rc.users
#	  rcuser.1
#	  rcuser.c
#
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X# rcuser
X#
X# Installation:
X#
X# Edit this Makefile and rcuser.c to suit your site.
X# Run "make install" as root.
X# Then edit your /etc/rc.local (or other startup script) so that
X#  /etc/rc.users is run at boot time.  Usually you will want it to
X#  be run fairly late in the boot process, in case users want to
X#  talk to other system daemons, etc.  (This could be done by make
X#  install, but it's probably best not to go tweaking peoples'
X#  rc files...)
X#
X
XCFLAGS = -O -s
XBINDIR = /usr/local
X
X# Change this if you want the rc files to be somewhere other than
X# /usr/lib/rc.
XRCDIR = /usr/lib/rc
X
Xrcuser: rcuser.c
X	$(CC) -DRCDIR=\"$(RCDIR)/\" $(CFLAGS) rcuser.c -o $@
X
Xinstall: rcuser
X	install -m 4711 rcuser $(BINDIR)
X	install -c -m 644 rc.users /etc
X	-mkdir $(RCDIR)
X	chmod 755 $(RCDIR)
X	@echo "Remember to edit /etc/rc.local to run /etc/rc.users"
X
Xclean:
X	-/bin/rm -f core rcuser *.o
SHAR_EOF
chmod 0600 Makefile || echo "restore of Makefile fails"
sed 's/^X//' << 'SHAR_EOF' > rc.users &&
X#!/bin/sh
X# Run all the user scripts in /usr/lib/rc.
X
Xcd /usr/lib/rc
X
Xexport USER
X
Xfor USER in *
Xdo
X(
X	/bin/su -f $USER -c "/bin/sh $USER" >/tmp/#rc.$USER 2>&1 </dev/null
X	if test -s /tmp/#rc.$USER; then
X		(echo "Output from your startup file at `date`"; echo "";
X		cat /tmp/#rc.$USER) | mail $USER
X	fi
X	/bin/rm /tmp/#rc.$USER
X) &
Xdone
SHAR_EOF
chmod 0600 rc.users || echo "restore of rc.users fails"
sed 's/^X//' << 'SHAR_EOF' > rcuser.1 &&
X.TH RCUSER 1 "29 March 1988" "Koreth's Nifty Utilities"
X.SH NAME
Xrcuser \- manipulate user system startup files
X.SH SYNOPSIS
X\fBrcuser\fR [\fB\-e\fR|\fB\-l\fR|\fB\-d\fR|\fB\-t\fR [\fIusername\fR]]
X.SH DESCRIPTION
X\fIRcuser\fR allows users to maintain shell scripts which are executed at
Xsystem startup time.  Users' startup scripts are stored in a system directory
X(\fI/usr/lib/rc\fR by default), in filenames matching the usernames of their
Xowners.  Startup files are executed by
X.IR sh (1).
X.LP
XAny output from the users' scripts are mailed to them.
X.LP
XThe superuser may specify a username on the command line; that user's file
Xwill be manipulated.  If no username is specified or \fIrcuser\fR is not
Xinvoked by the superuser, the current user's login name is used.
X.SH OPTIONS
X.IP \-e
XEdit a startup file.  The environment variable VISUAL is used if it exists;
Xotherwise a default editor
X.RI ( vi (1))
Xis used.  If a startup file
Xdoes not exist, it is created by \fIrcuser\fR before the editor is invoked.
X.IP \-l
XList a startup file.  The startup file is copied to standard output, using
X.IR cat (1).
XThis is the default action if no flags are specified on the command line.
X.IP \-d
XDelete a startup file.
X.IP \-t
XTest a startup file.  The file is executed the same way it would be at
Xsystem startup time.  If it doesn't exit fairly quickly and without
Xproducing output, something is probably wrong.  Note that startup files
Xare run with minimal environment strings; this environment is duplicated
Xby \fIrcuser\fR.
X.SH FILES
X.IP /usr/lib/rc
XUser startup directory
X.IP /etc/rc.local
XSystem startup script
X.IP /etc/rc.users
XRuns user startup scripts
X.SH "SEE ALSO"
Xcat(1), vi(1)
X.SH AUTHOR
XSteven Grimm, koreth@ssyx.ucsc.edu
SHAR_EOF
chmod 0600 rcuser.1 || echo "restore of rcuser.1 fails"
sed 's/^X//' << 'SHAR_EOF' > rcuser.c &&
X/*
X** rcuser -- allow users to perform functions at startup time
X**
X** by Steven Grimm, koreth@ssyx.ucsc.edu
X** 3-29-89
X*/
X
X/* Default editor, if VISUAL environment variable isn't set */
X#define VISUAL	"/usr/ucb/vi"
X
X/* Command to display a file */
X#define DISPLAY	"/bin/cat"
X
X/*
X** Command shell to test scripts with.  This should be the same
X** shell that's invoked for user scripts in rc.users.
X*/
X#define SHELL "/bin/sh"
X
X#include <pwd.h>
X#include <stdio.h>
X#include <errno.h>
X#include <sys/file.h>
X#include <sys/param.h>
X
X/* The username and id that we're working on behalf of. */
Xchar *username;
Xint  uid;
Xstruct passwd *pent;
X
Xchar *malloc();
X
X/*
X** Get a user's uid and, if necessary, name
X*/
Xgetuser(name)
Xchar *name;
X{
X	if (name == NULL)
X	{
X		uid = getuid();
X		pent = getpwuid(uid);
X		if (pent != NULL)
X			username = pent->pw_name;
X	}
X	else
X	{
X		username = name;
X		pent = getpwnam(name);
X		if (pent != NULL)
X			uid = pent->pw_uid;
X	}
X}
X
X/*
X** Print an error and exit.
X*/
Xpanic(err)
Xchar *err;
X{
X	perror(err);
X	exit(-1);
X}
X
X/*
X** Print usage and exit.
X*/
Xusage(name)
Xchar *name;
X{
X	fprintf(stderr,"Usage: %s [-l|-e|-d] [user]\n", name);
X	fprintf(stderr,"\t-l - show startup script\n");
X	fprintf(stderr,"\t-e - edit startup script\n");
X	fprintf(stderr,"\t-d - delete startup script\n");
X	fprintf(stderr,"\t-t - test startup script\n");
X	fprintf(stderr,"\n\tusername may only be specified by superuser\n");
X	exit(-1);
X}
X
X/*
X** Create a file, owned by the appropriate user.
X*/
Xcreate(file, uid)
Xchar *file;
Xint uid;
X{
X	int fd;
X
X	fd = open(file, O_WRONLY|O_CREAT, 0600);
X	if (fd == -1)
X		panic(file);
X
X	close(fd);
X	
X/* fchown() is a BSDism */
X	chown(file, uid, -1);
X}
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	char function, filename[MAXPATHLEN], *editor, *getenv();
X
X	if (argc < 2)
X	{
X		getuser(NULL);
X		function = 'l';
X	} else
X		if (argv[1][0] != '-')
X			usage(argv[0]);
X		else
X			switch(argv[1][1]) {
X			case 'l':
X			case 'e':
X			case 'd':
X			case 't':
X				function = argv[1][1];
X				break;
X			default:
X				usage(argv[0]);
X			}
X
X/* If a username is given on the command line, and we are superuser, use it. */
X	if (argc == 3 && getuid() == 0)
X		getuser(argv[2]);
X	else
X		getuser(NULL);
X
X/* Construct the name of the appropriate user's startup file. */
X	strcpy(filename, RCDIR);
X	strncat(filename, username, sizeof(filename)-sizeof(RCDIR)-1);
X
X/* Now, if the function requires it, create the file if it doesn't exist. */
X	if (function == 'e' && access(filename, F_OK) == -1)
X		if (errno == ENOENT)
X			create(filename, uid);
X		else
X			panic(filename);
X
X/* Delete the file if necessary/possible. */
X	if (function == 'd')
X		if (unlink(filename) == -1)
X			panic(filename);
X
X/* That's all we need to be root for, so change our uid to something secure. */
X	setreuid(uid, uid);
X
X/* Now edit or show the file, as appropriate. */
X	if (function == 'l')
X		execl(DISPLAY, DISPLAY, filename, NULL);
X	if (function == 'e')
X	{
X		if ((editor = getenv("VISUAL")) == NULL)
X			editor = VISUAL;
X		execl(editor, editor, filename, NULL);
X	}
X	if (function == 't')
X	{
X/* Duplicate the minimal environment under which the scripts are run */
X		char *env[5];
X
X		env[4] = NULL;
X		env[3] = malloc(strlen(pent->pw_name)+6);
X		sprintf(env[3], "USER=%s", pent->pw_name);
X		env[2] = malloc(strlen(pent->pw_shell)+7);
X		sprintf(env[2], "SHELL=%s", pent->pw_shell);
X		env[1] = malloc(strlen(RCDIR)+4);
X		sprintf(env[1], "PWD=%s", RCDIR);
X		env[1][strlen(RCDIR)+3] = '\0';	/* lop off trailing / */
X		env[0] = malloc(strlen(pent->pw_dir)+6);
X		sprintf(env[0], "HOME=%s", pent->pw_dir);
X		
X		execle(SHELL, SHELL, filename, NULL, env);
X	}
X	exit(0);
X}
X
SHAR_EOF
chmod 0600 rcuser.c || echo "restore of rcuser.c fails"
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.