154095Sbostic /*-
261545Sbostic * Copyright (c) 1986, 1992, 1993
361545Sbostic * The Regents of the University of California. All rights reserved.
436188Sbostic *
542712Sbostic * %sccs.include.redist.c%
622013Sdist */
722013Sdist
811201Ssam #ifndef lint
961545Sbostic static char copyright[] =
1061545Sbostic "@(#) Copyright (c) 1986, 1992, 1993\n\
1161545Sbostic The Regents of the University of California. All rights reserved.\n";
1236188Sbostic #endif /* not lint */
1311201Ssam
1422013Sdist #ifndef lint
15*69006Sbostic static char sccsid[] = "@(#)savecore.c 8.5 (Berkeley) 04/28/95";
1636188Sbostic #endif /* not lint */
1722013Sdist
183454Sroot #include <sys/param.h>
1956984Sbostic #include <sys/stat.h>
2040574Smckusick #include <sys/mount.h>
2154095Sbostic #include <sys/syslog.h>
2213607Ssam #include <sys/time.h>
2354095Sbostic
2456984Sbostic #include <dirent.h>
2554095Sbostic #include <errno.h>
2656984Sbostic #include <fcntl.h>
2754095Sbostic #include <nlist.h>
2854095Sbostic #include <paths.h>
2937298Sbostic #include <stdio.h>
3054095Sbostic #include <stdlib.h>
3154095Sbostic #include <string.h>
3256984Sbostic #include <tzfile.h>
3353830Smckusick #include <unistd.h>
343454Sroot
3552551Storek #define ok(number) ((number) - KERNBASE)
363611Sroot
3756984Sbostic struct nlist current_nl[] = { /* Namelist for currently running system. */
383454Sroot #define X_DUMPDEV 0
393454Sroot { "_dumpdev" },
403454Sroot #define X_DUMPLO 1
413454Sroot { "_dumplo" },
423454Sroot #define X_TIME 2
433454Sroot { "_time" },
4411201Ssam #define X_DUMPSIZE 3
4511201Ssam { "_dumpsize" },
463454Sroot #define X_VERSION 4
473454Sroot { "_version" },
483454Sroot #define X_PANICSTR 5
493454Sroot { "_panicstr" },
5011201Ssam #define X_DUMPMAG 6
5111201Ssam { "_dumpmag" },
5211201Ssam { "" },
533454Sroot };
5456984Sbostic int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
5556984Sbostic int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
563454Sroot
5756984Sbostic struct nlist dump_nl[] = { /* Name list for dumped system. */
5856984Sbostic { "_dumpdev" }, /* Entries MUST be the same as */
5956984Sbostic { "_dumplo" }, /* those in current_nl[]. */
6016727Sralph { "_time" },
6116727Sralph { "_dumpsize" },
6216727Sralph { "_version" },
6316727Sralph { "_panicstr" },
6416727Sralph { "_dumpmag" },
6516727Sralph { "" },
6616727Sralph };
6716727Sralph
6856984Sbostic /* Types match kernel declarations. */
6956984Sbostic long dumplo; /* where dump starts on dumpdev */
7056984Sbostic int dumpmag; /* magic number in dump */
7156984Sbostic int dumpsize; /* amount of memory dumped */
7256984Sbostic
7354095Sbostic char *vmunix;
743611Sroot char *dirname; /* directory to save dumps in */
753611Sroot char *ddname; /* name of dump device */
7656984Sbostic dev_t dumpdev; /* dump device */
7738680Skarels int dumpfd; /* read/write descriptor on block dev */
783611Sroot time_t now; /* current date */
7956984Sbostic char panic_mesg[1024];
803611Sroot int panicstr;
8156984Sbostic char vers[1024];
823454Sroot
8356984Sbostic int clear, compress, force, verbose; /* flags */
8456984Sbostic
8556984Sbostic void check_kmem __P((void));
8656984Sbostic int check_space __P((void));
8756984Sbostic void clear_dump __P((void));
8856984Sbostic int Create __P((char *, int));
8956984Sbostic int dump_exists __P((void));
9054288Sbostic char *find_dev __P((dev_t, int));
9156984Sbostic int get_crashtime __P((void));
9256984Sbostic void kmem_setup __P((void));
9356984Sbostic void log __P((int, char *, ...));
9456984Sbostic void Lseek __P((int, off_t, int));
9556984Sbostic int Open __P((char *, int rw));
9656984Sbostic int Read __P((int, void *, int));
9754095Sbostic char *rawname __P((char *s));
9856984Sbostic void save_core __P((void));
9956984Sbostic void usage __P((void));
10056984Sbostic void Write __P((int, void *, int));
10154095Sbostic
10254095Sbostic int
main(argc,argv)1033454Sroot main(argc, argv)
1043611Sroot int argc;
10554095Sbostic char *argv[];
1063454Sroot {
10747827Sbostic int ch;
1083611Sroot
10956984Sbostic openlog("savecore", LOG_PERROR, LOG_DAEMON);
11056984Sbostic
11168872Smckusick while ((ch = getopt(argc, argv, "cdfN:vz")) != EOF)
11247827Sbostic switch(ch) {
11347827Sbostic case 'c':
11447827Sbostic clear = 1;
11530356Skarels break;
11656984Sbostic case 'd': /* Not documented. */
11716727Sralph case 'v':
11847827Sbostic verbose = 1;
11916727Sralph break;
12047827Sbostic case 'f':
12147827Sbostic force = 1;
12230693Skarels break;
12356986Sbostic case 'N':
12456986Sbostic vmunix = optarg;
12556986Sbostic break;
12656984Sbostic case 'z':
12756984Sbostic compress = 1;
12856984Sbostic break;
12947827Sbostic case '?':
13016727Sralph default:
13147827Sbostic usage();
13216727Sralph }
13347827Sbostic argc -= optind;
13447827Sbostic argv += optind;
13547827Sbostic
13647827Sbostic if (!clear) {
13747827Sbostic if (argc != 1 && argc != 2)
13847827Sbostic usage();
13947827Sbostic dirname = argv[0];
14016727Sralph }
14126234Ssam if (argc == 2)
14254095Sbostic vmunix = argv[1];
14347827Sbostic
14456984Sbostic (void)time(&now);
14556984Sbostic kmem_setup();
14647827Sbostic
14730693Skarels if (clear) {
14830693Skarels clear_dump();
14930693Skarels exit(0);
15030693Skarels }
15156984Sbostic
15256984Sbostic if (!dump_exists() && !force)
15356984Sbostic exit(1);
15456984Sbostic
15526234Ssam check_kmem();
15656984Sbostic
15728034Seric if (panicstr)
15856984Sbostic syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg);
15928034Seric else
16056984Sbostic syslog(LOG_ALERT, "reboot");
16147827Sbostic
16230356Skarels if ((!get_crashtime() || !check_space()) && !force)
16326234Ssam exit(1);
16456984Sbostic
16556984Sbostic save_core();
16656984Sbostic
16726234Ssam clear_dump();
16826234Ssam exit(0);
1693454Sroot }
1703454Sroot
17154095Sbostic void
kmem_setup()17256984Sbostic kmem_setup()
1738846Smckusick {
1743454Sroot FILE *fp;
17554095Sbostic int kmem, i;
17616727Sralph char *dump_sys;
17716727Sralph
17816727Sralph /*
17956984Sbostic * Some names we need for the currently running system, others for
18056984Sbostic * the system that was running when the dump was made. The values
18156984Sbostic * obtained from the current system are used to look for things in
18256984Sbostic * /dev/kmem that cannot be found in the dump_sys namelist, but are
18356984Sbostic * presumed to be the same (since the disk partitions are probably
18456984Sbostic * the same!)
18516727Sralph */
18656984Sbostic if ((nlist(_PATH_UNIX, current_nl)) == -1)
18756984Sbostic syslog(LOG_ERR, "%s: nlist: %s", _PATH_UNIX, strerror(errno));
18826234Ssam for (i = 0; cursyms[i] != -1; i++)
18926234Ssam if (current_nl[cursyms[i]].n_value == 0) {
19056984Sbostic syslog(LOG_ERR, "%s: %s not in namelist",
19156984Sbostic _PATH_UNIX, current_nl[cursyms[i]].n_name);
19226234Ssam exit(1);
19326234Ssam }
19456984Sbostic
19556984Sbostic dump_sys = vmunix ? vmunix : _PATH_UNIX;
19656984Sbostic if ((nlist(dump_sys, dump_nl)) == -1)
19756984Sbostic syslog(LOG_ERR, "%s: nlist: %s", dump_sys, strerror(errno));
19826234Ssam for (i = 0; dumpsyms[i] != -1; i++)
19926234Ssam if (dump_nl[dumpsyms[i]].n_value == 0) {
20056984Sbostic syslog(LOG_ERR, "%s: %s not in namelist",
20156984Sbostic dump_sys, dump_nl[dumpsyms[i]].n_name);
20226234Ssam exit(1);
20326234Ssam }
20456984Sbostic
20537298Sbostic kmem = Open(_PATH_KMEM, O_RDONLY);
20653830Smckusick Lseek(kmem, (off_t)current_nl[X_DUMPDEV].n_value, L_SET);
20756984Sbostic (void)Read(kmem, &dumpdev, sizeof(dumpdev));
20865317Sbostic if (dumpdev == NODEV) {
20965317Sbostic syslog(LOG_WARNING, "no core dump (no dumpdev)");
21065317Sbostic exit(1);
21165317Sbostic }
21253830Smckusick Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, L_SET);
21356984Sbostic (void)Read(kmem, &dumplo, sizeof(dumplo));
21447827Sbostic if (verbose)
21556984Sbostic (void)printf("dumplo = %d (%d * %d)\n",
21656984Sbostic dumplo, dumplo/DEV_BSIZE, DEV_BSIZE);
21753830Smckusick Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET);
21856984Sbostic (void)Read(kmem, &dumpmag, sizeof(dumpmag));
21924646Sbloom dumplo *= DEV_BSIZE;
2203454Sroot ddname = find_dev(dumpdev, S_IFBLK);
22138680Skarels dumpfd = Open(ddname, O_RDWR);
22226234Ssam fp = fdopen(kmem, "r");
22326234Ssam if (fp == NULL) {
22456984Sbostic syslog(LOG_ERR, "%s: fdopen: %m", _PATH_KMEM);
2253611Sroot exit(1);
2263454Sroot }
22754095Sbostic if (vmunix)
2283807Sroot return;
22956984Sbostic (void)fseek(fp, (off_t)current_nl[X_VERSION].n_value, L_SET);
23056984Sbostic (void)fgets(vers, sizeof(vers), fp);
23156984Sbostic
23256984Sbostic /* Don't fclose(fp), we use dumpfd later. */
2338846Smckusick }
2348846Smckusick
23554095Sbostic void
check_kmem()23611635Ssam check_kmem()
23711635Ssam {
23856984Sbostic register char *cp;
2398846Smckusick FILE *fp;
24056984Sbostic char core_vers[1024];
2418846Smckusick
24238680Skarels fp = fdopen(dumpfd, "r");
24326234Ssam if (fp == NULL) {
24456984Sbostic syslog(LOG_ERR, "%s: fdopen: %m", ddname);
2453611Sroot exit(1);
2463454Sroot }
24756984Sbostic fseek(fp, (off_t)(dumplo + ok(dump_nl[X_VERSION].n_value)), L_SET);
24856984Sbostic fgets(core_vers, sizeof(core_vers), fp);
24956984Sbostic if (strcmp(vers, core_vers) && vmunix == 0)
25056984Sbostic syslog(LOG_WARNING,
25156984Sbostic "warning: %s version mismatch:\n\t%s\nand\t%s\n",
25256984Sbostic _PATH_UNIX, vers, core_vers);
25356984Sbostic (void)fseek(fp,
25456984Sbostic (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
25556984Sbostic (void)fread(&panicstr, sizeof(panicstr), 1, fp);
2563611Sroot if (panicstr) {
25756984Sbostic (void)fseek(fp, dumplo + ok(panicstr), L_SET);
2583454Sroot cp = panic_mesg;
2593454Sroot do
2603454Sroot *cp = getc(fp);
26138680Skarels while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]);
2623454Sroot }
26356984Sbostic /* Don't fclose(fp), we use dumpfd later. */
2643807Sroot }
2653454Sroot
26656984Sbostic void
clear_dump()26756984Sbostic clear_dump()
26856984Sbostic {
26956984Sbostic long newdumplo;
27056984Sbostic
27156984Sbostic newdumplo = 0;
27256984Sbostic Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
27356984Sbostic Write(dumpfd, &newdumplo, sizeof(newdumplo));
27456984Sbostic }
27556984Sbostic
27654095Sbostic int
dump_exists()27756984Sbostic dump_exists()
2783611Sroot {
27956984Sbostic int newdumpmag;
2803454Sroot
28156984Sbostic Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
28256984Sbostic (void)Read(dumpfd, &newdumpmag, sizeof(newdumpmag));
28356984Sbostic if (newdumpmag != dumpmag) {
28456987Sbostic if (verbose)
28556987Sbostic syslog(LOG_WARNING, "magic number mismatch (%x != %x)",
28656987Sbostic newdumpmag, dumpmag);
28756984Sbostic syslog(LOG_WARNING, "no core dump");
28811201Ssam return (0);
28916727Sralph }
29011201Ssam return (1);
2913454Sroot }
2923454Sroot
29356984Sbostic char buf[1024 * 1024];
29456984Sbostic
29556984Sbostic void
save_core()29656984Sbostic save_core()
2973454Sroot {
29856984Sbostic register FILE *fp;
29956984Sbostic register int bounds, ifd, nr, nw, ofd;
30056984Sbostic char *rawp, path[MAXPATHLEN];
3013454Sroot
30256984Sbostic /*
30356984Sbostic * Get the current number and update the bounds file. Do the update
30456984Sbostic * now, because may fail later and don't want to overwrite anything.
30556984Sbostic */
30656984Sbostic (void)snprintf(path, sizeof(path), "%s/bounds", dirname);
30756984Sbostic if ((fp = fopen(path, "r")) == NULL)
30856984Sbostic goto err1;
30956984Sbostic if (fgets(buf, sizeof(buf), fp) == NULL) {
31056984Sbostic if (ferror(fp))
31156984Sbostic err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno));
31256984Sbostic bounds = 0;
31356984Sbostic } else
31456984Sbostic bounds = atoi(buf);
31556984Sbostic if (fp != NULL)
31656984Sbostic (void)fclose(fp);
31756984Sbostic if ((fp = fopen(path, "w")) == NULL)
31856984Sbostic syslog(LOG_ERR, "%s: %m", path);
31956984Sbostic else {
32056984Sbostic (void)fprintf(fp, "%d\n", bounds + 1);
32156984Sbostic (void)fclose(fp);
32256984Sbostic }
32356984Sbostic (void)fclose(fp);
32456984Sbostic
32556984Sbostic /* Create the core file. */
32656984Sbostic (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s",
32756984Sbostic dirname, bounds, compress ? ".Z" : "");
32856984Sbostic if (compress) {
32956984Sbostic if ((fp = zopen(path, "w", 0)) == NULL) {
33056984Sbostic syslog(LOG_ERR, "%s: %s", path, strerror(errno));
33156984Sbostic exit(1);
33256984Sbostic }
33356984Sbostic } else
33457075Sbostic ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
33556984Sbostic
33656984Sbostic /* Open the raw device. */
33756984Sbostic rawp = rawname(ddname);
33856984Sbostic if ((ifd = open(rawp, O_RDONLY)) == -1) {
33956984Sbostic syslog(LOG_WARNING, "%s: %m; using block device", rawp);
34056984Sbostic ifd = dumpfd;
34156984Sbostic }
34256984Sbostic
34356984Sbostic /* Read the dump size. */
34456984Sbostic Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
34556984Sbostic (void)Read(dumpfd, &dumpsize, sizeof(dumpsize));
34656984Sbostic
34756984Sbostic /* Seek to the start of the core. */
34856984Sbostic Lseek(ifd, (off_t)dumplo, L_SET);
34956984Sbostic
35056984Sbostic /* Copy the core file. */
35156984Sbostic dumpsize *= NBPG;
35256984Sbostic syslog(LOG_NOTICE, "writing %score to %s",
35356984Sbostic compress ? "compressed " : "", path);
35456984Sbostic for (; dumpsize > 0; dumpsize -= nr) {
35556984Sbostic (void)printf("%6dK\r", dumpsize / 1024);
35656984Sbostic (void)fflush(stdout);
35756984Sbostic nr = read(ifd, buf, MIN(dumpsize, sizeof(buf)));
35856984Sbostic if (nr <= 0) {
35956984Sbostic if (nr == 0)
36056984Sbostic syslog(LOG_WARNING,
36156984Sbostic "WARNING: EOF on dump device");
36256984Sbostic else
36356984Sbostic syslog(LOG_ERR, "%s: %m", rawp);
36456984Sbostic goto err2;
36556984Sbostic }
36656984Sbostic if (compress)
36756984Sbostic nw = fwrite(buf, 1, nr, fp);
36856984Sbostic else
36956984Sbostic nw = write(ofd, buf, nr);
37056984Sbostic if (nw != nr) {
37156984Sbostic syslog(LOG_ERR, "%s: %s",
37256984Sbostic path, strerror(nw == 0 ? EIO : errno));
37356984Sbostic err2: syslog(LOG_WARNING,
37456984Sbostic "WARNING: vmcore may be incomplete");
37556984Sbostic (void)printf("\n");
37656984Sbostic exit(1);
37756984Sbostic }
37856984Sbostic }
37956984Sbostic (void)printf("\n");
38056984Sbostic (void)close(ifd);
38156984Sbostic if (compress)
38256984Sbostic (void)fclose(fp);
38356984Sbostic else
38456984Sbostic (void)close(ofd);
38556984Sbostic
38656984Sbostic /* Copy the kernel. */
38756986Sbostic ifd = Open(vmunix ? vmunix : _PATH_UNIX, O_RDONLY);
38856984Sbostic (void)snprintf(path, sizeof(path), "%s/vmunix.%d%s",
38956984Sbostic dirname, bounds, compress ? ".Z" : "");
39056984Sbostic if (compress) {
39156984Sbostic if ((fp = zopen(path, "w", 0)) == NULL) {
39256984Sbostic syslog(LOG_ERR, "%s: %s", path, strerror(errno));
39356984Sbostic exit(1);
39456984Sbostic }
39556984Sbostic } else
39658257Smckusick ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
39756984Sbostic syslog(LOG_NOTICE, "writing %skernel to %s",
39856984Sbostic compress ? "compressed " : "", path);
39956984Sbostic while ((nr = read(ifd, buf, sizeof(buf))) > 0) {
40056984Sbostic if (compress)
40156984Sbostic nw = fwrite(buf, 1, nr, fp);
40256984Sbostic else
40356984Sbostic nw = write(ofd, buf, nr);
40456984Sbostic if (nw != nr) {
40556984Sbostic syslog(LOG_ERR, "%s: %s",
40656984Sbostic path, strerror(nw == 0 ? EIO : errno));
40756984Sbostic syslog(LOG_WARNING,
40856984Sbostic "WARNING: vmunix may be incomplete");
40956984Sbostic exit(1);
41056984Sbostic }
41156984Sbostic }
41256984Sbostic if (nr < 0) {
41356984Sbostic syslog(LOG_ERR, "%s: %s",
41456984Sbostic vmunix ? vmunix : _PATH_UNIX, strerror(errno));
41556984Sbostic syslog(LOG_WARNING,
41656984Sbostic "WARNING: vmunix may be incomplete");
41756984Sbostic exit(1);
41856984Sbostic }
41956984Sbostic if (compress)
42056984Sbostic (void)fclose(fp);
42156984Sbostic else
42256984Sbostic (void)close(ofd);
4233454Sroot }
4243454Sroot
42556984Sbostic char *
find_dev(dev,type)42656984Sbostic find_dev(dev, type)
42756984Sbostic register dev_t dev;
42856984Sbostic register int type;
4293454Sroot {
43056984Sbostic register DIR *dfd;
43156984Sbostic struct dirent *dir;
43256984Sbostic struct stat sb;
43356984Sbostic char *dp, devname[MAXPATHLEN + 1];
4343454Sroot
43556984Sbostic if ((dfd = opendir(_PATH_DEV)) == NULL) {
43656984Sbostic syslog(LOG_ERR, "%s: %s", _PATH_DEV, strerror(errno));
4373611Sroot exit(1);
4383611Sroot }
43956984Sbostic (void)strcpy(devname, _PATH_DEV);
44056984Sbostic while ((dir = readdir(dfd))) {
44156984Sbostic (void)strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name);
44265317Sbostic if (lstat(devname, &sb)) {
44356984Sbostic syslog(LOG_ERR, "%s: %s", devname, strerror(errno));
44456984Sbostic continue;
44556984Sbostic }
44656984Sbostic if ((sb.st_mode & S_IFMT) != type)
44756984Sbostic continue;
44856984Sbostic if (dev == sb.st_rdev) {
44956984Sbostic closedir(dfd);
45056984Sbostic if ((dp = strdup(devname)) == NULL) {
45156984Sbostic syslog(LOG_ERR, "%s", strerror(errno));
45256984Sbostic exit(1);
45356984Sbostic }
45456984Sbostic return (dp);
45556984Sbostic }
4563454Sroot }
45756984Sbostic closedir(dfd);
45856984Sbostic syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev));
45956984Sbostic exit(1);
4603454Sroot }
4613454Sroot
46256984Sbostic char *
rawname(s)46356984Sbostic rawname(s)
46456984Sbostic char *s;
46556984Sbostic {
46656984Sbostic char *sl, name[MAXPATHLEN];
46756984Sbostic
468*69006Sbostic if ((sl = strrchr(s, '/')) == NULL || sl[1] == '0') {
46956984Sbostic syslog(LOG_ERR,
47056984Sbostic "can't make raw dump device name from %s", s);
47156984Sbostic return (s);
47256984Sbostic }
47356984Sbostic (void)snprintf(name, sizeof(name), "%.*s/r%s", sl - s, s, sl + 1);
47456984Sbostic if ((sl = strdup(name)) == NULL) {
47556984Sbostic syslog(LOG_ERR, "%s", strerror(errno));
47656984Sbostic exit(1);
47756984Sbostic }
47856984Sbostic return (sl);
47956984Sbostic }
48056984Sbostic
48154095Sbostic int
get_crashtime()48256984Sbostic get_crashtime()
4833454Sroot {
48456984Sbostic time_t dumptime; /* Time the dump was taken. */
4853454Sroot
48656984Sbostic Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
48756984Sbostic (void)Read(dumpfd, &dumptime, sizeof(dumptime));
48856984Sbostic if (dumptime == 0) {
48956984Sbostic if (verbose)
49056984Sbostic syslog(LOG_ERR, "dump time is zero");
49111201Ssam return (0);
49256984Sbostic }
49356984Sbostic (void)printf("savecore: system went down at %s", ctime(&dumptime));
49456984Sbostic #define LEEWAY (7 * SECSPERDAY)
49556984Sbostic if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
49656984Sbostic (void)printf("dump time is unreasonable\n");
49711201Ssam return (0);
4983454Sroot }
49956984Sbostic return (1);
5003454Sroot }
5013454Sroot
50254095Sbostic int
check_space()50356984Sbostic check_space()
5043454Sroot {
5053454Sroot register FILE *fp;
50659920Storek char *tvmunix;
50759920Storek off_t minfree, spacefree, vmunixsize, needed;
50859920Storek struct stat st;
50956984Sbostic struct statfs fsbuf;
51056984Sbostic char buf[100], path[MAXPATHLEN];
5113454Sroot
51259920Storek tvmunix = vmunix ? vmunix : _PATH_UNIX;
51359920Storek if (stat(tvmunix, &st) < 0) {
51459920Storek syslog(LOG_ERR, "%s: %m", tvmunix);
51559920Storek exit(1);
51659920Storek }
51759920Storek vmunixsize = st.st_blocks * S_BLKSIZE;
51856984Sbostic if (statfs(dirname, &fsbuf) < 0) {
51956984Sbostic syslog(LOG_ERR, "%s: %m", dirname);
52056984Sbostic exit(1);
52126006Skarels }
52256986Sbostic spacefree = (fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
52356984Sbostic
52456984Sbostic (void)snprintf(path, sizeof(path), "%s/minfree", dirname);
52556984Sbostic if ((fp = fopen(path, "r")) == NULL)
52656984Sbostic minfree = 0;
52756984Sbostic else {
52856984Sbostic if (fgets(buf, sizeof(buf), fp) == NULL)
52956984Sbostic minfree = 0;
53056984Sbostic else
53156984Sbostic minfree = atoi(buf);
53256984Sbostic (void)fclose(fp);
53338680Skarels }
53456984Sbostic
53564938Shibler needed = (dumpsize + vmunixsize) / 1024;
53659920Storek if (minfree > 0 && spacefree - needed < minfree) {
53756984Sbostic syslog(LOG_WARNING,
53856984Sbostic "no dump, not enough free space on device");
53956984Sbostic return (0);
5403454Sroot }
54159920Storek if (spacefree - needed < minfree)
54256984Sbostic syslog(LOG_WARNING,
54356984Sbostic "dump performed, but free space threshold crossed");
54456984Sbostic return (1);
5453454Sroot }
5463454Sroot
54754095Sbostic int
Open(name,rw)5483611Sroot Open(name, rw)
5493611Sroot char *name;
5503611Sroot int rw;
5513611Sroot {
5523611Sroot int fd;
5533611Sroot
55456984Sbostic if ((fd = open(name, rw, 0)) < 0) {
55556984Sbostic syslog(LOG_ERR, "%s: %m", name);
5563611Sroot exit(1);
5573611Sroot }
55826234Ssam return (fd);
5593611Sroot }
5603611Sroot
56154095Sbostic int
Read(fd,bp,size)56256984Sbostic Read(fd, bp, size)
56356984Sbostic int fd, size;
56456984Sbostic void *bp;
5653611Sroot {
56656984Sbostic int nr;
5673611Sroot
56856984Sbostic nr = read(fd, bp, size);
56956984Sbostic if (nr != size) {
57056984Sbostic syslog(LOG_ERR, "read: %m");
5713611Sroot exit(1);
5723611Sroot }
57356984Sbostic return (nr);
5743611Sroot }
5753611Sroot
57653830Smckusick void
Lseek(fd,off,flag)5773611Sroot Lseek(fd, off, flag)
57856984Sbostic int fd, flag;
57953830Smckusick off_t off;
5803611Sroot {
58156984Sbostic off_t ret;
5823611Sroot
58356984Sbostic ret = lseek(fd, off, flag);
58426234Ssam if (ret == -1) {
58556984Sbostic syslog(LOG_ERR, "lseek: %m");
5863611Sroot exit(1);
5873611Sroot }
5883611Sroot }
5893611Sroot
59054095Sbostic int
Create(file,mode)5913611Sroot Create(file, mode)
5923611Sroot char *file;
5933611Sroot int mode;
5943611Sroot {
5953611Sroot register int fd;
5963611Sroot
597*69006Sbostic fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
59826234Ssam if (fd < 0) {
59956984Sbostic syslog(LOG_ERR, "%s: %m", file);
6003611Sroot exit(1);
6013611Sroot }
60226234Ssam return (fd);
6033611Sroot }
6043611Sroot
60554095Sbostic void
Write(fd,bp,size)60656984Sbostic Write(fd, bp, size)
60756984Sbostic int fd, size;
60856984Sbostic void *bp;
6093611Sroot {
61039730Skarels int n;
6113611Sroot
61256984Sbostic if ((n = write(fd, bp, size)) < size) {
61356984Sbostic syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO));
6143611Sroot exit(1);
6153611Sroot }
6163611Sroot }
61729840Ssam
61854095Sbostic void
usage()61947827Sbostic usage()
62047827Sbostic {
62156986Sbostic (void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory");
62247827Sbostic exit(1);
62347827Sbostic }
624