Commit | Line | Data |
---|---|---|
0910ad56 | 1 | /*- |
62d2933c KB |
2 | * Copyright (c) 1986, 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
5c709f29 | 4 | * |
d60d530a | 5 | * %sccs.include.redist.c% |
5ff67f98 DF |
6 | */ |
7 | ||
261f5d78 | 8 | #ifndef lint |
62d2933c KB |
9 | static char copyright[] = |
10 | "@(#) Copyright (c) 1986, 1992, 1993\n\ | |
11 | The Regents of the University of California. All rights reserved.\n"; | |
5c709f29 | 12 | #endif /* not lint */ |
5ff67f98 DF |
13 | |
14 | #ifndef lint | |
62d2933c | 15 | static char sccsid[] = "@(#)savecore.c 8.1 (Berkeley) %G%"; |
5c709f29 | 16 | #endif /* not lint */ |
261f5d78 | 17 | |
d112e9ff | 18 | #include <sys/param.h> |
d112e9ff | 19 | #include <sys/stat.h> |
2ad23575 | 20 | #include <sys/mount.h> |
a8bf8cf3 | 21 | #include <sys/syslog.h> |
0910ad56 KB |
22 | #include <sys/time.h> |
23 | ||
2a15fef8 | 24 | #include <dirent.h> |
2ad23575 KB |
25 | #include <errno.h> |
26 | #include <fcntl.h> | |
f76fd03c | 27 | #include <nlist.h> |
7abf8d65 | 28 | #include <paths.h> |
0910ad56 KB |
29 | #include <stdio.h> |
30 | #include <stdlib.h> | |
31 | #include <string.h> | |
2ad23575 | 32 | #include <tzfile.h> |
0910ad56 | 33 | #include <unistd.h> |
d112e9ff | 34 | |
0e13cc10 | 35 | #define ok(number) ((number) - KERNBASE) |
97d6da0b | 36 | |
2ad23575 | 37 | struct nlist current_nl[] = { /* Namelist for currently running system. */ |
d112e9ff BJ |
38 | #define X_DUMPDEV 0 |
39 | { "_dumpdev" }, | |
40 | #define X_DUMPLO 1 | |
41 | { "_dumplo" }, | |
42 | #define X_TIME 2 | |
43 | { "_time" }, | |
261f5d78 SL |
44 | #define X_DUMPSIZE 3 |
45 | { "_dumpsize" }, | |
d112e9ff BJ |
46 | #define X_VERSION 4 |
47 | { "_version" }, | |
48 | #define X_PANICSTR 5 | |
49 | { "_panicstr" }, | |
261f5d78 SL |
50 | #define X_DUMPMAG 6 |
51 | { "_dumpmag" }, | |
52 | { "" }, | |
d112e9ff | 53 | }; |
2ad23575 KB |
54 | int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 }; |
55 | int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 }; | |
d112e9ff | 56 | |
2ad23575 KB |
57 | struct nlist dump_nl[] = { /* Name list for dumped system. */ |
58 | { "_dumpdev" }, /* Entries MUST be the same as */ | |
59 | { "_dumplo" }, /* those in current_nl[]. */ | |
a3e4f1d7 RC |
60 | { "_time" }, |
61 | { "_dumpsize" }, | |
62 | { "_version" }, | |
63 | { "_panicstr" }, | |
64 | { "_dumpmag" }, | |
65 | { "" }, | |
66 | }; | |
67 | ||
2ad23575 KB |
68 | /* Types match kernel declarations. */ |
69 | long dumplo; /* where dump starts on dumpdev */ | |
70 | int dumpmag; /* magic number in dump */ | |
71 | int dumpsize; /* amount of memory dumped */ | |
72 | ||
0910ad56 | 73 | char *vmunix; |
97d6da0b BJ |
74 | char *dirname; /* directory to save dumps in */ |
75 | char *ddname; /* name of dump device */ | |
97d6da0b | 76 | dev_t dumpdev; /* dump device */ |
2ad23575 | 77 | int dumpfd; /* read/write descriptor on block dev */ |
97d6da0b | 78 | time_t now; /* current date */ |
2ad23575 | 79 | char panic_mesg[1024]; |
97d6da0b | 80 | int panicstr; |
2ad23575 KB |
81 | char vers[1024]; |
82 | ||
83 | int clear, compress, force, verbose; /* flags */ | |
d112e9ff | 84 | |
2ad23575 KB |
85 | void check_kmem __P((void)); |
86 | int check_space __P((void)); | |
87 | void clear_dump __P((void)); | |
88 | int Create __P((char *, int)); | |
89 | int dump_exists __P((void)); | |
bea95b84 | 90 | char *find_dev __P((dev_t, int)); |
2ad23575 KB |
91 | int get_crashtime __P((void)); |
92 | void kmem_setup __P((void)); | |
93 | void log __P((int, char *, ...)); | |
94 | void Lseek __P((int, off_t, int)); | |
95 | int Open __P((char *, int rw)); | |
96 | int Read __P((int, void *, int)); | |
0910ad56 | 97 | char *rawname __P((char *s)); |
2ad23575 KB |
98 | void save_core __P((void)); |
99 | void usage __P((void)); | |
100 | void Write __P((int, void *, int)); | |
0910ad56 KB |
101 | |
102 | int | |
d112e9ff | 103 | main(argc, argv) |
97d6da0b | 104 | int argc; |
0910ad56 | 105 | char *argv[]; |
d112e9ff | 106 | { |
01d84d6a | 107 | int ch; |
865f9d47 | 108 | |
2ad23575 KB |
109 | openlog("savecore", LOG_PERROR, LOG_DAEMON); |
110 | ||
6a655f32 | 111 | while ((ch = getopt(argc, argv, "cdfNvz")) != EOF) |
01d84d6a KB |
112 | switch(ch) { |
113 | case 'c': | |
114 | clear = 1; | |
c6e3f9fb | 115 | break; |
2ad23575 | 116 | case 'd': /* Not documented. */ |
a3e4f1d7 | 117 | case 'v': |
01d84d6a | 118 | verbose = 1; |
a3e4f1d7 | 119 | break; |
01d84d6a KB |
120 | case 'f': |
121 | force = 1; | |
99b8650e | 122 | break; |
6a655f32 KB |
123 | case 'N': |
124 | vmunix = optarg; | |
125 | break; | |
2ad23575 KB |
126 | case 'z': |
127 | compress = 1; | |
128 | break; | |
01d84d6a | 129 | case '?': |
a3e4f1d7 | 130 | default: |
01d84d6a | 131 | usage(); |
a3e4f1d7 | 132 | } |
01d84d6a KB |
133 | argc -= optind; |
134 | argv += optind; | |
135 | ||
01d84d6a KB |
136 | if (!clear) { |
137 | if (argc != 1 && argc != 2) | |
138 | usage(); | |
139 | dirname = argv[0]; | |
d112e9ff | 140 | } |
865f9d47 | 141 | if (argc == 2) |
0910ad56 | 142 | vmunix = argv[1]; |
01d84d6a | 143 | |
2ad23575 KB |
144 | (void)time(&now); |
145 | kmem_setup(); | |
01d84d6a | 146 | |
739955be KM |
147 | } |
148 | ||
0910ad56 | 149 | void |
2ad23575 | 150 | kmem_setup() |
d112e9ff | 151 | { |
865f9d47 | 152 | FILE *fp; |
865f9d47 | 153 | int kmem, i; |
0910ad56 | 154 | char *dump_sys; |
a3e4f1d7 | 155 | |
a3e4f1d7 | 156 | /* |
2ad23575 KB |
157 | * Some names we need for the currently running system, others for |
158 | * the system that was running when the dump was made. The values | |
159 | * obtained from the current system are used to look for things in | |
160 | * /dev/kmem that cannot be found in the dump_sys namelist, but are | |
161 | * presumed to be the same (since the disk partitions are probably | |
162 | * the same!) | |
a3e4f1d7 | 163 | */ |
2ad23575 KB |
164 | if ((nlist(_PATH_UNIX, current_nl)) == -1) |
165 | syslog(LOG_ERR, "%s: nlist: %s", _PATH_UNIX, strerror(errno)); | |
865f9d47 SL |
166 | for (i = 0; cursyms[i] != -1; i++) |
167 | if (current_nl[cursyms[i]].n_value == 0) { | |
2ad23575 KB |
168 | syslog(LOG_ERR, "%s: %s not in namelist", |
169 | _PATH_UNIX, current_nl[cursyms[i]].n_name); | |
865f9d47 SL |
170 | exit(1); |
171 | } | |
2ad23575 KB |
172 | |
173 | dump_sys = vmunix ? vmunix : _PATH_UNIX; | |
174 | if ((nlist(dump_sys, dump_nl)) == -1) | |
175 | syslog(LOG_ERR, "%s: nlist: %s", dump_sys, strerror(errno)); | |
865f9d47 SL |
176 | for (i = 0; dumpsyms[i] != -1; i++) |
177 | if (dump_nl[dumpsyms[i]].n_value == 0) { | |
2ad23575 KB |
178 | syslog(LOG_ERR, "%s: %s not in namelist", |
179 | dump_sys, dump_nl[dumpsyms[i]].n_name); | |
865f9d47 SL |
180 | exit(1); |
181 | } | |
2ad23575 | 182 | |
f76fd03c | 183 | kmem = Open(_PATH_KMEM, O_RDONLY); |
ce12e961 | 184 | Lseek(kmem, (off_t)current_nl[X_DUMPDEV].n_value, L_SET); |
2ad23575 | 185 | (void)Read(kmem, &dumpdev, sizeof(dumpdev)); |
ce12e961 | 186 | Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, L_SET); |
2ad23575 | 187 | (void)Read(kmem, &dumplo, sizeof(dumplo)); |
01d84d6a | 188 | if (verbose) |
2ad23575 KB |
189 | (void)printf("dumplo = %d (%d * %d)\n", |
190 | dumplo, dumplo/DEV_BSIZE, DEV_BSIZE); | |
ce12e961 | 191 | Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET); |
2ad23575 | 192 | (void)Read(kmem, &dumpmag, sizeof(dumpmag)); |
f53aabcb | 193 | dumplo *= DEV_BSIZE; |
d112e9ff | 194 | ddname = find_dev(dumpdev, S_IFBLK); |
95503932 | 195 | dumpfd = Open(ddname, O_RDWR); |
865f9d47 SL |
196 | fp = fdopen(kmem, "r"); |
197 | if (fp == NULL) { | |
2ad23575 | 198 | syslog(LOG_ERR, "%s: fdopen: %m", _PATH_KMEM); |
97d6da0b | 199 | exit(1); |
d112e9ff | 200 | } |
0910ad56 | 201 | if (vmunix) |
f6cc4b0d | 202 | return; |
2ad23575 KB |
203 | (void)fseek(fp, (off_t)current_nl[X_VERSION].n_value, L_SET); |
204 | (void)fgets(vers, sizeof(vers), fp); | |
205 | ||
206 | /* Don't fclose(fp), we use dumpfd later. */ | |
798fe693 SL |
207 | } |
208 | ||
0910ad56 | 209 | void |
5638c7c2 SL |
210 | check_kmem() |
211 | { | |
798fe693 | 212 | register char *cp; |
2ad23575 KB |
213 | FILE *fp; |
214 | char core_vers[1024]; | |
798fe693 | 215 | |
95503932 | 216 | fp = fdopen(dumpfd, "r"); |
865f9d47 | 217 | if (fp == NULL) { |
2ad23575 | 218 | syslog(LOG_ERR, "%s: fdopen: %m", ddname); |
97d6da0b | 219 | exit(1); |
d112e9ff | 220 | } |
2ad23575 KB |
221 | fseek(fp, (off_t)(dumplo + ok(dump_nl[X_VERSION].n_value)), L_SET); |
222 | fgets(core_vers, sizeof(core_vers), fp); | |
223 | if (strcmp(vers, core_vers) && vmunix == 0) | |
224 | syslog(LOG_WARNING, | |
225 | "warning: %s version mismatch:\n\t%s\nand\t%s\n", | |
226 | _PATH_UNIX, vers, core_vers); | |
227 | (void)fseek(fp, | |
228 | (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET); | |
229 | (void)fread(&panicstr, sizeof(panicstr), 1, fp); | |
97d6da0b | 230 | if (panicstr) { |
2ad23575 | 231 | (void)fseek(fp, dumplo + ok(panicstr), L_SET); |
d112e9ff BJ |
232 | cp = panic_mesg; |
233 | do | |
234 | *cp = getc(fp); | |
95503932 | 235 | while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]); |
d112e9ff | 236 | } |
2ad23575 KB |
237 | /* Don't fclose(fp), we use dumpfd later. */ |
238 | } | |
239 | ||
240 | void | |
241 | clear_dump() | |
242 | { | |
243 | long newdumplo; | |
244 | ||
245 | newdumplo = 0; | |
246 | Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); | |
247 | Write(dumpfd, &newdumplo, sizeof(newdumplo)); | |
f6cc4b0d | 248 | } |
d112e9ff | 249 | |
0910ad56 | 250 | int |
2ad23575 | 251 | dump_exists() |
97d6da0b | 252 | { |
2ad23575 | 253 | int newdumpmag; |
d112e9ff | 254 | |
2ad23575 KB |
255 | Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); |
256 | (void)Read(dumpfd, &newdumpmag, sizeof(newdumpmag)); | |
257 | if (newdumpmag != dumpmag) { | |
3143c0b3 KB |
258 | if (verbose) |
259 | syslog(LOG_WARNING, "magic number mismatch (%x != %x)", | |
260 | newdumpmag, dumpmag); | |
2ad23575 | 261 | syslog(LOG_WARNING, "no core dump"); |
261f5d78 | 262 | return (0); |
d112e9ff | 263 | } |
261f5d78 | 264 | return (1); |
d112e9ff BJ |
265 | } |
266 | ||
2ad23575 KB |
267 | char buf[1024 * 1024]; |
268 | ||
269 | void | |
270 | save_core() | |
d112e9ff | 271 | { |
2ad23575 KB |
272 | register FILE *fp; |
273 | register int bounds, ifd, nr, nw, ofd; | |
274 | char *rawp, path[MAXPATHLEN]; | |
275 | ||
276 | /* | |
277 | * Get the current number and update the bounds file. Do the update | |
278 | * now, because may fail later and don't want to overwrite anything. | |
279 | */ | |
280 | (void)snprintf(path, sizeof(path), "%s/bounds", dirname); | |
281 | if ((fp = fopen(path, "r")) == NULL) | |
282 | goto err1; | |
283 | if (fgets(buf, sizeof(buf), fp) == NULL) { | |
284 | if (ferror(fp)) | |
285 | err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno)); | |
286 | bounds = 0; | |
287 | } else | |
288 | bounds = atoi(buf); | |
289 | if (fp != NULL) | |
290 | (void)fclose(fp); | |
291 | if ((fp = fopen(path, "w")) == NULL) | |
292 | syslog(LOG_ERR, "%s: %m", path); | |
293 | else { | |
294 | (void)fprintf(fp, "%d\n", bounds + 1); | |
295 | (void)fclose(fp); | |
296 | } | |
297 | (void)fclose(fp); | |
d112e9ff | 298 | |
2ad23575 KB |
299 | /* Create the core file. */ |
300 | (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s", | |
301 | dirname, bounds, compress ? ".Z" : ""); | |
302 | if (compress) { | |
303 | if ((fp = zopen(path, "w", 0)) == NULL) { | |
304 | syslog(LOG_ERR, "%s: %s", path, strerror(errno)); | |
305 | exit(1); | |
306 | } | |
307 | } else | |
60221963 | 308 | ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
2ad23575 KB |
309 | |
310 | /* Open the raw device. */ | |
311 | rawp = rawname(ddname); | |
312 | if ((ifd = open(rawp, O_RDONLY)) == -1) { | |
313 | syslog(LOG_WARNING, "%s: %m; using block device", rawp); | |
314 | ifd = dumpfd; | |
315 | } | |
316 | ||
317 | /* Read the dump size. */ | |
318 | Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET); | |
319 | (void)Read(dumpfd, &dumpsize, sizeof(dumpsize)); | |
320 | ||
321 | /* Seek to the start of the core. */ | |
322 | Lseek(ifd, (off_t)dumplo, L_SET); | |
323 | ||
324 | /* Copy the core file. */ | |
325 | dumpsize *= NBPG; | |
326 | syslog(LOG_NOTICE, "writing %score to %s", | |
327 | compress ? "compressed " : "", path); | |
328 | for (; dumpsize > 0; dumpsize -= nr) { | |
329 | (void)printf("%6dK\r", dumpsize / 1024); | |
330 | (void)fflush(stdout); | |
331 | nr = read(ifd, buf, MIN(dumpsize, sizeof(buf))); | |
332 | if (nr <= 0) { | |
333 | if (nr == 0) | |
334 | syslog(LOG_WARNING, | |
335 | "WARNING: EOF on dump device"); | |
336 | else | |
337 | syslog(LOG_ERR, "%s: %m", rawp); | |
338 | goto err2; | |
339 | } | |
340 | if (compress) | |
341 | nw = fwrite(buf, 1, nr, fp); | |
342 | else | |
343 | nw = write(ofd, buf, nr); | |
344 | if (nw != nr) { | |
345 | syslog(LOG_ERR, "%s: %s", | |
346 | path, strerror(nw == 0 ? EIO : errno)); | |
347 | err2: syslog(LOG_WARNING, | |
348 | "WARNING: vmcore may be incomplete"); | |
349 | (void)printf("\n"); | |
350 | exit(1); | |
351 | } | |
352 | } | |
353 | (void)printf("\n"); | |
354 | (void)close(ifd); | |
355 | if (compress) | |
356 | (void)fclose(fp); | |
357 | else | |
358 | (void)close(ofd); | |
359 | ||
360 | /* Copy the kernel. */ | |
6a655f32 | 361 | ifd = Open(vmunix ? vmunix : _PATH_UNIX, O_RDONLY); |
2ad23575 KB |
362 | (void)snprintf(path, sizeof(path), "%s/vmunix.%d%s", |
363 | dirname, bounds, compress ? ".Z" : ""); | |
364 | if (compress) { | |
365 | if ((fp = zopen(path, "w", 0)) == NULL) { | |
366 | syslog(LOG_ERR, "%s: %s", path, strerror(errno)); | |
367 | exit(1); | |
368 | } | |
369 | } else | |
32ee93da | 370 | ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
2ad23575 KB |
371 | syslog(LOG_NOTICE, "writing %skernel to %s", |
372 | compress ? "compressed " : "", path); | |
373 | while ((nr = read(ifd, buf, sizeof(buf))) > 0) { | |
374 | if (compress) | |
375 | nw = fwrite(buf, 1, nr, fp); | |
376 | else | |
377 | nw = write(ofd, buf, nr); | |
378 | if (nw != nr) { | |
379 | syslog(LOG_ERR, "%s: %s", | |
380 | path, strerror(nw == 0 ? EIO : errno)); | |
381 | syslog(LOG_WARNING, | |
382 | "WARNING: vmunix may be incomplete"); | |
383 | exit(1); | |
384 | } | |
385 | } | |
386 | if (nr < 0) { | |
387 | syslog(LOG_ERR, "%s: %s", | |
388 | vmunix ? vmunix : _PATH_UNIX, strerror(errno)); | |
389 | syslog(LOG_WARNING, | |
390 | "WARNING: vmunix may be incomplete"); | |
391 | exit(1); | |
392 | } | |
393 | if (compress) | |
394 | (void)fclose(fp); | |
395 | else | |
396 | (void)close(ofd); | |
d112e9ff BJ |
397 | } |
398 | ||
2ad23575 KB |
399 | char * |
400 | find_dev(dev, type) | |
401 | register dev_t dev; | |
402 | register int type; | |
d112e9ff | 403 | { |
2ad23575 KB |
404 | register DIR *dfd; |
405 | struct dirent *dir; | |
406 | struct stat sb; | |
407 | char *dp, devname[MAXPATHLEN + 1]; | |
d112e9ff | 408 | |
2ad23575 KB |
409 | if ((dfd = opendir(_PATH_DEV)) == NULL) { |
410 | syslog(LOG_ERR, "%s: %s", _PATH_DEV, strerror(errno)); | |
97d6da0b BJ |
411 | exit(1); |
412 | } | |
2ad23575 KB |
413 | (void)strcpy(devname, _PATH_DEV); |
414 | while ((dir = readdir(dfd))) { | |
415 | (void)strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name); | |
416 | if (stat(devname, &sb)) { | |
417 | syslog(LOG_ERR, "%s: %s", devname, strerror(errno)); | |
418 | continue; | |
419 | } | |
420 | if ((sb.st_mode & S_IFMT) != type) | |
421 | continue; | |
422 | if (dev == sb.st_rdev) { | |
423 | closedir(dfd); | |
424 | if ((dp = strdup(devname)) == NULL) { | |
425 | syslog(LOG_ERR, "%s", strerror(errno)); | |
426 | exit(1); | |
427 | } | |
428 | return (dp); | |
429 | } | |
d112e9ff | 430 | } |
2ad23575 KB |
431 | closedir(dfd); |
432 | syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev)); | |
433 | exit(1); | |
434 | } | |
435 | ||
436 | char * | |
437 | rawname(s) | |
438 | char *s; | |
439 | { | |
440 | char *sl, name[MAXPATHLEN]; | |
441 | ||
442 | if ((sl = rindex(s, '/')) == NULL || sl[1] == '0') { | |
443 | syslog(LOG_ERR, | |
444 | "can't make raw dump device name from %s", s); | |
445 | return (s); | |
446 | } | |
447 | (void)snprintf(name, sizeof(name), "%.*s/r%s", sl - s, s, sl + 1); | |
448 | if ((sl = strdup(name)) == NULL) { | |
449 | syslog(LOG_ERR, "%s", strerror(errno)); | |
450 | exit(1); | |
451 | } | |
452 | return (sl); | |
d112e9ff BJ |
453 | } |
454 | ||
0910ad56 | 455 | int |
2ad23575 | 456 | get_crashtime() |
d112e9ff | 457 | { |
2ad23575 | 458 | time_t dumptime; /* Time the dump was taken. */ |
d112e9ff | 459 | |
2ad23575 KB |
460 | Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET); |
461 | (void)Read(dumpfd, &dumptime, sizeof(dumptime)); | |
462 | if (dumptime == 0) { | |
463 | if (verbose) | |
464 | syslog(LOG_ERR, "dump time is zero"); | |
261f5d78 | 465 | return (0); |
2ad23575 KB |
466 | } |
467 | (void)printf("savecore: system went down at %s", ctime(&dumptime)); | |
468 | #define LEEWAY (7 * SECSPERDAY) | |
469 | if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { | |
470 | (void)printf("dump time is unreasonable\n"); | |
261f5d78 | 471 | return (0); |
d112e9ff | 472 | } |
2ad23575 | 473 | return (1); |
d112e9ff BJ |
474 | } |
475 | ||
0910ad56 | 476 | int |
2ad23575 | 477 | check_space() |
d112e9ff | 478 | { |
d112e9ff | 479 | register FILE *fp; |
f3c89e1f CT |
480 | char *tvmunix; |
481 | off_t minfree, spacefree, vmunixsize, needed; | |
482 | struct stat st; | |
2ad23575 | 483 | struct statfs fsbuf; |
2ad23575 | 484 | char buf[100], path[MAXPATHLEN]; |
d112e9ff | 485 | |
f3c89e1f CT |
486 | tvmunix = vmunix ? vmunix : _PATH_UNIX; |
487 | if (stat(tvmunix, &st) < 0) { | |
488 | syslog(LOG_ERR, "%s: %m", tvmunix); | |
489 | exit(1); | |
490 | } | |
491 | vmunixsize = st.st_blocks * S_BLKSIZE; | |
2ad23575 KB |
492 | if (statfs(dirname, &fsbuf) < 0) { |
493 | syslog(LOG_ERR, "%s: %m", dirname); | |
494 | exit(1); | |
4d1d39b2 | 495 | } |
6a655f32 | 496 | spacefree = (fsbuf.f_bavail * fsbuf.f_bsize) / 1024; |
2ad23575 KB |
497 | |
498 | (void)snprintf(path, sizeof(path), "%s/minfree", dirname); | |
499 | if ((fp = fopen(path, "r")) == NULL) | |
500 | minfree = 0; | |
501 | else { | |
502 | if (fgets(buf, sizeof(buf), fp) == NULL) | |
503 | minfree = 0; | |
504 | else | |
505 | minfree = atoi(buf); | |
506 | (void)fclose(fp); | |
95503932 | 507 | } |
2ad23575 | 508 | |
f3c89e1f CT |
509 | needed = dumpsize + vmunixsize; |
510 | if (minfree > 0 && spacefree - needed < minfree) { | |
2ad23575 KB |
511 | syslog(LOG_WARNING, |
512 | "no dump, not enough free space on device"); | |
513 | return (0); | |
d112e9ff | 514 | } |
f3c89e1f | 515 | if (spacefree - needed < minfree) |
2ad23575 KB |
516 | syslog(LOG_WARNING, |
517 | "dump performed, but free space threshold crossed"); | |
518 | return (1); | |
d112e9ff BJ |
519 | } |
520 | ||
0910ad56 | 521 | int |
97d6da0b BJ |
522 | Open(name, rw) |
523 | char *name; | |
524 | int rw; | |
525 | { | |
526 | int fd; | |
527 | ||
2ad23575 KB |
528 | if ((fd = open(name, rw, 0)) < 0) { |
529 | syslog(LOG_ERR, "%s: %m", name); | |
97d6da0b BJ |
530 | exit(1); |
531 | } | |
865f9d47 | 532 | return (fd); |
97d6da0b BJ |
533 | } |
534 | ||
0910ad56 | 535 | int |
2ad23575 KB |
536 | Read(fd, bp, size) |
537 | int fd, size; | |
538 | void *bp; | |
97d6da0b | 539 | { |
2ad23575 | 540 | int nr; |
97d6da0b | 541 | |
2ad23575 KB |
542 | nr = read(fd, bp, size); |
543 | if (nr != size) { | |
544 | syslog(LOG_ERR, "read: %m"); | |
97d6da0b BJ |
545 | exit(1); |
546 | } | |
2ad23575 | 547 | return (nr); |
97d6da0b BJ |
548 | } |
549 | ||
ce12e961 | 550 | void |
97d6da0b | 551 | Lseek(fd, off, flag) |
2ad23575 | 552 | int fd, flag; |
ce12e961 | 553 | off_t off; |
97d6da0b | 554 | { |
2ad23575 | 555 | off_t ret; |
97d6da0b | 556 | |
2ad23575 | 557 | ret = lseek(fd, off, flag); |
865f9d47 | 558 | if (ret == -1) { |
2ad23575 | 559 | syslog(LOG_ERR, "lseek: %m"); |
97d6da0b BJ |
560 | exit(1); |
561 | } | |
97d6da0b BJ |
562 | } |
563 | ||
0910ad56 | 564 | int |
97d6da0b BJ |
565 | Create(file, mode) |
566 | char *file; | |
567 | int mode; | |
568 | { | |
569 | register int fd; | |
570 | ||
865f9d47 SL |
571 | fd = creat(file, mode); |
572 | if (fd < 0) { | |
2ad23575 | 573 | syslog(LOG_ERR, "%s: %m", file); |
97d6da0b BJ |
574 | exit(1); |
575 | } | |
865f9d47 | 576 | return (fd); |
97d6da0b BJ |
577 | } |
578 | ||
0910ad56 | 579 | void |
2ad23575 KB |
580 | Write(fd, bp, size) |
581 | int fd, size; | |
582 | void *bp; | |
97d6da0b | 583 | { |
bfda3826 | 584 | int n; |
97d6da0b | 585 | |
2ad23575 KB |
586 | if ((n = write(fd, bp, size)) < size) { |
587 | syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO)); | |
97d6da0b BJ |
588 | exit(1); |
589 | } | |
590 | } | |
ce104dfd | 591 | |
0910ad56 | 592 | void |
01d84d6a KB |
593 | usage() |
594 | { | |
6a655f32 | 595 | (void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory"); |
01d84d6a KB |
596 | exit(1); |
597 | } |