Deleted Added
full compact
savecore.c (92086) savecore.c (92806)
1/*-
2 * Copyright (c) 1986, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1986, 1992, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)savecore.c 8.3 (Berkeley) 1/2/94";
43#endif
44static const char rcsid[] =
1/*-
2 * Copyright (c) 1986, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1986, 1992, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)savecore.c 8.3 (Berkeley) 1/2/94";
43#endif
44static const char rcsid[] =
45 "$FreeBSD: head/sbin/savecore/savecore.c 92086 2002-03-11 11:23:48Z des $";
45 "$FreeBSD: head/sbin/savecore/savecore.c 92806 2002-03-20 17:55:10Z obrien $";
46#endif /* not lint */
47
48#include <sys/param.h>
49#include <sys/stat.h>
50#include <sys/mount.h>
51#include <sys/syslog.h>
52#include <sys/sysctl.h>
53
54#include <vm/vm.h>
55#include <vm/vm_param.h>
56#include <vm/pmap.h>
57
58#include <dirent.h>
59#include <fcntl.h>
60#include <nlist.h>
61#include <paths.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <unistd.h>
66
67extern FILE *zopen(const char *fname, const char *mode);
68
69#if defined(__i386__) || defined(__sparc64__)
70#define ok(number) ((number) - kernbase)
71#elif defined(__alpha__)
72#define ok(number) ALPHA_K0SEG_TO_PHYS(number)
73#else
74#error savecore has not been ported to this platform yet.
75#endif
76
77struct nlist current_nl[] = { /* Namelist for currently running system. */
78#define X_DUMPLO 0
79 { "_dumplo" },
80#define X_TIME 1
81 { "_time_second" },
82#define X_DUMPSIZE 2
83 { "_dumpsize" },
84#define X_VERSION 3
85 { "_version" },
86#define X_PANICSTR 4
87 { "_panicstr" },
88#define X_DUMPMAG 5
89 { "_dumpmag" },
90#define X_KERNBASE 6
91 { "_kernbase" },
92 { "" },
93};
94int cursyms[] = { X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
95int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
96
97struct nlist dump_nl[] = { /* Name list for dumped system. */
98 { "_dumplo" }, /* Entries MUST be the same as */
99 { "_time_second" }, /* those in current_nl[]. */
100 { "_dumpsize" },
101 { "_version" },
102 { "_panicstr" },
103 { "_dumpmag" },
104 { "_kernbase" },
105 { "" },
106};
107
108/* Types match kernel declarations. */
109u_long dumpmag; /* magic number in dump */
110
111/* Based on kernel variables, but with more convenient types. */
112off_t dumplo; /* where dump starts on dumpdev */
113off_t dumpsize; /* amount of memory dumped */
114
115char *kernel; /* user-specified kernel */
116char *savedir; /* directory to save dumps in */
117char ddname[MAXPATHLEN]; /* name of dump device */
118dev_t dumpdev; /* dump device */
119int dumpfd; /* read/write descriptor on char dev */
120time_t now; /* current date */
121char panic_mesg[1024]; /* panic message */
122int panicstr; /* flag: dump was caused by panic */
123char vers[1024]; /* version of kernel that crashed */
124
125#if defined(__i386__) || defined(__sparc64__)
126u_long kernbase; /* offset of kvm to core file */
127#endif
128
129int clear, compress, force, verbose; /* flags */
130int keep; /* keep dump on device */
131
132void check_kmem __P((void));
133int check_space __P((void));
134void clear_dump __P((void));
135void DumpRead __P((int fd, void *bp, int size, off_t off, int flag));
136void DumpWrite __P((int fd, void *bp, int size, off_t off, int flag));
137int dump_exists __P((void));
138void find_dev __P((dev_t));
139int get_crashtime __P((void));
140void get_dumpsize __P((void));
141void kmem_setup __P((void));
142void Lseek __P((int, off_t, int));
143int Open __P((const char *, int rw));
144int Read __P((int, void *, int));
145void save_core __P((void));
146void usage __P((void));
147void Write __P((int, void *, int));
148
149int
150main(argc, argv)
151 int argc;
152 char *argv[];
153{
154 int ch;
155
156 openlog("savecore", LOG_PERROR, LOG_DAEMON);
157
158 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
159 switch(ch) {
160 case 'c':
161 clear = 1;
162 break;
163 case 'd': /* Not documented. */
164 case 'v':
165 verbose = 1;
166 break;
167 case 'f':
168 force = 1;
169 break;
170 case 'k':
171 keep = 1;
172 break;
173 case 'N':
174 kernel = optarg;
175 break;
176 case 'z':
177 compress = 1;
178 break;
179 case '?':
180 default:
181 usage();
182 }
183 argc -= optind;
184 argv += optind;
185
186 if (!clear) {
187 if (argc != 1 && argc != 2)
188 usage();
189 savedir = argv[0];
190 }
191 if (argc == 2)
192 kernel = argv[1];
193
194 (void)time(&now);
195 kmem_setup();
196
197 if (clear) {
198 clear_dump();
199 exit(0);
200 }
201
202 if (!dump_exists() && !force)
203 exit(1);
204
205 check_kmem();
206
207 if (panicstr)
208 syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg);
209 else
210 syslog(LOG_ALERT, "reboot");
211
212 get_dumpsize();
213
214 if ((!get_crashtime() || !check_space()) && !force)
215 exit(1);
216
217 save_core();
218
219 if (!keep)
220 clear_dump();
221
222 exit(0);
223}
224
225void
226kmem_setup()
227{
228 int kmem, i;
229 const char *dump_sys;
230 size_t len;
231 long kdumplo; /* block number where dump starts on dumpdev */
232 char *p;
233
234 /*
235 * Some names we need for the currently running system, others for
236 * the system that was running when the dump was made. The values
237 * obtained from the current system are used to look for things in
238 * /dev/kmem that cannot be found in the dump_sys namelist, but are
239 * presumed to be the same (since the disk partitions are probably
240 * the same!)
241 */
242 if ((nlist(getbootfile(), current_nl)) == -1)
243 syslog(LOG_ERR, "%s: nlist: %m", getbootfile());
244 for (i = 0; cursyms[i] != -1; i++)
245 if (current_nl[cursyms[i]].n_value == 0) {
246 syslog(LOG_ERR, "%s: %s not in namelist",
247 getbootfile(), current_nl[cursyms[i]].n_name);
248 exit(1);
249 }
250
251 dump_sys = kernel ? kernel : getbootfile();
252 if ((nlist(dump_sys, dump_nl)) == -1)
253 syslog(LOG_ERR, "%s: nlist: %m", dump_sys);
254 for (i = 0; dumpsyms[i] != -1; i++)
255 if (dump_nl[dumpsyms[i]].n_value == 0) {
256 syslog(LOG_ERR, "%s: %s not in namelist",
257 dump_sys, dump_nl[dumpsyms[i]].n_name);
258 exit(1);
259 }
260
261#if defined(__i386__) || defined(__sparc64__)
262 if (dump_nl[X_KERNBASE].n_value != 0)
263 kernbase = dump_nl[X_KERNBASE].n_value;
264 else
265 kernbase = KERNBASE;
266#endif
267
268 len = sizeof dumpdev;
269 if (sysctlbyname("kern.dumpdev", &dumpdev, &len, NULL, 0) == -1) {
270 syslog(LOG_ERR, "sysctl: kern.dumpdev: %m");
271 exit(1);
272 }
273 if (dumpdev == NODEV) {
274 syslog(LOG_WARNING, "no core dump (no dumpdev)");
275 exit(1);
276 }
277
278 kmem = Open(_PATH_KMEM, O_RDONLY);
279 Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, SEEK_SET);
280 (void)Read(kmem, &kdumplo, sizeof(kdumplo));
281 dumplo = (off_t)kdumplo * DEV_BSIZE;
282 if (verbose)
283 (void)printf("dumplo = %lld (%ld * %d)\n",
284 (long long)dumplo, kdumplo, DEV_BSIZE);
285 Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, SEEK_SET);
286 (void)Read(kmem, &dumpmag, sizeof(dumpmag));
287 find_dev(dumpdev);
288 dumpfd = Open(ddname, O_RDWR);
289 if (kernel)
290 return;
291
292 Lseek(kmem, (off_t)current_nl[X_VERSION].n_value, SEEK_SET);
293 Read(kmem, vers, sizeof(vers));
294 vers[sizeof(vers) - 1] = '\0';
295 p = strchr(vers, '\n');
296 if (p)
297 p[1] = '\0';
298
299 /* Don't fclose(fp), we use kmem later. */
300}
301
302void
303check_kmem()
304{
305 char core_vers[1024], *p;
306
307 DumpRead(dumpfd, core_vers, sizeof(core_vers),
308 dumplo + ok(dump_nl[X_VERSION].n_value), SEEK_SET);
309 core_vers[sizeof(core_vers) - 1] = '\0';
310 p = strchr(core_vers, '\n');
311 if (p)
312 p[1] = '\0';
313 if (strcmp(vers, core_vers) && kernel == 0)
314 syslog(LOG_WARNING,
315 "warning: %s version mismatch:\n\t\"%s\"\nand\t\"%s\"\n",
316 getbootfile(), vers, core_vers);
317 DumpRead(dumpfd, &panicstr, sizeof(panicstr),
318 dumplo + ok(dump_nl[X_PANICSTR].n_value), SEEK_SET);
319 if (panicstr) {
320 DumpRead(dumpfd, panic_mesg, sizeof(panic_mesg),
321 dumplo + ok(panicstr), SEEK_SET);
322 }
323}
324
325/*
326 * Clear the magic number in the dump header.
327 */
328void
329clear_dump()
330{
331 u_long newdumpmag;
332
333 newdumpmag = 0;
334 DumpWrite(dumpfd, &newdumpmag, sizeof(newdumpmag),
335 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET);
336 close(dumpfd);
337}
338
339/*
340 * Check if a dump exists by looking for a magic number in the dump
341 * header.
342 */
343int
344dump_exists()
345{
346 u_long newdumpmag;
347
348 DumpRead(dumpfd, &newdumpmag, sizeof(newdumpmag),
349 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET);
350 if (newdumpmag != dumpmag) {
351 if (verbose)
352 syslog(LOG_WARNING, "magic number mismatch (%x != %x)",
353 newdumpmag, dumpmag);
354 syslog(LOG_WARNING, "no core dump");
355 return (0);
356 }
357 return (1);
358}
359
360char buf[1024 * 1024];
361#define BLOCKSIZE (1<<12)
362#define BLOCKMASK (~(BLOCKSIZE-1))
363
364/*
365 * Save the core dump.
366 */
367void
368save_core()
369{
46#endif /* not lint */
47
48#include <sys/param.h>
49#include <sys/stat.h>
50#include <sys/mount.h>
51#include <sys/syslog.h>
52#include <sys/sysctl.h>
53
54#include <vm/vm.h>
55#include <vm/vm_param.h>
56#include <vm/pmap.h>
57
58#include <dirent.h>
59#include <fcntl.h>
60#include <nlist.h>
61#include <paths.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <unistd.h>
66
67extern FILE *zopen(const char *fname, const char *mode);
68
69#if defined(__i386__) || defined(__sparc64__)
70#define ok(number) ((number) - kernbase)
71#elif defined(__alpha__)
72#define ok(number) ALPHA_K0SEG_TO_PHYS(number)
73#else
74#error savecore has not been ported to this platform yet.
75#endif
76
77struct nlist current_nl[] = { /* Namelist for currently running system. */
78#define X_DUMPLO 0
79 { "_dumplo" },
80#define X_TIME 1
81 { "_time_second" },
82#define X_DUMPSIZE 2
83 { "_dumpsize" },
84#define X_VERSION 3
85 { "_version" },
86#define X_PANICSTR 4
87 { "_panicstr" },
88#define X_DUMPMAG 5
89 { "_dumpmag" },
90#define X_KERNBASE 6
91 { "_kernbase" },
92 { "" },
93};
94int cursyms[] = { X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
95int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
96
97struct nlist dump_nl[] = { /* Name list for dumped system. */
98 { "_dumplo" }, /* Entries MUST be the same as */
99 { "_time_second" }, /* those in current_nl[]. */
100 { "_dumpsize" },
101 { "_version" },
102 { "_panicstr" },
103 { "_dumpmag" },
104 { "_kernbase" },
105 { "" },
106};
107
108/* Types match kernel declarations. */
109u_long dumpmag; /* magic number in dump */
110
111/* Based on kernel variables, but with more convenient types. */
112off_t dumplo; /* where dump starts on dumpdev */
113off_t dumpsize; /* amount of memory dumped */
114
115char *kernel; /* user-specified kernel */
116char *savedir; /* directory to save dumps in */
117char ddname[MAXPATHLEN]; /* name of dump device */
118dev_t dumpdev; /* dump device */
119int dumpfd; /* read/write descriptor on char dev */
120time_t now; /* current date */
121char panic_mesg[1024]; /* panic message */
122int panicstr; /* flag: dump was caused by panic */
123char vers[1024]; /* version of kernel that crashed */
124
125#if defined(__i386__) || defined(__sparc64__)
126u_long kernbase; /* offset of kvm to core file */
127#endif
128
129int clear, compress, force, verbose; /* flags */
130int keep; /* keep dump on device */
131
132void check_kmem __P((void));
133int check_space __P((void));
134void clear_dump __P((void));
135void DumpRead __P((int fd, void *bp, int size, off_t off, int flag));
136void DumpWrite __P((int fd, void *bp, int size, off_t off, int flag));
137int dump_exists __P((void));
138void find_dev __P((dev_t));
139int get_crashtime __P((void));
140void get_dumpsize __P((void));
141void kmem_setup __P((void));
142void Lseek __P((int, off_t, int));
143int Open __P((const char *, int rw));
144int Read __P((int, void *, int));
145void save_core __P((void));
146void usage __P((void));
147void Write __P((int, void *, int));
148
149int
150main(argc, argv)
151 int argc;
152 char *argv[];
153{
154 int ch;
155
156 openlog("savecore", LOG_PERROR, LOG_DAEMON);
157
158 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
159 switch(ch) {
160 case 'c':
161 clear = 1;
162 break;
163 case 'd': /* Not documented. */
164 case 'v':
165 verbose = 1;
166 break;
167 case 'f':
168 force = 1;
169 break;
170 case 'k':
171 keep = 1;
172 break;
173 case 'N':
174 kernel = optarg;
175 break;
176 case 'z':
177 compress = 1;
178 break;
179 case '?':
180 default:
181 usage();
182 }
183 argc -= optind;
184 argv += optind;
185
186 if (!clear) {
187 if (argc != 1 && argc != 2)
188 usage();
189 savedir = argv[0];
190 }
191 if (argc == 2)
192 kernel = argv[1];
193
194 (void)time(&now);
195 kmem_setup();
196
197 if (clear) {
198 clear_dump();
199 exit(0);
200 }
201
202 if (!dump_exists() && !force)
203 exit(1);
204
205 check_kmem();
206
207 if (panicstr)
208 syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg);
209 else
210 syslog(LOG_ALERT, "reboot");
211
212 get_dumpsize();
213
214 if ((!get_crashtime() || !check_space()) && !force)
215 exit(1);
216
217 save_core();
218
219 if (!keep)
220 clear_dump();
221
222 exit(0);
223}
224
225void
226kmem_setup()
227{
228 int kmem, i;
229 const char *dump_sys;
230 size_t len;
231 long kdumplo; /* block number where dump starts on dumpdev */
232 char *p;
233
234 /*
235 * Some names we need for the currently running system, others for
236 * the system that was running when the dump was made. The values
237 * obtained from the current system are used to look for things in
238 * /dev/kmem that cannot be found in the dump_sys namelist, but are
239 * presumed to be the same (since the disk partitions are probably
240 * the same!)
241 */
242 if ((nlist(getbootfile(), current_nl)) == -1)
243 syslog(LOG_ERR, "%s: nlist: %m", getbootfile());
244 for (i = 0; cursyms[i] != -1; i++)
245 if (current_nl[cursyms[i]].n_value == 0) {
246 syslog(LOG_ERR, "%s: %s not in namelist",
247 getbootfile(), current_nl[cursyms[i]].n_name);
248 exit(1);
249 }
250
251 dump_sys = kernel ? kernel : getbootfile();
252 if ((nlist(dump_sys, dump_nl)) == -1)
253 syslog(LOG_ERR, "%s: nlist: %m", dump_sys);
254 for (i = 0; dumpsyms[i] != -1; i++)
255 if (dump_nl[dumpsyms[i]].n_value == 0) {
256 syslog(LOG_ERR, "%s: %s not in namelist",
257 dump_sys, dump_nl[dumpsyms[i]].n_name);
258 exit(1);
259 }
260
261#if defined(__i386__) || defined(__sparc64__)
262 if (dump_nl[X_KERNBASE].n_value != 0)
263 kernbase = dump_nl[X_KERNBASE].n_value;
264 else
265 kernbase = KERNBASE;
266#endif
267
268 len = sizeof dumpdev;
269 if (sysctlbyname("kern.dumpdev", &dumpdev, &len, NULL, 0) == -1) {
270 syslog(LOG_ERR, "sysctl: kern.dumpdev: %m");
271 exit(1);
272 }
273 if (dumpdev == NODEV) {
274 syslog(LOG_WARNING, "no core dump (no dumpdev)");
275 exit(1);
276 }
277
278 kmem = Open(_PATH_KMEM, O_RDONLY);
279 Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, SEEK_SET);
280 (void)Read(kmem, &kdumplo, sizeof(kdumplo));
281 dumplo = (off_t)kdumplo * DEV_BSIZE;
282 if (verbose)
283 (void)printf("dumplo = %lld (%ld * %d)\n",
284 (long long)dumplo, kdumplo, DEV_BSIZE);
285 Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, SEEK_SET);
286 (void)Read(kmem, &dumpmag, sizeof(dumpmag));
287 find_dev(dumpdev);
288 dumpfd = Open(ddname, O_RDWR);
289 if (kernel)
290 return;
291
292 Lseek(kmem, (off_t)current_nl[X_VERSION].n_value, SEEK_SET);
293 Read(kmem, vers, sizeof(vers));
294 vers[sizeof(vers) - 1] = '\0';
295 p = strchr(vers, '\n');
296 if (p)
297 p[1] = '\0';
298
299 /* Don't fclose(fp), we use kmem later. */
300}
301
302void
303check_kmem()
304{
305 char core_vers[1024], *p;
306
307 DumpRead(dumpfd, core_vers, sizeof(core_vers),
308 dumplo + ok(dump_nl[X_VERSION].n_value), SEEK_SET);
309 core_vers[sizeof(core_vers) - 1] = '\0';
310 p = strchr(core_vers, '\n');
311 if (p)
312 p[1] = '\0';
313 if (strcmp(vers, core_vers) && kernel == 0)
314 syslog(LOG_WARNING,
315 "warning: %s version mismatch:\n\t\"%s\"\nand\t\"%s\"\n",
316 getbootfile(), vers, core_vers);
317 DumpRead(dumpfd, &panicstr, sizeof(panicstr),
318 dumplo + ok(dump_nl[X_PANICSTR].n_value), SEEK_SET);
319 if (panicstr) {
320 DumpRead(dumpfd, panic_mesg, sizeof(panic_mesg),
321 dumplo + ok(panicstr), SEEK_SET);
322 }
323}
324
325/*
326 * Clear the magic number in the dump header.
327 */
328void
329clear_dump()
330{
331 u_long newdumpmag;
332
333 newdumpmag = 0;
334 DumpWrite(dumpfd, &newdumpmag, sizeof(newdumpmag),
335 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET);
336 close(dumpfd);
337}
338
339/*
340 * Check if a dump exists by looking for a magic number in the dump
341 * header.
342 */
343int
344dump_exists()
345{
346 u_long newdumpmag;
347
348 DumpRead(dumpfd, &newdumpmag, sizeof(newdumpmag),
349 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET);
350 if (newdumpmag != dumpmag) {
351 if (verbose)
352 syslog(LOG_WARNING, "magic number mismatch (%x != %x)",
353 newdumpmag, dumpmag);
354 syslog(LOG_WARNING, "no core dump");
355 return (0);
356 }
357 return (1);
358}
359
360char buf[1024 * 1024];
361#define BLOCKSIZE (1<<12)
362#define BLOCKMASK (~(BLOCKSIZE-1))
363
364/*
365 * Save the core dump.
366 */
367void
368save_core()
369{
370 register FILE *fp;
371 register int bounds, ifd, nr, nw;
370 FILE *fp;
371 int bounds, ifd, nr, nw;
372 int hs, he; /* start and end of hole */
373 char path[MAXPATHLEN];
374 mode_t oumask;
375
376 /*
377 * Get the current number and update the bounds file. Do the update
378 * now, because may fail later and don't want to overwrite anything.
379 */
380 (void)snprintf(path, sizeof(path), "%s/bounds", savedir);
381 if ((fp = fopen(path, "r")) == NULL)
382 goto err1;
383 if (fgets(buf, sizeof(buf), fp) == NULL) {
384 if (ferror(fp))
385err1: syslog(LOG_WARNING, "%s: %m", path);
386 bounds = 0;
387 } else
388 bounds = atoi(buf);
389 if (fp != NULL)
390 (void)fclose(fp);
391 if ((fp = fopen(path, "w")) == NULL)
392 syslog(LOG_ERR, "%s: %m", path);
393 else {
394 (void)fprintf(fp, "%d\n", bounds + 1);
395 (void)fclose(fp);
396 }
397
398 /* Create the core file. */
399 oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
400 (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s",
401 savedir, bounds, compress ? ".gz" : "");
402 if (compress)
403 fp = zopen(path, "w");
404 else
405 fp = fopen(path, "w");
406 if (fp == NULL) {
407 syslog(LOG_ERR, "%s: %m", path);
408 exit(1);
409 }
410 (void)umask(oumask);
411
412 /* Seek to the start of the core. */
413 Lseek(dumpfd, dumplo, SEEK_SET);
414
415 /* Copy the core file. */
416 syslog(LOG_NOTICE, "writing %score to %s",
417 compress ? "compressed " : "", path);
418 for (; dumpsize > 0; dumpsize -= nr) {
419 (void)printf("%6dK\r", dumpsize / 1024);
420 (void)fflush(stdout);
421 nr = read(dumpfd, buf, MIN(dumpsize, sizeof(buf)));
422 if (nr <= 0) {
423 if (nr == 0)
424 syslog(LOG_WARNING,
425 "WARNING: EOF on dump device");
426 else
427 syslog(LOG_ERR, "%s: %m", ddname);
428 goto err2;
429 }
430
431 if (compress) {
432 nw = fwrite(buf, 1, nr, fp);
433 } else {
434 for (nw = 0; nw < nr; nw = he) {
435 /* find a contiguous block of zeroes */
436 for (hs = nw; hs < nr; hs += BLOCKSIZE) {
437 for (he = hs; he < nr && buf[he] == 0; ++he)
438 /* nothing */ ;
439 /* is the hole long enough to matter? */
440 if (he >= hs + BLOCKSIZE)
441 break;
442 }
443
444 /* back down to a block boundary */
445 he &= BLOCKMASK;
446
447 /*
448 * 1) Don't go beyond the end of the buffer.
449 * 2) If the end of the buffer is less than
450 * BLOCKSIZE bytes away, we're at the end
451 * of the file, so just grab what's left.
452 */
453 if (hs + BLOCKSIZE > nr)
454 hs = he = nr;
455
456 /*
457 * At this point, we have a partial ordering:
458 * nw <= hs <= he <= nr
459 * If hs > nw, buf[nw..hs] contains non-zero data.
460 * If he > hs, buf[hs..he] is all zeroes.
461 */
462 if (hs > nw)
463 if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
464 break;
465 if (he > hs)
466 if (fseek(fp, he - hs, SEEK_CUR) == -1)
467 break;
468 }
469 }
470 if (nw != nr) {
471 syslog(LOG_ERR, "%s: %m", path);
472err2: syslog(LOG_WARNING,
473 "WARNING: vmcore may be incomplete");
474 (void)printf("\n");
475 exit(1);
476 }
477 }
478
479 (void)fclose(fp);
480
481 /* Copy the kernel. */
482 ifd = Open(kernel ? kernel : getbootfile(), O_RDONLY);
483 (void)snprintf(path, sizeof(path), "%s/kernel.%d%s",
484 savedir, bounds, compress ? ".gz" : "");
485 if (compress)
486 fp = zopen(path, "w");
487 else
488 fp = fopen(path, "w");
489 if (fp == NULL) {
490 syslog(LOG_ERR, "%s: %m", path);
491 exit(1);
492 }
493 syslog(LOG_NOTICE, "writing %skernel to %s",
494 compress ? "compressed " : "", path);
495 while ((nr = read(ifd, buf, sizeof(buf))) > 0) {
496 nw = fwrite(buf, 1, nr, fp);
497 if (nw != nr) {
498 syslog(LOG_ERR, "%s: %m", path);
499 syslog(LOG_WARNING,
500 "WARNING: kernel may be incomplete");
501 exit(1);
502 }
503 }
504 if (nr < 0) {
505 syslog(LOG_ERR, "%s: %m", kernel ? kernel : getbootfile());
506 syslog(LOG_WARNING,
507 "WARNING: kernel may be incomplete");
508 exit(1);
509 }
510 (void)fclose(fp);
511 close(ifd);
512}
513
514/*
515 * Verify that the specified device node exists and matches the
516 * specified device.
517 */
518int
519verify_dev(name, dev)
520 char *name;
372 int hs, he; /* start and end of hole */
373 char path[MAXPATHLEN];
374 mode_t oumask;
375
376 /*
377 * Get the current number and update the bounds file. Do the update
378 * now, because may fail later and don't want to overwrite anything.
379 */
380 (void)snprintf(path, sizeof(path), "%s/bounds", savedir);
381 if ((fp = fopen(path, "r")) == NULL)
382 goto err1;
383 if (fgets(buf, sizeof(buf), fp) == NULL) {
384 if (ferror(fp))
385err1: syslog(LOG_WARNING, "%s: %m", path);
386 bounds = 0;
387 } else
388 bounds = atoi(buf);
389 if (fp != NULL)
390 (void)fclose(fp);
391 if ((fp = fopen(path, "w")) == NULL)
392 syslog(LOG_ERR, "%s: %m", path);
393 else {
394 (void)fprintf(fp, "%d\n", bounds + 1);
395 (void)fclose(fp);
396 }
397
398 /* Create the core file. */
399 oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
400 (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s",
401 savedir, bounds, compress ? ".gz" : "");
402 if (compress)
403 fp = zopen(path, "w");
404 else
405 fp = fopen(path, "w");
406 if (fp == NULL) {
407 syslog(LOG_ERR, "%s: %m", path);
408 exit(1);
409 }
410 (void)umask(oumask);
411
412 /* Seek to the start of the core. */
413 Lseek(dumpfd, dumplo, SEEK_SET);
414
415 /* Copy the core file. */
416 syslog(LOG_NOTICE, "writing %score to %s",
417 compress ? "compressed " : "", path);
418 for (; dumpsize > 0; dumpsize -= nr) {
419 (void)printf("%6dK\r", dumpsize / 1024);
420 (void)fflush(stdout);
421 nr = read(dumpfd, buf, MIN(dumpsize, sizeof(buf)));
422 if (nr <= 0) {
423 if (nr == 0)
424 syslog(LOG_WARNING,
425 "WARNING: EOF on dump device");
426 else
427 syslog(LOG_ERR, "%s: %m", ddname);
428 goto err2;
429 }
430
431 if (compress) {
432 nw = fwrite(buf, 1, nr, fp);
433 } else {
434 for (nw = 0; nw < nr; nw = he) {
435 /* find a contiguous block of zeroes */
436 for (hs = nw; hs < nr; hs += BLOCKSIZE) {
437 for (he = hs; he < nr && buf[he] == 0; ++he)
438 /* nothing */ ;
439 /* is the hole long enough to matter? */
440 if (he >= hs + BLOCKSIZE)
441 break;
442 }
443
444 /* back down to a block boundary */
445 he &= BLOCKMASK;
446
447 /*
448 * 1) Don't go beyond the end of the buffer.
449 * 2) If the end of the buffer is less than
450 * BLOCKSIZE bytes away, we're at the end
451 * of the file, so just grab what's left.
452 */
453 if (hs + BLOCKSIZE > nr)
454 hs = he = nr;
455
456 /*
457 * At this point, we have a partial ordering:
458 * nw <= hs <= he <= nr
459 * If hs > nw, buf[nw..hs] contains non-zero data.
460 * If he > hs, buf[hs..he] is all zeroes.
461 */
462 if (hs > nw)
463 if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
464 break;
465 if (he > hs)
466 if (fseek(fp, he - hs, SEEK_CUR) == -1)
467 break;
468 }
469 }
470 if (nw != nr) {
471 syslog(LOG_ERR, "%s: %m", path);
472err2: syslog(LOG_WARNING,
473 "WARNING: vmcore may be incomplete");
474 (void)printf("\n");
475 exit(1);
476 }
477 }
478
479 (void)fclose(fp);
480
481 /* Copy the kernel. */
482 ifd = Open(kernel ? kernel : getbootfile(), O_RDONLY);
483 (void)snprintf(path, sizeof(path), "%s/kernel.%d%s",
484 savedir, bounds, compress ? ".gz" : "");
485 if (compress)
486 fp = zopen(path, "w");
487 else
488 fp = fopen(path, "w");
489 if (fp == NULL) {
490 syslog(LOG_ERR, "%s: %m", path);
491 exit(1);
492 }
493 syslog(LOG_NOTICE, "writing %skernel to %s",
494 compress ? "compressed " : "", path);
495 while ((nr = read(ifd, buf, sizeof(buf))) > 0) {
496 nw = fwrite(buf, 1, nr, fp);
497 if (nw != nr) {
498 syslog(LOG_ERR, "%s: %m", path);
499 syslog(LOG_WARNING,
500 "WARNING: kernel may be incomplete");
501 exit(1);
502 }
503 }
504 if (nr < 0) {
505 syslog(LOG_ERR, "%s: %m", kernel ? kernel : getbootfile());
506 syslog(LOG_WARNING,
507 "WARNING: kernel may be incomplete");
508 exit(1);
509 }
510 (void)fclose(fp);
511 close(ifd);
512}
513
514/*
515 * Verify that the specified device node exists and matches the
516 * specified device.
517 */
518int
519verify_dev(name, dev)
520 char *name;
521 register dev_t dev;
521 dev_t dev;
522{
523 struct stat sb;
524
525 if (lstat(name, &sb) == -1)
526 return (-1);
527 if (!S_ISCHR(sb.st_mode) || sb.st_rdev != dev)
528 return (-1);
529 return (0);
530}
531
532/*
533 * Find the dump device.
534 *
535 * 1) try devname(3); see if it returns something sensible
536 * 2) scan /dev for the desired node
537 * 3) as a last resort, try to create the node we need
538 */
539void
540find_dev(dev)
522{
523 struct stat sb;
524
525 if (lstat(name, &sb) == -1)
526 return (-1);
527 if (!S_ISCHR(sb.st_mode) || sb.st_rdev != dev)
528 return (-1);
529 return (0);
530}
531
532/*
533 * Find the dump device.
534 *
535 * 1) try devname(3); see if it returns something sensible
536 * 2) scan /dev for the desired node
537 * 3) as a last resort, try to create the node we need
538 */
539void
540find_dev(dev)
541 register dev_t dev;
541 dev_t dev;
542{
543 struct dirent *ent;
544 char *dn, *dnp;
545 DIR *d;
546
547 strcpy(ddname, _PATH_DEV);
548 dnp = ddname + sizeof _PATH_DEV - 1;
549 if ((dn = devname(dev, S_IFCHR)) != NULL) {
550 strcpy(dnp, dn);
551 if (verify_dev(ddname, dev) == 0)
552 return;
553 }
554 if ((d = opendir(_PATH_DEV)) != NULL) {
555 while ((ent = readdir(d))) {
556 strcpy(dnp, ent->d_name);
557 if (verify_dev(ddname, dev) == 0) {
558 closedir(d);
559 return;
560 }
561 }
562 closedir(d);
563 }
564 strcpy(dnp, "dump");
565 if (mknod(ddname, S_IFCHR|S_IRUSR|S_IWUSR, dev) == 0)
566 return;
567 syslog(LOG_ERR, "can't find device %d/%#x", major(dev), minor(dev));
568 exit(1);
569}
570
571/*
572 * Extract the date and time of the crash from the dump header, and
573 * make sure it looks sane (within one week of current date and time).
574 */
575int
576get_crashtime()
577{
578 time_t dumptime; /* Time the dump was taken. */
579
580 DumpRead(dumpfd, &dumptime, sizeof(dumptime),
581 dumplo + ok(dump_nl[X_TIME].n_value), SEEK_SET);
582 if (dumptime == 0) {
583 if (verbose)
584 syslog(LOG_ERR, "dump time is zero");
585 return (0);
586 }
587 (void)printf("savecore: system went down at %s", ctime(&dumptime));
588#define LEEWAY (7 * 86400)
589 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
590 (void)printf("dump time is unreasonable\n");
591 return (0);
592 }
593 return (1);
594}
595
596/*
597 * Extract the size of the dump from the dump header.
598 */
599void
600get_dumpsize()
601{
602 int kdumpsize;
603
604 /* Read the dump size. */
605 DumpRead(dumpfd, &kdumpsize, sizeof(kdumpsize),
606 dumplo + ok(dump_nl[X_DUMPSIZE].n_value), SEEK_SET);
607 dumpsize = (off_t)kdumpsize * getpagesize();
608}
609
610/*
611 * Check that sufficient space is available on the disk that holds the
612 * save directory.
613 */
614int
615check_space()
616{
542{
543 struct dirent *ent;
544 char *dn, *dnp;
545 DIR *d;
546
547 strcpy(ddname, _PATH_DEV);
548 dnp = ddname + sizeof _PATH_DEV - 1;
549 if ((dn = devname(dev, S_IFCHR)) != NULL) {
550 strcpy(dnp, dn);
551 if (verify_dev(ddname, dev) == 0)
552 return;
553 }
554 if ((d = opendir(_PATH_DEV)) != NULL) {
555 while ((ent = readdir(d))) {
556 strcpy(dnp, ent->d_name);
557 if (verify_dev(ddname, dev) == 0) {
558 closedir(d);
559 return;
560 }
561 }
562 closedir(d);
563 }
564 strcpy(dnp, "dump");
565 if (mknod(ddname, S_IFCHR|S_IRUSR|S_IWUSR, dev) == 0)
566 return;
567 syslog(LOG_ERR, "can't find device %d/%#x", major(dev), minor(dev));
568 exit(1);
569}
570
571/*
572 * Extract the date and time of the crash from the dump header, and
573 * make sure it looks sane (within one week of current date and time).
574 */
575int
576get_crashtime()
577{
578 time_t dumptime; /* Time the dump was taken. */
579
580 DumpRead(dumpfd, &dumptime, sizeof(dumptime),
581 dumplo + ok(dump_nl[X_TIME].n_value), SEEK_SET);
582 if (dumptime == 0) {
583 if (verbose)
584 syslog(LOG_ERR, "dump time is zero");
585 return (0);
586 }
587 (void)printf("savecore: system went down at %s", ctime(&dumptime));
588#define LEEWAY (7 * 86400)
589 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
590 (void)printf("dump time is unreasonable\n");
591 return (0);
592 }
593 return (1);
594}
595
596/*
597 * Extract the size of the dump from the dump header.
598 */
599void
600get_dumpsize()
601{
602 int kdumpsize;
603
604 /* Read the dump size. */
605 DumpRead(dumpfd, &kdumpsize, sizeof(kdumpsize),
606 dumplo + ok(dump_nl[X_DUMPSIZE].n_value), SEEK_SET);
607 dumpsize = (off_t)kdumpsize * getpagesize();
608}
609
610/*
611 * Check that sufficient space is available on the disk that holds the
612 * save directory.
613 */
614int
615check_space()
616{
617 register FILE *fp;
617 FILE *fp;
618 const char *tkernel;
619 off_t minfree, spacefree, totfree, kernelsize, needed;
620 struct stat st;
621 struct statfs fsbuf;
622 char buf[100], path[MAXPATHLEN];
623
624 tkernel = kernel ? kernel : getbootfile();
625 if (stat(tkernel, &st) < 0) {
626 syslog(LOG_ERR, "%s: %m", tkernel);
627 exit(1);
628 }
629 kernelsize = st.st_blocks * S_BLKSIZE;
630
631 if (statfs(savedir, &fsbuf) < 0) {
632 syslog(LOG_ERR, "%s: %m", savedir);
633 exit(1);
634 }
635 spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
636 totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
637
638 (void)snprintf(path, sizeof(path), "%s/minfree", savedir);
639 if ((fp = fopen(path, "r")) == NULL)
640 minfree = 0;
641 else {
642 if (fgets(buf, sizeof(buf), fp) == NULL)
643 minfree = 0;
644 else
645 minfree = atoi(buf);
646 (void)fclose(fp);
647 }
648
649 needed = (dumpsize + kernelsize) / 1024;
650 if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
651 syslog(LOG_WARNING,
652 "no dump, not enough free space on device (%lld available, need %lld)",
653 (long long)(minfree > 0 ? spacefree : totfree),
654 (long long)needed);
655 return (0);
656 }
657 if (spacefree - needed < 0)
658 syslog(LOG_WARNING,
659 "dump performed, but free space threshold crossed");
660 return (1);
661}
662
663int
664Open(name, rw)
665 const char *name;
666 int rw;
667{
668 int fd;
669
670 fd = open(name, rw, 0);
671 if (fd < 0) {
672 syslog(LOG_ERR, "%s: %m", name);
673 exit(1);
674 }
675 return (fd);
676}
677
678int
679Read(fd, bp, size)
680 int fd, size;
681 void *bp;
682{
683 int nr;
684
685 nr = read(fd, bp, size);
686 if (nr != size) {
687 syslog(LOG_ERR, "read: %m");
688 exit(1);
689 }
690 return (nr);
691}
692
693void
694Lseek(fd, off, flag)
695 int fd, flag;
696 off_t off;
697{
698 off_t ret;
699
700 ret = lseek(fd, off, flag);
701 if (ret == -1) {
702 syslog(LOG_ERR, "lseek: %m");
703 exit(1);
704 }
705}
706
707/*
708 * DumpWrite and DumpRead block io requests to the * dump device.
709 */
710#define DUMPBUFSIZE 8192
711void
712DumpWrite(fd, bp, size, off, flag)
713 int fd, size, flag;
714 void *bp;
715 off_t off;
716{
717 unsigned char buf[DUMPBUFSIZE], *p, *q;
718 off_t pos;
719 int i, j;
720
721 if (flag != SEEK_SET) {
722 syslog(LOG_ERR, "lseek: not SEEK_SET");
723 exit(2);
724 }
725 q = bp;
726 while (size) {
727 pos = off & ~(DUMPBUFSIZE - 1);
728 Lseek(fd, pos, flag);
729 (void)Read(fd, buf, sizeof(buf));
730 j = off & (DUMPBUFSIZE - 1);
731 p = buf + j;
732 i = size;
733 if (i > DUMPBUFSIZE - j)
734 i = DUMPBUFSIZE - j;
735 memcpy(p, q, i);
736 Lseek(fd, pos, flag);
737 (void)Write(fd, buf, sizeof(buf));
738 size -= i;
739 q += i;
740 off += i;
741 }
742}
743
744void
745DumpRead(fd, bp, size, off, flag)
746 int fd, size, flag;
747 void *bp;
748 off_t off;
749{
750 unsigned char buf[DUMPBUFSIZE], *p, *q;
751 off_t pos;
752 int i, j;
753
754 if (flag != SEEK_SET) {
755 syslog(LOG_ERR, "lseek: not SEEK_SET");
756 exit(2);
757 }
758 q = bp;
759 while (size) {
760 pos = off & ~(DUMPBUFSIZE - 1);
761 Lseek(fd, pos, flag);
762 (void)Read(fd, buf, sizeof(buf));
763 j = off & (DUMPBUFSIZE - 1);
764 p = buf + j;
765 i = size;
766 if (i > DUMPBUFSIZE - j)
767 i = DUMPBUFSIZE - j;
768 memcpy(q, p, i);
769 size -= i;
770 q += i;
771 off += i;
772 }
773}
774
775void
776Write(fd, bp, size)
777 int fd, size;
778 void *bp;
779{
780 int n;
781
782 n = write(fd, bp, size);
783 if (n < size) {
784 syslog(LOG_ERR, "write: %m");
785 exit(1);
786 }
787}
788
789void
790usage()
791{
792 (void)syslog(LOG_ERR, "usage: savecore [-cfkvz] [-N system] directory");
793 exit(1);
794}
618 const char *tkernel;
619 off_t minfree, spacefree, totfree, kernelsize, needed;
620 struct stat st;
621 struct statfs fsbuf;
622 char buf[100], path[MAXPATHLEN];
623
624 tkernel = kernel ? kernel : getbootfile();
625 if (stat(tkernel, &st) < 0) {
626 syslog(LOG_ERR, "%s: %m", tkernel);
627 exit(1);
628 }
629 kernelsize = st.st_blocks * S_BLKSIZE;
630
631 if (statfs(savedir, &fsbuf) < 0) {
632 syslog(LOG_ERR, "%s: %m", savedir);
633 exit(1);
634 }
635 spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
636 totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
637
638 (void)snprintf(path, sizeof(path), "%s/minfree", savedir);
639 if ((fp = fopen(path, "r")) == NULL)
640 minfree = 0;
641 else {
642 if (fgets(buf, sizeof(buf), fp) == NULL)
643 minfree = 0;
644 else
645 minfree = atoi(buf);
646 (void)fclose(fp);
647 }
648
649 needed = (dumpsize + kernelsize) / 1024;
650 if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
651 syslog(LOG_WARNING,
652 "no dump, not enough free space on device (%lld available, need %lld)",
653 (long long)(minfree > 0 ? spacefree : totfree),
654 (long long)needed);
655 return (0);
656 }
657 if (spacefree - needed < 0)
658 syslog(LOG_WARNING,
659 "dump performed, but free space threshold crossed");
660 return (1);
661}
662
663int
664Open(name, rw)
665 const char *name;
666 int rw;
667{
668 int fd;
669
670 fd = open(name, rw, 0);
671 if (fd < 0) {
672 syslog(LOG_ERR, "%s: %m", name);
673 exit(1);
674 }
675 return (fd);
676}
677
678int
679Read(fd, bp, size)
680 int fd, size;
681 void *bp;
682{
683 int nr;
684
685 nr = read(fd, bp, size);
686 if (nr != size) {
687 syslog(LOG_ERR, "read: %m");
688 exit(1);
689 }
690 return (nr);
691}
692
693void
694Lseek(fd, off, flag)
695 int fd, flag;
696 off_t off;
697{
698 off_t ret;
699
700 ret = lseek(fd, off, flag);
701 if (ret == -1) {
702 syslog(LOG_ERR, "lseek: %m");
703 exit(1);
704 }
705}
706
707/*
708 * DumpWrite and DumpRead block io requests to the * dump device.
709 */
710#define DUMPBUFSIZE 8192
711void
712DumpWrite(fd, bp, size, off, flag)
713 int fd, size, flag;
714 void *bp;
715 off_t off;
716{
717 unsigned char buf[DUMPBUFSIZE], *p, *q;
718 off_t pos;
719 int i, j;
720
721 if (flag != SEEK_SET) {
722 syslog(LOG_ERR, "lseek: not SEEK_SET");
723 exit(2);
724 }
725 q = bp;
726 while (size) {
727 pos = off & ~(DUMPBUFSIZE - 1);
728 Lseek(fd, pos, flag);
729 (void)Read(fd, buf, sizeof(buf));
730 j = off & (DUMPBUFSIZE - 1);
731 p = buf + j;
732 i = size;
733 if (i > DUMPBUFSIZE - j)
734 i = DUMPBUFSIZE - j;
735 memcpy(p, q, i);
736 Lseek(fd, pos, flag);
737 (void)Write(fd, buf, sizeof(buf));
738 size -= i;
739 q += i;
740 off += i;
741 }
742}
743
744void
745DumpRead(fd, bp, size, off, flag)
746 int fd, size, flag;
747 void *bp;
748 off_t off;
749{
750 unsigned char buf[DUMPBUFSIZE], *p, *q;
751 off_t pos;
752 int i, j;
753
754 if (flag != SEEK_SET) {
755 syslog(LOG_ERR, "lseek: not SEEK_SET");
756 exit(2);
757 }
758 q = bp;
759 while (size) {
760 pos = off & ~(DUMPBUFSIZE - 1);
761 Lseek(fd, pos, flag);
762 (void)Read(fd, buf, sizeof(buf));
763 j = off & (DUMPBUFSIZE - 1);
764 p = buf + j;
765 i = size;
766 if (i > DUMPBUFSIZE - j)
767 i = DUMPBUFSIZE - j;
768 memcpy(q, p, i);
769 size -= i;
770 q += i;
771 off += i;
772 }
773}
774
775void
776Write(fd, bp, size)
777 int fd, size;
778 void *bp;
779{
780 int n;
781
782 n = write(fd, bp, size);
783 if (n < size) {
784 syslog(LOG_ERR, "write: %m");
785 exit(1);
786 }
787}
788
789void
790usage()
791{
792 (void)syslog(LOG_ERR, "usage: savecore [-cfkvz] [-N system] directory");
793 exit(1);
794}