v13i065: Tools to help automate backups

Rich Salz rsalz at bbn.com
Wed Feb 24 21:00:18 AEST 1988


Submitted-by: Scooter Morris <scooter at genie.gene.com>
Posting-number: Volume 13, Issue 65
Archive-name: backups


This is a little backup utility that to somewhat automate a backup
schedule.  The main advantage that it has is that it will "quietize" the
system before performing the dumps.

The program reads a control file, and determines which filesystems to dump
at which level, and when.  It is designed to work with the UCB "dump(8)"
program.
	/r$

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README Makefile backup.8 backup.c backup.h convdate.c parser.y
#	proclist.c quietize.c restart.c scanner.l shutdown.c ulist.h
#	genie_dates backup_dates
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
			backup

This program should be run set-uid root.  At genentech, we set the
permissions to 4550 with group operator.  Backup was originally a
simple experiment to play around with yacc, it has proven to be
a very useful tool.  Daily backups are normally performed using
the "-m" option, which allows the system to continue running.  Without
this option, all running processes are sent "SIGHUP", any processes
remaining after the SIGHUP are SIGSTOPped for the duration of the
backup.  After backup is complete, a SIGCONT is sent to all of the
stopped processes.

Some notes about exclusions and special cases:  
	There is a list of processes to be excluded from either HUP or
	STOP in proclist.c.  In addition, some programs such as daemons,
	etc. require special restarting.  The table for this is in
	proclist.c also.

					10/2/87
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'

# $Header: Makefile,v 1.3 85/04/05 17:16:57 scooter Exp $
VPATH = .:./RCS
SOURCES = backup.c quietize.c shutdown.c proclist.c restart.c convdate.c \
	  parser.y scanner.l

OBJECTS = backup.o quietize.o shutdown.o proclist.o restart.o convdate.o \
	  y.tab.o
INCLUDES = backup.h ulist.h
CFLAGS = -O -DDEBUG
YFLAGS = -d

.SUFFIXES:	.c,v .l,v .y,v

backup: $(OBJECTS)
	cc $(CFLAGS) -o backup $(OBJECTS)

y.tab.o: y.tab.c lex.yy.c y.tab.h
	cc $(CFLAGS) -c y.tab.c

lex.yy.c:scanner.l
	lex scanner.l

y.tab.c: parser.y
	 yacc $(YFLAGS) parser.y

.y,v.y:
	co $<

.l,v.l:
	co $<

.c,v.o:	
	co $<
	cc $(CFLAGS) -c $<
SHAR_EOF
fi # end of overwriting check
if test -f 'backup.8'
then
	echo shar: will not over-write existing file "'backup.8'"
else
cat << \SHAR_EOF > 'backup.8'
.TH BACKUP 8
.SH NAME
backup \- perform tape backups
.SH SYNOPSIS
.B backup
[ options ] [ date ]
.SH DESCRIPTION
.vs -1p
.I backup
reads the file
.B /etc/backup_dates
and runs
.B dump(8)
to backup the specified filesystems.  If no
.I date
is given, the current date is used.
The 
.I backup_dates
file consists of lines of 6 fields each.  The fields are separated by spaces
of tabs.  The fields specify the day of the week (Sun-Sat), the week of the
month (1-5), the month (Jan-Dec), the dump level to perform (0-9), the
filesystem, and an arbitrary message to be delivered to the operator upon
completion of the dump.  Each of these fields may contain a range or
a comma-separated list, or an asterisk meaning all legal values.
.PP
Options for 
.I backup
are:
.TP
.B  \-m
Run 
.I backup
in multiuser mode.  Usually backup will kill any forground processes
and suspend any background processes so that the filesystems will be
guaranteed to be quiescent.  When run in multiuser mode, no action
is taken to insure that there is no filesystem activity.
.TP
.BI \-b blocksize
Sets the tape blocking factor to
.I blocksize.
The default is 32.
.TP
.BI \-s tapelength
Sets the assumed length of the tape to
.I tapelength.
This defines how many blocks are written to each tape.  The default is 
2300 feet.
.TP
.BI \-d density
Sets the tape density to
.I density.
This is normally 6250 BPI.
.TP
.BI \-t device
Sets the device to use to
.I device.
This is /dev/rmt9 on our systems which corresponds to the TU78 tape drives
at 6250 BPI.
.TP
.BI \-f file
Causes backup to read the filesystem dump schedule from the file
.I file
instead of from /etc/backup_dates.
.TP
.BI \-w minutes
Sets the warning time to give users when running in single-user mode.
.SH BACKUP_DATES Example
.nf
# Backup schedule for Genie - Genentech, Inc.
# Daily level 9's
Tue-Fri	*	*	9	/va	"/va dump complete"
# Monday dumps - level 1's
Mon	2-5	*	1	/	"root dump complete"
Mon	2,3,4,5	*	1	/va	"/va dump complete"
# Monthly level 0's
Mon	1	*	0	/	"root dump complete"
Mon	1	*	0	/va	"/va dump complete"
.fi
.SH AUTHOR
Scooter Morris - Genentech, Inc.
.SH SEE ALSO
dump(8), shutdown(8), backup_dates(5)
.SH BUGS
SHAR_EOF
fi # end of overwriting check
if test -f 'backup.c'
then
	echo shar: will not over-write existing file "'backup.c'"
else
cat << \SHAR_EOF > 'backup.c'
#ifdef lint
static char rcsid[] = "$Header: backup.c,v 1.9 86/10/20 18:37:34 scooter Exp $";
#endif lint
/*
 * backup - a program to control daily dumps
 *
 * This program has been written to control the daily dumping
 * of all of the system's files.  Backup reads from the file
 * /etc/backup_dates to get the days and times that a filesystem
 * should be backed up.  The format of backup_dates is:
 *
 * Day_of_week	Week_of_month	Month	Level	Filesystem	Message
 *
 * where:
 *	Day_of_week is one of {Mon,Tue,Wed,Thu,Fri,Sat,Sun}
 *	Week_of_month is 1-5
 *	Month is one of {Jan,Feb,...,Dec}
 *	Level is 0-9
 *	Filesystem is the NAME of the filesystem
 *	Message is a message to be printed to the operator upon
 *	        completion of the dump
 *
 * For example, backup_dates might look like:
 *
 * # Backup schedule for Genie - Genentech, Inc.
 * # Daily level 9's
 * Tue-Fri	*	*	9	/va	"/va dump complete"
 * # Monday dumps - level 1's
 * Mon	2-5	*	1	/	"root dump complete"
 * Mon	2,3,4,5	*	1	/va	"/va dump complete"
 * # Monthly level 0's
 * Mon	1	*	0	/	"root dump complete"
 * Mon	1	*	0	/va	"/va dump complete"
 *
 * Note that the "#" character is used as a comment, and that ranges
 * as well as the "*" may be used.  Obviously ranges and wildcards are
 * only allowed in the Day_of_week and Week_of_month fields.
 *
 * Usage:
 *	backup [-b blocksize] [-s tapelength] [-t device] [-f file ] [-m] [-w n]
 *             [-d density] [date]
 *
 * Diagnostics:
 *	Backup will complain if the input file is garbaged or if the
 *	filesystem is mounted.  The return status from dump is monitored
 *	to track the progress of the dump and to determine if dump
 *	fails.  If it fails, the operator will be prompted to determine
 *	if they want to retry this filesystem.
 *
 * Author: Scooter Morris, Genentech
 * Date: March, 1985
 *
 */

#include <stdio.h>
#include <sys/time.h>
#include <fstab.h>
#include <signal.h>
#include <errno.h>
#include <sys/reboot.h>
#include "backup.h"

struct tm	*localtime();
struct tm	*convdate();
struct fstab	*fsent;
char 		line[180];
extern int	errno;
int		x_opt = NO;

char		*day_names[7] =
{ "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" };

char		*month_names[12] =
{ "January","February","March","April","May","June","July","August",
  "September","October","November","December" };

main(argc, argv)
int argc; char *argv[];
{
	FILE	*file;
	char	*ptr;
	char	fname[BUFSIZ];	/* file name */
	char	tname[BUFSIZ];	/* tape name */
	char	fsname[BUFSIZ];
	char	dump_comm[BUFSIZ];
	char	*tmp,*rindex();
	int	f_opt = NO;
	int	t_opt = NO;
	int	m_opt = NO;
	int	date_opt = 0;
	int	ret = 0;
	int	minutes = 5;
	int	tape_block = BLOCK_SIZE;
	int	tape_size = TAPE_LENGTH;
	int	tape_density = TAPE_DENSITY;
	long	tmptime;	/* place to put time */
	struct	tm *curtim;	/* current time structure */

	int	week_day,month_week,month,day,year;

	argc--, argv++;
	while (argc > 0) {
		ptr = *argv;
		while (*ptr) switch (*ptr++) {

		case '-':
			break;

		case 'm':
		case 'M':
			m_opt = YES;
			break;

		case 'f':
		case 'F':
			f_opt = YES;
			if (*ptr == 0) {
			    argv++;
			    argc--;
			    if (*argv == 0) {
				fprintf(stderr,
					"backup: no file given with '-f'.\n");
				exit(1);
			    }
			    strcpy(fname,*argv);
			}
			else {
			    strcpy(fname,ptr);
			    *ptr = 0;
			}
			break;

		case 't':
		case 'T':
			t_opt = YES;
			if (*ptr == 0) {
			    argv++;
			    argc--;
			    if (*argv == 0) {
				fprintf(stderr,
					"backup: no device given with '-t'.\n");
				exit(1);
			    }
			    strcpy(tname,*argv);
			}
			else {
			    strcpy(fname,ptr);
			    *ptr = 0;
			}
			break;

		case 'b':
		case 'B':
			if (*ptr == 0) {
			    argv++;
			    argc--;
			    if (*argv == 0) {
				fprintf(stderr,
			"backup: no blocking factor given with '-b'.\n");
				exit(1);
			    }
			    tape_block = atoi(*argv);
			}
			else {
			    tape_block = atoi(ptr);
			    *ptr = 0;
			}
			break;
			

		case 'd':
		case 'D':
			if (*ptr == 0) {
			    argv++;
			    argc--;
			    if (*argv == 0) {
				fprintf(stderr,
			"backup: no density given with '-d'.\n");
				exit(1);
			    }
			    tape_density = atoi(*argv);
			}
			else {
			    tape_density = atoi(ptr);
			    *ptr = 0;
			}
			break;

		case 's':
		case 'S':
			if (*ptr == 0) {
			    argv++;
			    argc--;
			    if (*argv == 0) {
				fprintf(stderr,
					"backup: no size given with '-s'.\n");
				exit(1);
			    }
			    tape_size = atoi(*argv);
			}
			else {
			    tape_size = atoi(ptr);
			    *ptr = 0;
			}
			break;
		case 'w':
		case 'W':
			if (*ptr == 0) {
			    argv++;
			    argc--;
			    if (*argv == 0) {
				fprintf(stderr,
			"backup: warning time in minutes not given with '-w'.\n");
				exit(1);
			    }
			    minutes = atoi(*argv);
			}
			else {
			    minutes = atoi(ptr);
			    *ptr = 0;
			}
			break;
		case 'X':
		case 'x':
			x_opt = YES;
			printf("*** Debugging ***\n");
			break;

		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			month = day = year = 0;
			date_opt = sscanf(--ptr,"%d/%d/%d",&month,&day,&year);
			if (date_opt < 2)
			{
				fprintf(stderr,
				"backup: illegal date specification\n");
				exit(1);
			}
			*ptr = 0;
			break;

		default:
			fprintf(stderr,
			"Unknown option '%c' - ignored\n",ptr[-1]);
		}
		argc--, argv++;
		*ptr = 0;
	}

	quiet = 0;

	/* Ignore impatience */

	signal(SIGTERM,SIG_IGN);
	signal(SIGHUP,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	signal(SIGTSTP,SIG_IGN);

	/* get current date */

	if (date_opt)
	{
		curtim = convdate(month,day,year);
	} else {
		time(&tmptime);
		curtim = localtime(&tmptime);
	}

	week_day = curtim -> tm_wday;
	month_week = ( (curtim -> tm_mday - 1) / 7 ) + 1;
	month = curtim -> tm_mon;

	/* get dates file name */

	if (! f_opt) sprintf(fname,"%s",BACKUPFILE);
	if (! t_opt) sprintf(tname,"%s",DEVICE);

/*
 * Open up the input file
 */

	file = fopen(fname,"r");
	if (file == NULL)
	{
		perror(file);
		exit(errno);
	}

/*
 * Give introduction
 */

	printf("backup: Performing backup for %s %s %d, %d\n",
		day_names[week_day],month_names[month],curtim->tm_mday,
		curtim->tm_year+1900);

	line_count = 0;
	while (fgets(line,180,file) != NULL)
	{
		line_count++;
		lineptr = 0;
		if(yyparse() || ignore == YES)continue;

		if (x_opt)
		{
			printf("Today: %dw %dd %dm\n",month_week,week_day,month);
			printres("Weeks: ",weeks,week_lst,week_ptr);
			printres("Days: ",days,day_lst,day_ptr);
			printres("Months: ",months,month_lst,month_ptr);
		}

		if (check_per(month_week,weeks,week_lst,week_ptr))continue;

		if (check_per(week_day,days,day_lst,day_ptr))continue;

		if (check_per(month,months,month_lst,month_ptr))continue;

		fsent = getfsfile(filesys);
		if (fsent == NULL)
		{
			fprintf(stderr,"*** No filesystem %s\n",filesys);
			continue;
		}

		if (m_opt == NO)
		{
		/*
		 * Single user - if we already haven't quietize the system
		 */

			if (!quiet) 
			{
				fprintf(stderr,"%s\n%s",
	"*** You are about ready to kick off all users!!! ***",
	"*** Are you SURE you want to do this? ");
				gets(dump_comm);
				if (dump_comm[0] != 'y' &&
				    dump_comm[0] != 'Y') abort();
				fprintf(stderr,
	"*** Are you POSITIVE??? ");
				gets(dump_comm);
				if (dump_comm[0] != 'y' &&
				    dump_comm[0] != 'Y') abort();

				fprintf(stderr,
	"*** Beginning system shutdown....");
				quietize(minutes);
				quiet++;
			}
		}

		tmp = rindex(fsent->fs_spec,'/');
		fsname[0] = '\0';
		strncpy(fsname,fsent->fs_spec,(int)tmp-(int)(fsent->fs_spec)+1);
		fsname[(int)tmp-(int)(fsent->fs_spec)+1] = '\0';
		strncat(fsname,"r",1);
		strcat(fsname,++tmp);

		printf("To perform level %d dump of %s\n",level,filesys);
		dump_comm[0] = '0';
retry:		while (*dump_comm != 'r' && *dump_comm != 'q')
		{
printf("mount first tape and press 'r' RETURN when ready: ");
			gets(dump_comm);
		}

		if (*dump_comm == 'q') continue;

		sprintf(dump_comm,"%s %1dnufsdb %s %d %d %d %s\n",
				   DUMPCOM,level,tname,
				   tape_size,tape_density,tape_block,
				   fsname);

		ret = system(dump_comm);

		sprintf(line,"mt -t %s offl\n",tname);
		system(line);
		printf("*** %s ***\n",string);
	}

	printf("Backup is now complete!\n");
	if (m_opt == NO)
	{
		restart();	/* Restart the System */
	}
}

char
getnextchar()
{
	return((char)line[lineptr++]);
}

check_per(today,target,list,count)
int today,target,count;
int list[];
{
	int i;

	if (target == ALL)
		return(0);
	else if (target == LIST)
	{
		for (i = 0 ; i < count ; i++)
		{
			if(list[i] == today)return(0);
		}
	}
	else if (target == RANGE && today >= list[0] && today <= list[1])
		return(0);

	return(1);
}

printres(string,today,list,count)
char	*string;
int	today;
int	list[];
int	count;
{
	int i;

	printf("%s ",string);
	switch(today)
	{
	case ALL:
		printf("ALL ");
		break;
	case LIST:
		printf("LIST ");
		break;
	case RANGE:
		printf("RANGE ");
		break;
	}

	printf("(%d)",count);
	for (i = 0 ; i < count ; i++)
	{
		printf(" %d,",list[i]);
	}
	printf("\n");
}

abort()
{
	fprintf(stderr,"*** Backup aborted ***\n");
	exit(1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'backup.h'
then
	echo shar: will not over-write existing file "'backup.h'"
else
cat << \SHAR_EOF > 'backup.h'
/* $Header: backup.h,v 1.3 86/10/14 01:36:46 scooter Exp $ */
/*
 * backup.h - defines and defaults for backup
 */

#define	BLOCK_SIZE	32	/* Default blocking factor */
#define	TAPE_LENGTH	2300	/* Default tape length */
#define TAPE_DENSITY	6250	/* Default tape density */
#define DEVICE	"/dev/rmt9"	/* Default device for dumps */
#define	BACKUPFILE "/etc/backup_dates"
#define DUMPCOM "/etc/dump"

#define	YES	1
#define	NO	0
#define	ALL	-1
#define	RANGE	0
#define	LIST	1

int	ignore,days,weeks,months;
int	week_ptr,week_lst[5];
int	month_ptr,month_lst[12];
int	day_ptr,day_lst[7];
int	level,line_count,lineptr;
char	string[180];
char	filesys[180];
int	quiet;
extern	int	x_opt;
SHAR_EOF
fi # end of overwriting check
if test -f 'convdate.c'
then
	echo shar: will not over-write existing file "'convdate.c'"
else
cat << \SHAR_EOF > 'convdate.c'
#ifndef lint
	static char RCSid[] = "$Header: convdate.c,v 1.1 85/05/22 15:53:36 scooter Exp $";
#endif lint

/*
 * Module to convert date from mm/dd/yy format to a "tm" structure
 */


#include	<stdio.h>
#include	<sys/time.h>
#include	<tzfile.h>

static int	dmsize[13] =
	{ -1,31,28,31,30,31,30,31,31,30,31,30,31 };

struct tm *
convdate(month,day,year)
int month,day,year;
{
	int i;
	struct tm *today;
	struct timeval tv;
	struct timezone tz;

	gettimeofday(&tv,&tz);
	today = localtime(&tv.tv_sec);

	if (year == 0)year = today->tm_year;
	if (month == 0)month = today->tm_mon+1;
	if (day == 0)day = today->tm_mday;

	if (year < 1000)year += 1900;

	tv.tv_sec = 0;

	if (isleap(year) && month > 2)
		++tv.tv_sec;
	for (--year;year >= EPOCH_YEAR;--year)
		tv.tv_sec += isleap(year) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR;
	while (--month)
		tv.tv_sec += dmsize[month];
	tv.tv_sec += day - 1;
	tv.tv_sec = HOURS_PER_DAY * tv.tv_sec;
	tv.tv_sec = MINS_PER_HOUR * tv.tv_sec;
	tv.tv_sec = SECS_PER_MIN * tv.tv_sec;
	
	/* Now convert to local timezone */
	tv.tv_sec += (long)tz.tz_minuteswest*SECS_PER_MIN;
	if (localtime(&tv.tv_sec)->tm_isdst) tv.tv_sec -= SECS_PER_HOUR;

	return(localtime(&tv.tv_sec));
}
SHAR_EOF
fi # end of overwriting check
if test -f 'parser.y'
then
	echo shar: will not over-write existing file "'parser.y'"
else
cat << \SHAR_EOF > 'parser.y'
%{
static char rcsid[] = "$Header: parser.y,v 1.2 85/04/05 17:15:02 scooter Exp $";

#include	"backup.h"

%}

%start pgm

%token COMMENT DAY STRING NUM FILESYS STAR DASH NEWLINE MONTH COMMA

%%

pgm	: COMMENT NEWLINE
				{ ignore = YES; YYACCEPT; }
	| day_spec week_spec month_spec level filesys end_spec NEWLINE
				{ ignore = NO; YYACCEPT; }
	| error '\n'
				{ yyerrok; }
	;

level:	NUM
				{ level = $1; }
	;

filesys: FILESYS
				{ strcpy(filesys,yytext); }
	;

day_spec: STAR
				{ days = ALL; }
	| day_list
				{ days = LIST; }
	| DAY DASH DAY
				{ days = RANGE; day_lst[0] = $1; 
				  day_lst[1] = $3; day_ptr = 2;}
	;

day_list: DAY
				{ day_ptr = 0; day_lst[day_ptr++] = $1; }
	| day_list COMMA DAY
				{ day_lst[day_ptr++] = $3; }
	;

week_spec:STAR
				{ weeks = ALL; }
	| num_list
				{ weeks = LIST; }
	| NUM DASH NUM
				{ weeks = RANGE; week_lst[0] = $1; 
				  week_lst[1] = $3; week_ptr = 2;}
	;

num_list: NUM
				{ week_ptr = 0; week_lst[week_ptr++] = $1; }
	| num_list COMMA NUM
				{ week_lst[week_ptr++] = $3; }
	;

month_spec: STAR
				{ months = ALL; }
	| month_list
				{ months = LIST; }
	| MONTH DASH MONTH
				{ months = RANGE; month_lst[0] = $1; 
				  month_lst[1] = $3; month_ptr = 2;}
	;

month_list: MONTH
				{ month_ptr = 0; month_lst[month_ptr++] = $1; }
	| month_list COMMA MONTH
				{ month_lst[month_ptr++] = $3; }
	;

end_spec:	/* empty */
	| STRING
	| STRING COMMENT
	| COMMENT
	;

%%

#include "lex.yy.c"

yyerror(s)
char *s;
{
	fprintf(stderr,"%s:line = %d, char = %d\n",s,line_count,lineptr);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'proclist.c'
then
	echo shar: will not over-write existing file "'proclist.c'"
else
cat << \SHAR_EOF > 'proclist.c'
static char rcsid[] = "$Header: proclist.c,v 1.6 87/05/25 16:55:54 scooter Exp $";

/*
 * proclist
 *
 * This routine returns a list of candidate procedures for
 * killing.
 *
 * $Log:	proclist.c,v $
 * Revision 1.6  87/05/25  16:55:54  scooter
 * Added Appleshare stuff to "special processing" list
 * 
 * Revision 1.5  86/10/15  09:26:13  scooter
 * Added syslogd to the exclusion list
 * 
 * Revision 1.4  86/10/14  01:33:46  scooter
 * Added process specific startup/shutdown stuff
 * 
 *
 */

#include "backup.h"
#include "ulist.h"
#include <stdio.h>

/*
 * Table of offsets for portions of the ps -l line
 */

#define	UID	7
#define	PID	12
#define	PPID	18
#define	STAT	61
#define	CMD	75

/*
 * List of processes to exclude
 */

char	*exlist[] =
	{ "init",
	  "swapper",
	  "pagedaemon",
	  "/etc/timed",
	  "/etc/named",
	  "/etc/syslogd",
	  "/etc/atalkad",		/* Kinetics route info server */
	  "/usr/local/lib/lsrv",	/* Appletalk spooler */
	  "/usr/local/lib/atis",	/* Appletalk name server */
	  "- std.9600",
	  "- std.4800",
	  "- std.1200",
	  "- P4800",
	  "- P1200",
	  "- D1200",
	  "- Console",
	  0 };

/*
 * Processes which require special shutdown/restart
 */

struct	proc_struct 
{
	char	*pr_name;
	char	*pr_shutdown;
	char	*pr_restart;
} special_procs[] = {
	{"/etc/rjecop","opr 0 .d","/etc/hsp_reload"},
	{"genie Aufs Daemon","kill -TERM %d","cd /usr/adm;/usr/local/lib/aufs -V AppleSharePublicVolumes -U 20"},
	{"jinn Aufs Daemon","kill -TERM %d","cd /usr/adm;/usr/local/lib/aufs -U 20"},
	{0,0,0}
};

struct ulist *
proclist()
{
	struct ulist *head=NULL;
	struct ulist *tail=NULL;
	FILE *pschan,*popen();
	char string[180],*tmp,*rindex();
	int i,ex_flag;

	pschan = popen("/bin/ps -lgaxw","r");
	if (pschan == NULL)
	{
		fprintf(stderr,"*** Unable to get ps listing ***");
		exit (1);
	}

	fgets(string,180,pschan);	/* Skip the header */

	while ( fgets(string,180,pschan) != NULL )
	{

		/*
		 * Check for excluded processes
		 */

		i = ex_flag = 0;

		while ( tmp = exlist[i++] )
		{
			if (!strncmp(string+CMD,tmp,strlen(tmp)))
			{
				ex_flag = 1;
				break;
			}
		}

		if (ex_flag) continue;

		if (head == NULL)
		{
			head = tail = (struct ulist *)
				malloc(sizeof(struct ulist));
		} else
		{
			tail->next = (struct ulist *)
				malloc(sizeof(struct ulist));
			tail = tail->next;
		}

		tail->uid = atoi(string+UID);
		tail->pid = atoi(string+PID);
		tail->ppid = atoi(string+PPID);
		strncpy(tail->stat,string+STAT,4);
		strncpy(tail->cmd,string+CMD,39);
		tmp = rindex(tail->cmd,'\n');
		if (tmp != NULL)*tmp = '\0';
		tail->special_flag = 0;
		tail->next = NULL;

		/*
		 * Check for special shutdown/startup
		 */
		
		i = 0;
		while ( tmp = special_procs[i].pr_name )
		{
			if (!strncmp(tail->cmd,tmp,strlen(tmp)))
			{
				tail->special_flag++;
				
				/* Allow single argument (pid) -- this will allow special signals */
				sprintf(tail->proc_shutdn, special_procs[i].pr_shutdown, tail->pid);
				sprintf(tail->proc_restart, special_procs[i].pr_restart, tail->pid);
				break;
			}
			i++;
		}


#ifdef	DEBUG
		if (x_opt)
			printf("%6d, %6d, %6d, %4s, %s\n",tail->uid,tail->pid,
					tail->ppid,tail->stat,tail->cmd);
#endif	DEBUG

	}
	pclose(pschan);

	return(head);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'quietize.c'
then
	echo shar: will not over-write existing file "'quietize.c'"
else
cat << \SHAR_EOF > 'quietize.c'
static char rcsid[] = "$Header: quietize.c,v 1.7 86/10/14 01:34:03 scooter Exp $";

/*
 * quietize
 *
 * This module controls all of the procedures necessary to bring
 * the system to a quiescent state.  Basically this can be summarized
 * by the following:
 *
 *	1. Do a shutdown to tell the users goodbye (/etc/shutdown)
 *	2. Get a listing of all the processes running (/bin/ps)
 *	3. Send a SIGHUP to all user processes and handle special shutdown
 *	4. Get another listing
 *	5. Send a SIGSTOP to everything but gettys and inits
 *
 * $Log:	quietize.c,v $
 * Revision 1.7  86/10/14  01:34:03  scooter
 * Added process specific startup/shutdown stuff
 * 
 *
 */

#include	"backup.h"
#include	"ulist.h"
#include	<stdio.h>
#include	<signal.h>

struct	ulist 	*u_list,*proclist(),*proc;
int	our_pid;
int	our_ppid;

quietize(minutes)
int minutes;
{
	int fixlog(),procont();

/*
 * Begin by going through all of the warning stuff
 */

	fprintf(stderr,"\n*** Warning users ...");
	if (minutes <= 0)minutes = 5;

	signal(SIGINT,fixlog);

#ifdef	DEBUG
	if (x_opt == NO)
		shutdown(minutes);
#else	DEBUG
	shutdown(minutes);
#endif	DEBUG

/*
 * Get our pid
 */

	our_pid = getpid();

/*
 * Get the list of processes on the system
 */

	fprintf(stderr,"\n*** Finding processes ...");
	u_list = proclist();

/*
 * Blow them away
 */

	fprintf(stderr,"\n*** Hanging up processes ...");
	for (proc = u_list ; proc != NULL ; proc = proc->next)
	{
		if (proc->pid == our_pid)our_ppid = proc->ppid;
	}

#ifdef	DEBUG
	if (x_opt)
		printf("Our pid = %d, our ppid = %d\n",our_pid,our_ppid);
#endif	DEBUG

	for (proc = u_list ; proc != NULL ; proc = proc->next)
	{
		if (proc->pid == our_pid ||
		    proc->pid == our_ppid ||
		    proc->special_flag)continue;
#ifdef	DEBUG
	if (x_opt)
		printf("Hanging up proces %s (%d)\n",proc->cmd,proc->pid);
	else
#endif	DEBUG
		kill(proc->pid,SIGHUP);
	}

	/*
	 * Make an attempt to be clean by freeing up the memory
	 */

	for (proc = u_list ; proc != NULL ; )
	{
		free(proc->cmd);
		u_list = proc;
		proc = proc->next;
		free(u_list);
	}

	/*
	 * Get the left-over list
	 */

	u_list = proclist();

	/*
	 * Stop them
	 */

	fprintf(stderr,"\n*** Stopping up processes ...");

	signal(SIGINT,procont);

	for (proc = u_list ; proc != NULL ; proc = proc->next)
	{
		if ( proc->pid == our_pid ||
			proc->pid == our_ppid)continue;

#ifdef	DEBUG
		if (x_opt)
		{
			if (proc->special_flag)
				printf("Special shutdown of %s (%d) with %s\n",
					proc->cmd,proc->pid,proc->proc_shutdn);
			else
				printf("Stopping up process %s (%d)\n",proc->cmd,
					proc->pid);
		} else
#endif	DEBUG
		if (proc->special_flag)
			system(proc->proc_shutdn);
		else
			kill(proc->pid,SIGSTOP);
	}

	/*
	 * Now that things should be quiet, sync the disks
	 */

	sync();
	sleep(1);
	sync();
	sleep(5);

}

fixlog()
{
	unlink("/etc/nologin");
	fprintf(stderr,"*** Backup aborted ***\n");
	exit(0);
}

procont()
{
	int restart();

	restart();
	fprintf(stderr,"*** Backup aborted ***\n");
	exit(0);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'restart.c'
then
	echo shar: will not over-write existing file "'restart.c'"
else
cat << \SHAR_EOF > 'restart.c'
static char rcsid[] = "$Header: restart.c,v 1.3 86/10/14 01:34:06 scooter Exp $";

/*
 * restart
 *
 * This module controls the system restart after backup is complete
 *
 * $Log:	restart.c,v $
 * Revision 1.3  86/10/14  01:34:06  scooter
 * Added process specific startup/shutdown stuff
 * 
 *
 */

#include	<stdio.h>
#include	"backup.h"
#include	"ulist.h"
#include	<signal.h>

extern struct ulist	*u_list;
extern int		our_pid,our_ppid;

restart()
{
	FILE *fs;
	struct ulist *proc;
	

	/*
	 * Restart stopped processes
	 */

	fprintf(stderr,"\n*** Restarting processes ...");

	for (proc = u_list ; proc != NULL ; proc = proc->next)
	{
		if (proc->pid < 5 || proc->pid == our_pid ||
			proc->pid == our_ppid)continue;

#ifdef	DEBUG
		if (x_opt)
			if (proc->special_flag)
				printf("restarting %s with %s\n",
					proc->cmd,proc->proc_restart);
			else
				printf("starting process %d\n",proc->pid);
		else
#endif	DEBUG
		if (proc->special_flag)
			system(proc->proc_restart);
		else
			kill(proc->pid,SIGCONT);
	}

	unlink("/etc/nologin");		/* Make sure users can log in */

	unlink("/dev/printer");		/* Restart all of the printers */
	system("/usr/lib/lpd");		/* Start the deaemon */

	return(0);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'scanner.l'
then
	echo shar: will not over-write existing file "'scanner.l'"
else
cat << \SHAR_EOF > 'scanner.l'
%{
/* $Header: scanner.l,v 1.3 85/04/08 09:59:35 scooter Exp $ */

#include	"y.tab.h"

#undef  input
#undef  output
#undef  unput
#define allprint(c) (putchar(c))
#define sprint(str) (printf("%s",str))
#define output(c) (putchar(c))
#define input() (yytchar=yysptr>yysbuf?U(*--yysptr):getnextchar())
#define unput(c) (*yysptr++=(c))
#define yywrap() 1

%}

star	\*
dash	\-
filesys	\/[0-9a-zA-Z/]*
slash	\/
space	[ \t] 
nu	[0-9][0-9]*
arb	[a-zA-Z]*
string	\"[^"]*\"
comm	\#.*
quote	\"
comma	\,
newline [\n]
a	[aA]
b	[bB]
c	[cC]
d	[dD]
e	[eE]
f	[fF]
g	[gG]
h	[hH]
i	[iI]
j	[jJ]
k	[kK]
l	[lL]
m	[mM]
n	[nN]
o	[oO]
p	[pP]
q	[qQ]
r	[rR]
s	[sS]
t	[tT]
u	[uU]
v	[vV]
w	[wW]
x	[xX]
y	[yY]
z	[zZ]

%%

{comm}{arb}		{return(COMMENT);}
{string}		{strcpy(string,yytext);return(STRING);}
{star}{space}		{yylval=0;return(STAR);}

{nu}			{sscanf(yytext,"%d",&yylval);
			 return(NUM);}
{dash}			{return(DASH);}

{s}{u}{n}{arb}		{yylval=0;return(DAY);}
{m}{o}{n}{arb}		{yylval=1;return(DAY);}
{t}{u}{e}{arb}		{yylval=2;return(DAY);}
{w}{e}{d}{arb}		{yylval=3;return(DAY);}
{t}{h}{u}{arb}		{yylval=4;return(DAY);}
{f}{r}{i}{arb}		{yylval=5;return(DAY);}
{s}{a}{t}{arb}		{yylval=6;return(DAY);}

{j}{a}{n}{arb}		{yylval=0;return(MONTH);}
{f}{e}{b}{arb}		{yylval=1;return(MONTH);}
{m}{a}{r}{arb}		{yylval=2;return(MONTH);}
{a}{p}{r}{arb}		{yylval=3;return(MONTH);}
{m}{a}{y}{arb}		{yylval=4;return(MONTH);}
{j}{u}{n}{arb}		{yylval=5;return(MONTH);}
{j}{u}{l}{arb}		{yylval=6;return(MONTH);}
{a}{u}{g}{arb}		{yylval=7;return(MONTH);}
{s}{e}{p}{arb}		{yylval=8;return(MONTH);}
{o}{c}{t}{arb}		{yylval=9;return(MONTH);}
{n}{o}{v}{arb}		{yylval=10;return(MONTH);}
{d}{e}{c}{arb}		{yylval=11;return(MONTH);}

{filesys}		{return(FILESYS);}
{newline}		{return(NEWLINE);}
{comma}			{return(COMMA);}

[ \t,]	;
SHAR_EOF
fi # end of overwriting check
if test -f 'shutdown.c'
then
	echo shar: will not over-write existing file "'shutdown.c'"
else
cat << \SHAR_EOF > 'shutdown.c'
static char rcsid[] = "$Header: shutdown.c,v 1.1 85/04/05 17:14:09 scooter Exp $";

/*
 * shutdown
 *
 * This module controls the system shutdown message stuff.
 */

#include	<stdio.h>
#include	"backup.h"

shutdown(minutes)
int minutes;
{
	char	temp[180];
	FILE	*nlfl;

/*
 * Begin by formatting the shutdown command
 */

	sprintf(temp,"/etc/shutdown -k +%d %s",minutes,
			"System going down for system backups");

	system (temp);

/*
 * Now sleep until shutdown is complete
 */

	sleep(minutes*60 + 5);

/*
 * Since shutdown unlinks /etc/nologin when it exits, we must re-do it
 */

	nlfl = fopen("/etc/nologin","w");
	if (nlfl == NULL)
	{
		fprintf(stderr,"*** Warning: unable to disable logins\n");
	} else {
		fprintf(nlfl,"NO LOGINS: System backups in progress\n");
		fflush(nlfl);
		fclose(nlfl);
	}

}
SHAR_EOF
fi # end of overwriting check
if test -f 'ulist.h'
then
	echo shar: will not over-write existing file "'ulist.h'"
else
cat << \SHAR_EOF > 'ulist.h'
/* $Header: ulist.h,v 1.2 86/10/14 01:34:47 scooter Exp $ */
struct	ulist {
	int	pid;		/* Process id */
	int	ppid;		/* Parent process id */
	int	uid;		/* Uid of the process */
	int	stat[4];	/* The process state */
	char	cmd[40];	/* The command name */
	int	special_flag;	/* Special startup/shutdown? */
	char	proc_shutdn[80];	/* shutdown command */
	char	proc_restart[80];	/* restart command */
	struct	ulist *next;
};
SHAR_EOF
fi # end of overwriting check
if test -f 'genie_dates'
then
	echo shar: will not over-write existing file "'genie_dates'"
else
cat << \SHAR_EOF > 'genie_dates'
# Backup schedule for Genie - Genentech, Inc.
# Daily level 2's
Mon-Thu	*	*	2	/va	"Dump complete - Label tape  /va  level 2  Today's date "
Mon-Thu	*	*	2	/usr/src	"Dump complete - Label tape  /usr/src  level 2  Today's date"
Mon-Thu	*	*	2	/usr	"Dump complete - Label tape  /usr  level 2  Today's date"
Mon-Thu	*	*	2	/usr/spool	"Dump complete - Label tape  /usr/spool  level 2  Today's date"
Mon-Thu	*	*	2	/nmr	"Dump complete - Label tape  /nmr  level 2  Today's date"
# Weekly level 1's
Fri	1-5	*	1	/	"Dump complete - Label tape /  level 1  Today's date"
Fri	1-5	*	1	/va	"Dump complete - Label tape /va  level 1  Today's date"
Fri	1-5	*	1	/usr/src	"Dump complete - Label tape /usr/src  level 1  Today's date"
Fri	1-5	*	1	/usr	"Dump complete - Label tape /usr  level 1  Today's date"
Fri	1-5	*	1	/usr/spool	"Dump complete - Label tape /usr/spool  level 1  Today's date"
Fri	1-5	*	1	/nmr	"Dump complete - Label tape /nmr  level 1  Today's date"
Fri	1-5	*	1	/usr/seqdb	"Dump complete - Label tape /usr/seqdb  level 1  Today's date"
Fri	1-5	*	1	/usr/src/contrib	"Dump complete - Label tape /usr/src/contrib  level 1  Today's date"
# Monthly level 0's
Sun	1	*	0	/	"Dump complete - Label tape  root  level 0  Today's date"
Sun	1	*	0	/va	"Dump complete - Label tapes  /va  level 0  Today's date  Vol #"
Sun	1	*	0	/usr/src	"Dump complete - Label tape  /usr/src  level 0 Today's date"
Sun	1	*	0	/usr	"Dump complete - Label tapes  /usr  level 0  Today's date  Vol #"
Sun	1	*	0	/usr/spool	"Dump complete - Label tape  /usr/spool  level 0  Today's date  Vol #"
Sun	1	*	0	/nmr	"Dump complete - Label tape  /nmr  level 0  Today's date  Vol #"
SHAR_EOF
fi # end of overwriting check
if test -f 'backup_dates'
then
	echo shar: will not over-write existing file "'backup_dates'"
else
cat << \SHAR_EOF > 'backup_dates'
# Backup schedule for Genie - Genentech, Inc.
# Daily level 9's
Tue,Fri	*	*	9	/va	"/va dump complete"
Tue,Wed,Fri	*	*	9	/vb	"/vb dump complete"
Tue,Wed,Fri	*	*	9	/vc	"/vc dump complete"
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list