xref: /csrg-svn/sbin/savecore/savecore.c (revision 22013)
1*22013Sdist /*
2*22013Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22013Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22013Sdist  * specifies the terms and conditions for redistribution.
5*22013Sdist  */
6*22013Sdist 
711201Ssam #ifndef lint
8*22013Sdist char copyright[] =
9*22013Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10*22013Sdist  All rights reserved.\n";
11*22013Sdist #endif not lint
1211201Ssam 
13*22013Sdist #ifndef lint
14*22013Sdist static char sccsid[] = "@(#)savecore.c	5.1 (Berkeley) 06/04/85";
15*22013Sdist #endif not lint
16*22013Sdist 
173454Sroot /*
183611Sroot  * savecore
193454Sroot  */
2016727Sralph 
213454Sroot #include <stdio.h>
223454Sroot #include <nlist.h>
233454Sroot #include <sys/param.h>
243454Sroot #include <sys/dir.h>
253454Sroot #include <sys/stat.h>
268846Smckusick #include <sys/fs.h>
2713607Ssam #include <sys/time.h>
283454Sroot 
293611Sroot #define	DAY	(60L*60L*24L)
303611Sroot #define	LEEWAY	(3*DAY)
313611Sroot 
323611Sroot #define eq(a,b) (!strcmp(a,b))
3311201Ssam #ifdef vax
343611Sroot #define ok(number) ((number)&0x7fffffff)
3511201Ssam #else
3611201Ssam #define ok(number) (number)
3711201Ssam #endif
383611Sroot 
393454Sroot #define SHUTDOWNLOG "/usr/adm/shutdownlog"
403454Sroot 
4116727Sralph struct nlist current_nl[] = {	/* namelist for currently running system */
423454Sroot #define X_DUMPDEV	0
433454Sroot 	{ "_dumpdev" },
443454Sroot #define X_DUMPLO	1
453454Sroot 	{ "_dumplo" },
463454Sroot #define X_TIME		2
473454Sroot 	{ "_time" },
4811201Ssam #define	X_DUMPSIZE	3
4911201Ssam 	{ "_dumpsize" },
503454Sroot #define X_VERSION	4
513454Sroot 	{ "_version" },
523454Sroot #define X_PANICSTR	5
533454Sroot 	{ "_panicstr" },
5411201Ssam #define	X_DUMPMAG	6
5511201Ssam 	{ "_dumpmag" },
5611201Ssam 	{ "" },
573454Sroot };
583454Sroot 
5916727Sralph struct nlist dump_nl[] = {	/* name list for dumped system */
6016727Sralph 	{ "_dumpdev" },		/* entries MUST be the same as */
6116727Sralph 	{ "_dumplo" },		/*	those in current_nl[]  */
6216727Sralph 	{ "_time" },
6316727Sralph 	{ "_dumpsize" },
6416727Sralph 	{ "_version" },
6516727Sralph 	{ "_panicstr" },
6616727Sralph 	{ "_dumpmag" },
6716727Sralph 	{ "" },
6816727Sralph };
6916727Sralph 
703807Sroot char	*system;
713611Sroot char	*dirname;			/* directory to save dumps in */
723611Sroot char	*ddname;			/* name of dump device */
733611Sroot char	*find_dev();
743611Sroot dev_t	dumpdev;			/* dump device */
753611Sroot time_t	dumptime;			/* time the dump was taken */
763611Sroot int	dumplo;				/* where dump starts on dumpdev */
7711201Ssam int	dumpsize;			/* amount of memory dumped */
7811201Ssam int	dumpmag;			/* magic number in dump */
793611Sroot time_t	now;				/* current date */
803611Sroot char	*path();
813611Sroot unsigned malloc();
823611Sroot char	*ctime();
833611Sroot char	vers[80];
843611Sroot char	core_vers[80];
853611Sroot char	panic_mesg[80];
863611Sroot int	panicstr;
873611Sroot off_t	lseek();
883611Sroot off_t	Lseek();
8916727Sralph int	Verbose;
903454Sroot 
913454Sroot main(argc, argv)
923611Sroot 	char **argv;
933611Sroot 	int argc;
943454Sroot {
953611Sroot 
9616727Sralph 	while ((argc > 1) && (argv[1][0] == '-')) {
9716727Sralph 		switch (argv[1][1]) {
9816727Sralph 		case 'v':
9921815Skarels 		case 'd':
10016727Sralph 			Verbose = 1;
10116727Sralph 			break;
10216727Sralph 		default:
10316727Sralph 			fprintf(stderr, "savecore: illegal flag -%c\n",
10416727Sralph 				argv[1][1]);
10516727Sralph 			fprintf(stderr,
10616727Sralph 				"usage: savecore [-v] dirname [ system ]\n");
10716727Sralph 			exit(1);
10816727Sralph 		}
10916727Sralph 		argc--;
11016727Sralph 		argv++;
11116727Sralph 	}
11216727Sralph 
1133807Sroot 	if (argc != 2 && argc != 3) {
11416727Sralph 		fprintf(stderr, "usage: savecore [-v] dirname [ system ]\n");
1153454Sroot 		exit(1);
1163454Sroot 	}
1173454Sroot 	dirname = argv[1];
1183807Sroot 	if (argc == 3)
1193807Sroot 		system = argv[2];
1203611Sroot 	if (access(dirname, 2) < 0) {
1213454Sroot 		perror(dirname);
1223611Sroot 		exit(1);
1233454Sroot 	}
1243454Sroot 	read_kmem();
1258846Smckusick 	if (dump_exists()) {
1268846Smckusick 		(void) time(&now);
1278846Smckusick 		check_kmem();
1288846Smckusick 		log_entry();
1298846Smckusick 		if (get_crashtime() && check_space()) {
1308846Smckusick 			save_core();
1318846Smckusick 			clear_dump();
13216727Sralph 		} else {
13316727Sralph 			if (Verbose)
13416727Sralph 				fprintf(stderr, "No space or time\n");
1358846Smckusick 			exit(1);
13616727Sralph 		}
1378846Smckusick 	}
13816727Sralph 	else if (Verbose) {
13916727Sralph 		fprintf(stderr, "No dump exists\n");
14016727Sralph 	}
1418846Smckusick 	return 0;
1423454Sroot }
1433454Sroot 
1448846Smckusick int
1458846Smckusick dump_exists()
1468846Smckusick {
1478846Smckusick 	register int dumpfd;
1488846Smckusick 	int word;
1498846Smckusick 
1508846Smckusick 	dumpfd = Open(ddname, 0);
15116727Sralph 	Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), 0);
1528846Smckusick 	Read(dumpfd, (char *)&word, sizeof word);
1538846Smckusick 	close(dumpfd);
15416727Sralph 	if (Verbose && (word != dumpmag)) {
15516727Sralph 		printf("dumplo = %d (%d bytes)\n", dumplo/512, dumplo);
15616727Sralph 		printf("magic number mismatch: %x != %x\n", word, dumpmag);
15716727Sralph 	}
15811201Ssam 	return (word == dumpmag);
1598846Smckusick }
1608846Smckusick 
1618846Smckusick clear_dump()
1628846Smckusick {
1638846Smckusick 	register int dumpfd;
1648846Smckusick 	int zero = 0;
1658846Smckusick 
1668846Smckusick 	dumpfd = Open(ddname, 1);
16716727Sralph 	Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), 0);
1688846Smckusick 	Write(dumpfd, (char *)&zero, sizeof zero);
1698846Smckusick 	close(dumpfd);
1708846Smckusick }
1718846Smckusick 
1723611Sroot char *
1733611Sroot find_dev(dev, type)
1743611Sroot 	register dev_t dev;
1753611Sroot 	register int type;
1763454Sroot {
1778846Smckusick 	register DIR *dfd = opendir("/dev");
1788846Smckusick 	struct direct *dir;
1793454Sroot 	struct stat statb;
1808846Smckusick 	static char devname[MAXPATHLEN + 1];
1813521Sroot 	char *dp;
1823454Sroot 
1833454Sroot 	strcpy(devname, "/dev/");
1848846Smckusick 	while ((dir = readdir(dfd))) {
1858846Smckusick 		strcpy(devname + 5, dir->d_name);
1863611Sroot 		if (stat(devname, &statb)) {
1873454Sroot 			perror(devname);
1883611Sroot 			continue;
1893454Sroot 		}
1903611Sroot 		if ((statb.st_mode&S_IFMT) != type)
1913611Sroot 			continue;
1923611Sroot 		if (dev == statb.st_rdev) {
1938846Smckusick 			closedir(dfd);
1943611Sroot 			dp = (char *)malloc(strlen(devname)+1);
1953611Sroot 			strcpy(dp, devname);
1963611Sroot 			return dp;
1973611Sroot 		}
1983454Sroot 	}
1998846Smckusick 	closedir(dfd);
20011201Ssam 	fprintf(stderr, "savecore: Can't find device %d,%d\n",
20111201Ssam 		major(dev), minor(dev));
2023611Sroot 	exit(1);
2033611Sroot 	/*NOTREACHED*/
2043454Sroot }
2053454Sroot 
2063454Sroot read_kmem()
2073454Sroot {
2083454Sroot 	int kmem;
2093454Sroot 	FILE *fp;
2103454Sroot 	register char *cp;
21116727Sralph 	char *dump_sys;
21216727Sralph 
21316727Sralph 	dump_sys = system ? system : "/vmunix";
2143454Sroot 
21516727Sralph 	nlist("/vmunix", current_nl);
21616727Sralph 	nlist(dump_sys, dump_nl);
21716727Sralph 
21816727Sralph 	/*
21916727Sralph 	 * Some names we need for the currently running system,
22016727Sralph 	 * others for the system that was running when the dump was made.
22116727Sralph 	 * The values obtained from the current system are used
22216727Sralph 	 * to look for things in /dev/kmem that cannot be found
22316727Sralph 	 * in the dump_sys namelist, but are presumed to be the same
22416727Sralph 	 * (since the disk partitions are probably the same!)
22516727Sralph 	 */
22616727Sralph 	if (current_nl[X_DUMPDEV].n_value == 0) {
22711201Ssam 		fprintf(stderr, "savecore: /vmunix: dumpdev not in namelist\n");
2283611Sroot 		exit(1);
2293454Sroot 	}
23016727Sralph 	if (current_nl[X_DUMPLO].n_value == 0) {
23111201Ssam 		fprintf(stderr, "savecore: /vmunix: dumplo not in namelist\n");
2323611Sroot 		exit(1);
2333454Sroot 	}
23416727Sralph 	if (dump_nl[X_TIME].n_value == 0) {
23516727Sralph 		fprintf(stderr, "savecore: %s: time not in namelist\n",
23616727Sralph 				dump_sys);
2373611Sroot 		exit(1);
2383454Sroot 	}
23916727Sralph 	if (dump_nl[X_DUMPSIZE].n_value == 0) {
24016727Sralph 		fprintf(stderr, "savecore: %s: dumpsize not in namelist\n",
24116727Sralph 				dump_sys);
2423611Sroot 		exit(1);
2433454Sroot 	}
24416727Sralph 	/* we need VERSION in both images */
24516727Sralph 	if (current_nl[X_VERSION].n_value == 0) {
24616727Sralph 		fprintf(stderr, "savecore: /vmunix: version not in namelist\n",
24716727Sralph 				dump_sys);
2483611Sroot 		exit(1);
2493454Sroot 	}
25016727Sralph 	if (dump_nl[X_VERSION].n_value == 0) {
25116727Sralph 		fprintf(stderr, "savecore: %s: version not in namelist\n",
25216727Sralph 				dump_sys);
2533611Sroot 		exit(1);
2543454Sroot 	}
25516727Sralph 	if (dump_nl[X_PANICSTR].n_value == 0) {
25616727Sralph 		fprintf(stderr, "savecore: %s: panicstr not in namelist\n",
25716727Sralph 				dump_sys);
25816727Sralph 		exit(1);
25916727Sralph 	}
26016727Sralph 	/* we need DUMPMAG in both images */
26116727Sralph 	if (current_nl[X_DUMPMAG].n_value == 0) {
26211201Ssam 		fprintf(stderr, "savecore: /vmunix: dumpmag not in namelist\n");
2638846Smckusick 		exit(1);
2648846Smckusick 	}
26516727Sralph 	if (dump_nl[X_DUMPMAG].n_value == 0) {
26616727Sralph 		fprintf(stderr, "savecore: %s: dumpmag not in namelist\n",
26716727Sralph 				dump_sys);
26816727Sralph 		exit(1);
26916727Sralph 	}
2703454Sroot 	kmem = Open("/dev/kmem", 0);
27116727Sralph 	Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, 0);
27211201Ssam 	Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
27316727Sralph 	Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, 0);
27411201Ssam 	Read(kmem, (char *)&dumplo, sizeof (dumplo));
27516727Sralph 	Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, 0);
27611201Ssam 	Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
2773454Sroot 	dumplo *= 512L;
2783454Sroot 	ddname = find_dev(dumpdev, S_IFBLK);
2793611Sroot 	if ((fp = fdopen(kmem, "r")) == NULL) {
28011201Ssam 		fprintf(stderr, "savecore: Couldn't fdopen kmem\n");
2813611Sroot 		exit(1);
2823454Sroot 	}
2833807Sroot 	if (system)
2843807Sroot 		return;
28516727Sralph 	fseek(fp, (long)current_nl[X_VERSION].n_value, 0);
2863454Sroot 	fgets(vers, sizeof vers, fp);
2873454Sroot 	fclose(fp);
2888846Smckusick }
2898846Smckusick 
29011635Ssam check_kmem()
29111635Ssam {
2928846Smckusick 	FILE *fp;
2938846Smckusick 	register char *cp;
2948846Smckusick 
2953611Sroot 	if ((fp = fopen(ddname, "r")) == NULL) {
2963454Sroot 		perror(ddname);
2973611Sroot 		exit(1);
2983454Sroot 	}
29916727Sralph 	fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), 0);
3003454Sroot 	fgets(core_vers, sizeof core_vers, fp);
3013454Sroot 	fclose(fp);
30216727Sralph 	if (!eq(vers, core_vers) && (system == 0))
30311201Ssam 		fprintf(stderr,
30411201Ssam 		   "savecore: Warning: vmunix version mismatch:\n\t%sand\n\t%s",
30511201Ssam 		   vers, core_vers);
3063611Sroot 	fp = fopen(ddname, "r");
30716727Sralph 	fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), 0);
3083611Sroot 	fread((char *)&panicstr, sizeof panicstr, 1, fp);
3093611Sroot 	if (panicstr) {
3103611Sroot 		fseek(fp, dumplo + ok(panicstr), 0);
3113454Sroot 		cp = panic_mesg;
3123454Sroot 		do
3133454Sroot 			*cp = getc(fp);
3143454Sroot 		while (*cp++);
3153454Sroot 	}
3163611Sroot 	fclose(fp);
3173807Sroot }
3183454Sroot 
3193611Sroot get_crashtime()
3203611Sroot {
3213454Sroot 	int dumpfd;
3223483Sroot 	time_t clobber = (time_t)0;
3233454Sroot 
3248846Smckusick 	dumpfd = Open(ddname, 0);
32516727Sralph 	Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), 0);
3263611Sroot 	Read(dumpfd, (char *)&dumptime, sizeof dumptime);
3273454Sroot 	close(dumpfd);
32816727Sralph 	if (dumptime == 0) {
32916727Sralph 		if (Verbose)
33016727Sralph 			printf("dump time not found\n");
33111201Ssam 		return (0);
33216727Sralph 	}
3333454Sroot 	printf("System went down at %s", ctime(&dumptime));
3343454Sroot 	if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
3353454Sroot 		printf("Dump time is unreasonable\n");
33611201Ssam 		return (0);
3373454Sroot 	}
33811201Ssam 	return (1);
3393454Sroot }
3403454Sroot 
3413611Sroot char *
3423611Sroot path(file)
3433611Sroot 	char *file;
3443454Sroot {
3453611Sroot 	register char *cp = (char *)malloc(strlen(file) + strlen(dirname) + 2);
3463454Sroot 
3473611Sroot 	(void) strcpy(cp, dirname);
3483611Sroot 	(void) strcat(cp, "/");
3493611Sroot 	(void) strcat(cp, file);
35011201Ssam 	return (cp);
3513454Sroot }
3523454Sroot 
3533454Sroot check_space()
3543454Sroot {
3553454Sroot 	struct stat dsb;
3563454Sroot 	register char *ddev;
35712215Ssam 	int dfd, spacefree;
3588847Smckusick 	struct fs fs;
3593454Sroot 
3603611Sroot 	if (stat(dirname, &dsb) < 0) {
3613611Sroot 		perror(dirname);
3623611Sroot 		exit(1);
3633611Sroot 	}
3643454Sroot 	ddev = find_dev(dsb.st_dev, S_IFBLK);
3653454Sroot 	dfd = Open(ddev, 0);
3668847Smckusick 	Lseek(dfd, (long)(SBLOCK * DEV_BSIZE), 0);
3678847Smckusick 	Read(dfd, (char *)&fs, sizeof fs);
3683454Sroot 	close(dfd);
36912215Ssam 	spacefree = fs.fs_cstotal.cs_nbfree * fs.fs_bsize / 1024;
37012215Ssam 	if (read_number("minfree") > spacefree) {
37111201Ssam 		fprintf(stderr,
37211201Ssam 		   "savecore: Dump omitted, not enough space on device\n");
3733611Sroot 		return (0);
3743454Sroot 	}
3758847Smckusick 	if (fs.fs_cstotal.cs_nbfree * fs.fs_frag + fs.fs_cstotal.cs_nffree <
3768847Smckusick 	    fs.fs_dsize * fs.fs_minfree / 100)
3778847Smckusick 		fprintf(stderr,
3788847Smckusick 			"Dump performed, but free space threshold crossed\n");
3793611Sroot 	return (1);
3803454Sroot }
3813454Sroot 
3823454Sroot read_number(fn)
3833611Sroot 	char *fn;
3843454Sroot {
3853454Sroot 	char lin[80];
3863454Sroot 	register FILE *fp;
3873454Sroot 
3883454Sroot 	if ((fp = fopen(path(fn), "r")) == NULL)
38911201Ssam 		return (0);
3903611Sroot 	if (fgets(lin, 80, fp) == NULL) {
3913611Sroot 		fclose(fp);
39211201Ssam 		return (0);
3933454Sroot 	}
3943611Sroot 	fclose(fp);
39511201Ssam 	return (atoi(lin));
3963454Sroot }
3973454Sroot 
3983454Sroot save_core()
3993454Sroot {
4003454Sroot 	register int n;
4013611Sroot 	char buffer[32*NBPG];
4023454Sroot 	register char *cp = buffer;
4033454Sroot 	register int ifd, ofd, bounds;
4043454Sroot 	register FILE *fp;
4053454Sroot 
4063454Sroot 	bounds = read_number("bounds");
4073807Sroot 	ifd = Open(system?system:"/vmunix", 0);
4088846Smckusick 	sprintf(cp, "vmunix.%d", bounds);
4098846Smckusick 	ofd = Create(path(cp), 0644);
4103454Sroot 	while((n = Read(ifd, cp, BUFSIZ)) > 0)
4113454Sroot 		Write(ofd, cp, n);
4123454Sroot 	close(ifd);
4133454Sroot 	close(ofd);
4143454Sroot 	ifd = Open(ddname, 0);
41516727Sralph 	Lseek(ifd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), 0);
41611635Ssam 	Read(ifd, (char *)&dumpsize, sizeof (dumpsize));
4178846Smckusick 	sprintf(cp, "vmcore.%d", bounds);
4188846Smckusick 	ofd = Create(path(cp), 0644);
4193611Sroot 	Lseek(ifd, (off_t)dumplo, 0);
42011201Ssam 	printf("Saving %d bytes of image in vmcore.%d\n", NBPG*dumpsize,
42111201Ssam 		bounds);
42211201Ssam 	while (dumpsize > 0) {
42311201Ssam 		n = Read(ifd, cp, (dumpsize > 32 ? 32 : dumpsize) * NBPG);
4243454Sroot 		Write(ofd, cp, n);
42511201Ssam 		dumpsize -= n/NBPG;
4263454Sroot 	}
4273454Sroot 	close(ifd);
4283454Sroot 	close(ofd);
4293454Sroot 	fp = fopen(path("bounds"), "w");
4303454Sroot 	fprintf(fp, "%d\n", bounds+1);
4313454Sroot 	fclose(fp);
4323454Sroot }
4333454Sroot 
4343454Sroot char *days[] = {
4353454Sroot 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
4363454Sroot };
4373454Sroot 
4383454Sroot char *months[] = {
4393454Sroot 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
4403454Sroot 	"Oct", "Nov", "Dec"
4413454Sroot };
4423454Sroot 
4433454Sroot log_entry()
4443454Sroot {
4453454Sroot 	FILE *fp;
4463454Sroot 	struct tm *tm, *localtime();
4473454Sroot 
4483454Sroot 	tm = localtime(&now);
4493611Sroot 	fp = fopen("/usr/adm/shutdownlog", "a");
4503611Sroot 	if (fp == 0)
4513611Sroot 		return;
4523454Sroot 	fseek(fp, 0L, 2);
4533454Sroot 	fprintf(fp, "%02d:%02d  %s %s %2d, %4d.  Reboot", tm->tm_hour,
4543454Sroot 		tm->tm_min, days[tm->tm_wday], months[tm->tm_mon],
4553454Sroot 		tm->tm_mday, tm->tm_year + 1900);
4563454Sroot 	if (panicstr)
4573611Sroot 		fprintf(fp, " after panic: %s\n", panic_mesg);
4583454Sroot 	else
4593454Sroot 		putc('\n', fp);
4603454Sroot 	fclose(fp);
4613454Sroot }
4623611Sroot 
4633611Sroot /*
4643611Sroot  * Versions of std routines that exit on error.
4653611Sroot  */
4663611Sroot 
4673611Sroot Open(name, rw)
4683611Sroot 	char *name;
4693611Sroot 	int rw;
4703611Sroot {
4713611Sroot 	int fd;
4723611Sroot 
4733611Sroot 	if ((fd = open(name, rw)) < 0) {
4743611Sroot 		perror(name);
4753611Sroot 		exit(1);
4763611Sroot 	}
4773611Sroot 	return fd;
4783611Sroot }
4793611Sroot 
4803611Sroot Read(fd, buff, size)
4813611Sroot 	int fd, size;
4823611Sroot 	char *buff;
4833611Sroot {
4843611Sroot 	int ret;
4853611Sroot 
4863611Sroot 	if ((ret = read(fd, buff, size)) < 0) {
4873611Sroot 		perror("read");
4883611Sroot 		exit(1);
4893611Sroot 	}
4903611Sroot 	return ret;
4913611Sroot }
4923611Sroot 
4933611Sroot off_t
4943611Sroot Lseek(fd, off, flag)
4953611Sroot 	int fd, flag;
4963611Sroot 	long off;
4973611Sroot {
4983611Sroot 	long ret;
4993611Sroot 
5003611Sroot 	if ((ret = lseek(fd, off, flag)) == -1L) {
5013611Sroot 		perror("lseek");
5023611Sroot 		exit(1);
5033611Sroot 	}
5043611Sroot 	return ret;
5053611Sroot }
5063611Sroot 
5073611Sroot Create(file, mode)
5083611Sroot 	char *file;
5093611Sroot 	int mode;
5103611Sroot {
5113611Sroot 	register int fd;
5123611Sroot 
5133611Sroot 	if ((fd = creat(file, mode)) < 0) {
5143611Sroot 		perror(file);
5153611Sroot 		exit(1);
5163611Sroot 	}
5173611Sroot 	return fd;
5183611Sroot }
5193611Sroot 
5203611Sroot Write(fd, buf, size)
5213611Sroot 	int fd, size;
5223611Sroot 	char *buf;
5233611Sroot {
5243611Sroot 
5253611Sroot 	if (write(fd, buf, size) < size) {
5263611Sroot 		perror("write");
5273611Sroot 		exit(1);
5283611Sroot 	}
5293611Sroot }
530