Deleted Added
full compact
savecore.c (96049) savecore.c (96103)
1/*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * Copyright (c) 1986, 1992, 1993
36 * The Regents of the University of California. All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 */
66
67#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * Copyright (c) 1986, 1992, 1993
36 * The Regents of the University of California. All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 */
66
67#include <sys/cdefs.h>
68__FBSDID("$FreeBSD: head/sbin/savecore/savecore.c 96049 2002-05-05 01:04:00Z fenner $");
68__FBSDID("$FreeBSD: head/sbin/savecore/savecore.c 96103 2002-05-06 08:27:21Z marcel $");
69
70#include <sys/param.h>
71#include <sys/disk.h>
72#include <sys/kerneldump.h>
73#include <sys/param.h>
74#include <sys/mount.h>
75#include <sys/stat.h>
76#include <errno.h>
77#include <fcntl.h>
78#include <fstab.h>
79#include <paths.h>
80#include <stdarg.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <syslog.h>
85#include <time.h>
86#include <unistd.h>
87
88int compress, clear, force, keep, verbose; /* flags */
89int nfound, nsaved, nerr; /* statistics */
90
91extern FILE *zopen(const char *, const char *);
92
93static void
94printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
95 int bounds)
96{
97 uint64_t dumplen;
98 time_t t;
99
100 fprintf(f, "Good dump found on device %s\n", device);
101 fprintf(f, " Architecture: %s\n", h->architecture);
102 fprintf(f, " Architecture version: %d\n",
103 dtoh32(h->architectureversion));
104 dumplen = dtoh64(h->dumplength);
105 fprintf(f, " Dump length: %lldB (%lld MB)\n", (long long)dumplen,
106 (long long)(dumplen >> 20));
107 fprintf(f, " Blocksize: %d\n", dtoh32(h->blocksize));
108 t = dtoh64(h->dumptime);
109 fprintf(f, " Dumptime: %s", ctime(&t));
110 fprintf(f, " Hostname: %s\n", h->hostname);
111 fprintf(f, " Versionstring: %s", h->versionstring);
112 fprintf(f, " Panicstring: %s\n", h->panicstring);
113 fprintf(f, " Bounds: %d\n", bounds);
114 fflush(f);
115}
116
117static int
118getbounds(void) {
119 FILE *fp;
120 char buf[6];
121 int ret;
122
123 ret = 0;
124
125 if ((fp = fopen("bounds", "r")) == NULL) {
126 syslog(LOG_WARNING, "unable to open bounds file, using 0");
127 goto newfile;
128 }
129
130 if (fgets(buf, sizeof buf, fp) == NULL) {
131 syslog(LOG_WARNING, "unable to read from bounds, using 0");
132 fclose(fp);
133 goto newfile;
134 }
135
136 errno = 0;
137 ret = (int)strtol(buf, NULL, 10);
138 if (ret == 0 && (errno == EINVAL || errno == ERANGE))
139 syslog(LOG_WARNING, "invalid value found in bounds, using 0");
140
141newfile:
142
143 if ((fp = fopen("bounds", "w")) == NULL) {
144 syslog(LOG_WARNING, "unable to write to bounds file: %m");
145 goto done;
146 }
147
148 if (verbose)
149 printf("bounds number: %d\n", ret);
150
151 fprintf(fp, "%d\n", (ret + 1));
152 fclose(fp);
153
154done:
155 return (ret);
156}
157
158/*
159 * Check that sufficient space is available on the disk that holds the
160 * save directory.
161 */
162static int
163check_space(char *savedir, off_t dumpsize)
164{
165 FILE *fp;
166 off_t minfree, spacefree, totfree, needed;
167 struct statfs fsbuf;
168 char buf[100], path[MAXPATHLEN];
169
170 if (statfs(savedir, &fsbuf) < 0) {
171 syslog(LOG_ERR, "%s: %m", savedir);
172 exit(1);
173 }
174 spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
175 totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
176
177 (void)snprintf(path, sizeof(path), "%s/minfree", savedir);
178 if ((fp = fopen(path, "r")) == NULL)
179 minfree = 0;
180 else {
181 if (fgets(buf, sizeof(buf), fp) == NULL)
182 minfree = 0;
183 else
184 minfree = atoi(buf);
185 (void)fclose(fp);
186 }
187
188 needed = dumpsize / 1024 + 2; /* 2 for info file */
189 if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
190 syslog(LOG_WARNING,
191 "no dump, not enough free space on device (%lld available, need %lld)",
192 (long long)(minfree > 0 ? spacefree : totfree),
193 (long long)needed);
194 return (0);
195 }
196 if (spacefree - needed < 0)
197 syslog(LOG_WARNING,
198 "dump performed, but free space threshold crossed");
199 return (1);
200}
201
202#define BLOCKSIZE (1<<12)
203#define BLOCKMASK (~(BLOCKSIZE-1))
204
205static void
206DoFile(char *savedir, const char *device)
207{
208 struct kerneldumpheader kdhf, kdhl;
209 char buf[1024 * 1024];
210 off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
211 FILE *info, *fp;
212 int fd, fdinfo, error, wl;
213 int nr, nw, hs, he;
214 int bounds;
215 u_int sectorsize;
216 mode_t oumask;
217
218 dmpcnt = 0;
219 mediasize = 0;
220
221 if (verbose)
222 printf("checking for kernel dump on device %s\n", device);
223
224 fd = open(device, O_RDWR);
225 if (fd < 0) {
226 syslog(LOG_ERR, "%s: %m", device);
227 return;
228 }
229 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
230 if (!error)
231 error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
232 if (error) {
233 syslog(LOG_ERR,
234 "couldn't find media and/or sector size of %s: %m", device);
235 goto closefd;
236 }
237
238 if (verbose) {
239 printf("mediasize = %lld\n", (long long)mediasize);
240 printf("sectorsize = %u\n", sectorsize);
241 }
242
243 lasthd = mediasize - sectorsize;
244 lseek(fd, lasthd, SEEK_SET);
245 error = read(fd, &kdhl, sizeof kdhl);
246 if (error != sizeof kdhl) {
247 syslog(LOG_ERR,
248 "error reading last dump header at offset %lld in %s: %m",
249 (long long)lasthd, device);
250 goto closefd;
251 }
252 if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
253 if (verbose)
254 printf("magic mismatch on last dump header on %s\n",
255 device);
256
257 if (force == 0)
258 goto closefd;
259
260 if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED,
261 sizeof kdhl.magic) == 0) {
262 if (verbose)
263 printf("forcing magic on %s\n", device);
264 memcpy(kdhl.magic, KERNELDUMPMAGIC,
265 sizeof kdhl.magic);
266 } else {
267 syslog(LOG_ERR, "unable to force dump - bad magic");
268 goto closefd;
269 }
270 }
271 if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
272 syslog(LOG_ERR,
273 "unknown version (%d) in last dump header on %s",
274 dtoh32(kdhl.version), device);
275 goto closefd;
276 }
277
278 nfound++;
279 if (clear)
280 goto nuke;
281
282 if (kerneldump_parity(&kdhl)) {
283 syslog(LOG_ERR,
284 "parity error on last dump header on %s", device);
285 nerr++;
286 goto closefd;
287 }
288 dumpsize = dtoh64(kdhl.dumplength);
289 firsthd = lasthd - dumpsize - sizeof kdhf;
290 lseek(fd, firsthd, SEEK_SET);
291 error = read(fd, &kdhf, sizeof kdhf);
292 if (error != sizeof kdhf) {
293 syslog(LOG_ERR,
294 "error reading first dump header at offset %lld in %s: %m",
295 (long long)firsthd, device);
296 nerr++;
297 goto closefd;
298 }
299 if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
300 syslog(LOG_ERR,
301 "first and last dump headers disagree on %s", device);
302 nerr++;
303 goto closefd;
304 }
305
306 if (kdhl.panicstring[0])
307 syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring);
308 else
309 syslog(LOG_ALERT, "reboot");
310
311 if (verbose)
312 printf("Checking for available free space\n");
313 if (!check_space(savedir, dumpsize)) {
314 nerr++;
315 goto closefd;
316 }
317
318 bounds = getbounds();
319
320 sprintf(buf, "info.%d", bounds);
321
322 /*
323 * Create or overwrite any existing files.
324 */
325 fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
326 if (fdinfo < 0) {
327 syslog(LOG_ERR, "%s: %m", buf);
328 nerr++;
329 goto closefd;
330 }
331 oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
332 if (compress) {
333 sprintf(buf, "vmcore.%d.gz", bounds);
334 fp = zopen(buf, "w");
335 } else {
336 sprintf(buf, "vmcore.%d", bounds);
337 fp = fopen(buf, "w");
338 }
339 if (fp == NULL) {
340 syslog(LOG_ERR, "%s: %m", buf);
341 close(fdinfo);
342 nerr++;
343 goto closefd;
344 }
345 (void)umask(oumask);
346
347 info = fdopen(fdinfo, "w");
348
349 if (verbose)
350 printheader(stdout, &kdhl, device, bounds);
351
352 printheader(info, &kdhl, device, bounds);
353 fclose(info);
354
355 syslog(LOG_NOTICE, "writing %score to %s",
356 compress ? "compressed " : "", buf);
357
358 while (dumpsize > 0) {
359 wl = sizeof(buf);
360 if (wl > dumpsize)
361 wl = dumpsize;
362 nr = read(fd, buf, wl);
363 if (nr != wl) {
364 if (nr == 0)
365 syslog(LOG_WARNING,
366 "WARNING: EOF on dump device");
367 else
368 syslog(LOG_ERR, "read error on %s: %m", device);
369 nerr++;
370 goto closeall;
371 }
372 if (compress) {
373 nw = fwrite(buf, 1, wl, fp);
374 } else {
375 for (nw = 0; nw < nr; nw = he) {
376 /* find a contiguous block of zeroes */
377 for (hs = nw; hs < nr; hs += BLOCKSIZE) {
378 for (he = hs; he < nr && buf[he] == 0; ++he)
379 /* nothing */ ;
380 /* is the hole long enough to matter? */
381 if (he >= hs + BLOCKSIZE)
382 break;
383 }
384
385 /* back down to a block boundary */
386 he &= BLOCKMASK;
387
388 /*
389 * 1) Don't go beyond the end of the buffer.
390 * 2) If the end of the buffer is less than
391 * BLOCKSIZE bytes away, we're at the end
392 * of the file, so just grab what's left.
393 */
394 if (hs + BLOCKSIZE > nr)
395 hs = he = nr;
396
397 /*
398 * At this point, we have a partial ordering:
399 * nw <= hs <= he <= nr
400 * If hs > nw, buf[nw..hs] contains non-zero data.
401 * If he > hs, buf[hs..he] is all zeroes.
402 */
403 if (hs > nw)
404 if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
405 break;
406 if (he > hs)
407 if (fseek(fp, he - hs, SEEK_CUR) == -1)
408 break;
409 }
410 }
411 if (nw != wl) {
412 syslog(LOG_ERR,
413 "write error on vmcore.%d file: %m", bounds);
414 syslog(LOG_WARNING,
415 "WARNING: vmcore may be incomplete");
416 nerr++;
417 goto closeall;
418 }
419 if (verbose) {
420 dmpcnt += wl;
69
70#include <sys/param.h>
71#include <sys/disk.h>
72#include <sys/kerneldump.h>
73#include <sys/param.h>
74#include <sys/mount.h>
75#include <sys/stat.h>
76#include <errno.h>
77#include <fcntl.h>
78#include <fstab.h>
79#include <paths.h>
80#include <stdarg.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <syslog.h>
85#include <time.h>
86#include <unistd.h>
87
88int compress, clear, force, keep, verbose; /* flags */
89int nfound, nsaved, nerr; /* statistics */
90
91extern FILE *zopen(const char *, const char *);
92
93static void
94printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
95 int bounds)
96{
97 uint64_t dumplen;
98 time_t t;
99
100 fprintf(f, "Good dump found on device %s\n", device);
101 fprintf(f, " Architecture: %s\n", h->architecture);
102 fprintf(f, " Architecture version: %d\n",
103 dtoh32(h->architectureversion));
104 dumplen = dtoh64(h->dumplength);
105 fprintf(f, " Dump length: %lldB (%lld MB)\n", (long long)dumplen,
106 (long long)(dumplen >> 20));
107 fprintf(f, " Blocksize: %d\n", dtoh32(h->blocksize));
108 t = dtoh64(h->dumptime);
109 fprintf(f, " Dumptime: %s", ctime(&t));
110 fprintf(f, " Hostname: %s\n", h->hostname);
111 fprintf(f, " Versionstring: %s", h->versionstring);
112 fprintf(f, " Panicstring: %s\n", h->panicstring);
113 fprintf(f, " Bounds: %d\n", bounds);
114 fflush(f);
115}
116
117static int
118getbounds(void) {
119 FILE *fp;
120 char buf[6];
121 int ret;
122
123 ret = 0;
124
125 if ((fp = fopen("bounds", "r")) == NULL) {
126 syslog(LOG_WARNING, "unable to open bounds file, using 0");
127 goto newfile;
128 }
129
130 if (fgets(buf, sizeof buf, fp) == NULL) {
131 syslog(LOG_WARNING, "unable to read from bounds, using 0");
132 fclose(fp);
133 goto newfile;
134 }
135
136 errno = 0;
137 ret = (int)strtol(buf, NULL, 10);
138 if (ret == 0 && (errno == EINVAL || errno == ERANGE))
139 syslog(LOG_WARNING, "invalid value found in bounds, using 0");
140
141newfile:
142
143 if ((fp = fopen("bounds", "w")) == NULL) {
144 syslog(LOG_WARNING, "unable to write to bounds file: %m");
145 goto done;
146 }
147
148 if (verbose)
149 printf("bounds number: %d\n", ret);
150
151 fprintf(fp, "%d\n", (ret + 1));
152 fclose(fp);
153
154done:
155 return (ret);
156}
157
158/*
159 * Check that sufficient space is available on the disk that holds the
160 * save directory.
161 */
162static int
163check_space(char *savedir, off_t dumpsize)
164{
165 FILE *fp;
166 off_t minfree, spacefree, totfree, needed;
167 struct statfs fsbuf;
168 char buf[100], path[MAXPATHLEN];
169
170 if (statfs(savedir, &fsbuf) < 0) {
171 syslog(LOG_ERR, "%s: %m", savedir);
172 exit(1);
173 }
174 spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
175 totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
176
177 (void)snprintf(path, sizeof(path), "%s/minfree", savedir);
178 if ((fp = fopen(path, "r")) == NULL)
179 minfree = 0;
180 else {
181 if (fgets(buf, sizeof(buf), fp) == NULL)
182 minfree = 0;
183 else
184 minfree = atoi(buf);
185 (void)fclose(fp);
186 }
187
188 needed = dumpsize / 1024 + 2; /* 2 for info file */
189 if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
190 syslog(LOG_WARNING,
191 "no dump, not enough free space on device (%lld available, need %lld)",
192 (long long)(minfree > 0 ? spacefree : totfree),
193 (long long)needed);
194 return (0);
195 }
196 if (spacefree - needed < 0)
197 syslog(LOG_WARNING,
198 "dump performed, but free space threshold crossed");
199 return (1);
200}
201
202#define BLOCKSIZE (1<<12)
203#define BLOCKMASK (~(BLOCKSIZE-1))
204
205static void
206DoFile(char *savedir, const char *device)
207{
208 struct kerneldumpheader kdhf, kdhl;
209 char buf[1024 * 1024];
210 off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
211 FILE *info, *fp;
212 int fd, fdinfo, error, wl;
213 int nr, nw, hs, he;
214 int bounds;
215 u_int sectorsize;
216 mode_t oumask;
217
218 dmpcnt = 0;
219 mediasize = 0;
220
221 if (verbose)
222 printf("checking for kernel dump on device %s\n", device);
223
224 fd = open(device, O_RDWR);
225 if (fd < 0) {
226 syslog(LOG_ERR, "%s: %m", device);
227 return;
228 }
229 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
230 if (!error)
231 error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
232 if (error) {
233 syslog(LOG_ERR,
234 "couldn't find media and/or sector size of %s: %m", device);
235 goto closefd;
236 }
237
238 if (verbose) {
239 printf("mediasize = %lld\n", (long long)mediasize);
240 printf("sectorsize = %u\n", sectorsize);
241 }
242
243 lasthd = mediasize - sectorsize;
244 lseek(fd, lasthd, SEEK_SET);
245 error = read(fd, &kdhl, sizeof kdhl);
246 if (error != sizeof kdhl) {
247 syslog(LOG_ERR,
248 "error reading last dump header at offset %lld in %s: %m",
249 (long long)lasthd, device);
250 goto closefd;
251 }
252 if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
253 if (verbose)
254 printf("magic mismatch on last dump header on %s\n",
255 device);
256
257 if (force == 0)
258 goto closefd;
259
260 if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED,
261 sizeof kdhl.magic) == 0) {
262 if (verbose)
263 printf("forcing magic on %s\n", device);
264 memcpy(kdhl.magic, KERNELDUMPMAGIC,
265 sizeof kdhl.magic);
266 } else {
267 syslog(LOG_ERR, "unable to force dump - bad magic");
268 goto closefd;
269 }
270 }
271 if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
272 syslog(LOG_ERR,
273 "unknown version (%d) in last dump header on %s",
274 dtoh32(kdhl.version), device);
275 goto closefd;
276 }
277
278 nfound++;
279 if (clear)
280 goto nuke;
281
282 if (kerneldump_parity(&kdhl)) {
283 syslog(LOG_ERR,
284 "parity error on last dump header on %s", device);
285 nerr++;
286 goto closefd;
287 }
288 dumpsize = dtoh64(kdhl.dumplength);
289 firsthd = lasthd - dumpsize - sizeof kdhf;
290 lseek(fd, firsthd, SEEK_SET);
291 error = read(fd, &kdhf, sizeof kdhf);
292 if (error != sizeof kdhf) {
293 syslog(LOG_ERR,
294 "error reading first dump header at offset %lld in %s: %m",
295 (long long)firsthd, device);
296 nerr++;
297 goto closefd;
298 }
299 if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
300 syslog(LOG_ERR,
301 "first and last dump headers disagree on %s", device);
302 nerr++;
303 goto closefd;
304 }
305
306 if (kdhl.panicstring[0])
307 syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring);
308 else
309 syslog(LOG_ALERT, "reboot");
310
311 if (verbose)
312 printf("Checking for available free space\n");
313 if (!check_space(savedir, dumpsize)) {
314 nerr++;
315 goto closefd;
316 }
317
318 bounds = getbounds();
319
320 sprintf(buf, "info.%d", bounds);
321
322 /*
323 * Create or overwrite any existing files.
324 */
325 fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
326 if (fdinfo < 0) {
327 syslog(LOG_ERR, "%s: %m", buf);
328 nerr++;
329 goto closefd;
330 }
331 oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
332 if (compress) {
333 sprintf(buf, "vmcore.%d.gz", bounds);
334 fp = zopen(buf, "w");
335 } else {
336 sprintf(buf, "vmcore.%d", bounds);
337 fp = fopen(buf, "w");
338 }
339 if (fp == NULL) {
340 syslog(LOG_ERR, "%s: %m", buf);
341 close(fdinfo);
342 nerr++;
343 goto closefd;
344 }
345 (void)umask(oumask);
346
347 info = fdopen(fdinfo, "w");
348
349 if (verbose)
350 printheader(stdout, &kdhl, device, bounds);
351
352 printheader(info, &kdhl, device, bounds);
353 fclose(info);
354
355 syslog(LOG_NOTICE, "writing %score to %s",
356 compress ? "compressed " : "", buf);
357
358 while (dumpsize > 0) {
359 wl = sizeof(buf);
360 if (wl > dumpsize)
361 wl = dumpsize;
362 nr = read(fd, buf, wl);
363 if (nr != wl) {
364 if (nr == 0)
365 syslog(LOG_WARNING,
366 "WARNING: EOF on dump device");
367 else
368 syslog(LOG_ERR, "read error on %s: %m", device);
369 nerr++;
370 goto closeall;
371 }
372 if (compress) {
373 nw = fwrite(buf, 1, wl, fp);
374 } else {
375 for (nw = 0; nw < nr; nw = he) {
376 /* find a contiguous block of zeroes */
377 for (hs = nw; hs < nr; hs += BLOCKSIZE) {
378 for (he = hs; he < nr && buf[he] == 0; ++he)
379 /* nothing */ ;
380 /* is the hole long enough to matter? */
381 if (he >= hs + BLOCKSIZE)
382 break;
383 }
384
385 /* back down to a block boundary */
386 he &= BLOCKMASK;
387
388 /*
389 * 1) Don't go beyond the end of the buffer.
390 * 2) If the end of the buffer is less than
391 * BLOCKSIZE bytes away, we're at the end
392 * of the file, so just grab what's left.
393 */
394 if (hs + BLOCKSIZE > nr)
395 hs = he = nr;
396
397 /*
398 * At this point, we have a partial ordering:
399 * nw <= hs <= he <= nr
400 * If hs > nw, buf[nw..hs] contains non-zero data.
401 * If he > hs, buf[hs..he] is all zeroes.
402 */
403 if (hs > nw)
404 if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
405 break;
406 if (he > hs)
407 if (fseek(fp, he - hs, SEEK_CUR) == -1)
408 break;
409 }
410 }
411 if (nw != wl) {
412 syslog(LOG_ERR,
413 "write error on vmcore.%d file: %m", bounds);
414 syslog(LOG_WARNING,
415 "WARNING: vmcore may be incomplete");
416 nerr++;
417 goto closeall;
418 }
419 if (verbose) {
420 dmpcnt += wl;
421 printf("%llu\r", dmpcnt);
421 printf("%llu\r", (unsigned long long)dmpcnt);
422 fflush(stdout);
423 }
424 dumpsize -= wl;
425 }
426 if (verbose)
427 printf("\n");
428
429 if (fclose(fp) < 0) {
430 syslog(LOG_ERR, "error on vmcore.%d: %m", bounds);
431 nerr++;
432 goto closeall;
433 }
434 nsaved++;
435
436 if (verbose)
437 printf("dump saved\n");
438
439nuke:
440 if (clear || !keep) {
441 if (verbose)
442 printf("clearing dump header\n");
443 memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic);
444 lseek(fd, lasthd, SEEK_SET);
445 error = write(fd, &kdhl, sizeof kdhl);
446 if (error != sizeof kdhl)
447 syslog(LOG_ERR,
448 "error while clearing the dump header: %m");
449 }
450 close(fd);
451 return;
452
453closeall:
454 fclose(fp);
455
456closefd:
457 close(fd);
458}
459
460static void
461usage(void)
462{
463 fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n");
464 exit (1);
465}
466
467int
468main(int argc, char **argv)
469{
470 int i, ch, error;
471 struct fstab *fsp;
472 char *savedir;
473
474 openlog("savecore", LOG_PERROR, LOG_DAEMON);
475
476 savedir = strdup(".");
477 if (savedir == NULL) {
478 syslog(LOG_ERR, "Cannot allocate memory");
479 exit(1);
480 }
481 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
482 switch(ch) {
483 case 'c':
484 clear = 1;
485 break;
486 case 'k':
487 keep = 1;
488 break;
489 case 'v':
490 verbose = 1;
491 break;
492 case 'f':
493 force = 1;
494 break;
495 case 'z':
496 compress = 1;
497 break;
498 case 'd': /* Obsolete */
499 case 'N':
500 case '?':
501 default:
502 usage();
503 }
504 argc -= optind;
505 argv += optind;
506 if (argc >= 1) {
507 error = chdir(argv[0]);
508 if (error) {
509 syslog(LOG_ERR, "chdir(%s): %m", argv[0]);
510 exit(1);
511 }
512 savedir = argv[0];
513 argc--;
514 argv++;
515 }
516 if (argc == 0) {
517 for (;;) {
518 fsp = getfsent();
519 if (fsp == NULL)
520 break;
521 if (strcmp(fsp->fs_vfstype, "swap") &&
522 strcmp(fsp->fs_vfstype, "dump"))
523 continue;
524 DoFile(savedir, fsp->fs_spec);
525 }
526 } else {
527 for (i = 0; i < argc; i++)
528 DoFile(savedir, argv[i]);
529 }
530
531 /* Emit minimal output. */
532 if (nfound == 0)
533 syslog(LOG_WARNING, "no dumps found");
534 else if (nsaved == 0) {
535 if (nerr != 0)
536 syslog(LOG_WARNING, "unsaved dumps found but not saved");
537 else
538 syslog(LOG_WARNING, "no unsaved dumps found");
539 }
540
541 return (0);
542}
422 fflush(stdout);
423 }
424 dumpsize -= wl;
425 }
426 if (verbose)
427 printf("\n");
428
429 if (fclose(fp) < 0) {
430 syslog(LOG_ERR, "error on vmcore.%d: %m", bounds);
431 nerr++;
432 goto closeall;
433 }
434 nsaved++;
435
436 if (verbose)
437 printf("dump saved\n");
438
439nuke:
440 if (clear || !keep) {
441 if (verbose)
442 printf("clearing dump header\n");
443 memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic);
444 lseek(fd, lasthd, SEEK_SET);
445 error = write(fd, &kdhl, sizeof kdhl);
446 if (error != sizeof kdhl)
447 syslog(LOG_ERR,
448 "error while clearing the dump header: %m");
449 }
450 close(fd);
451 return;
452
453closeall:
454 fclose(fp);
455
456closefd:
457 close(fd);
458}
459
460static void
461usage(void)
462{
463 fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n");
464 exit (1);
465}
466
467int
468main(int argc, char **argv)
469{
470 int i, ch, error;
471 struct fstab *fsp;
472 char *savedir;
473
474 openlog("savecore", LOG_PERROR, LOG_DAEMON);
475
476 savedir = strdup(".");
477 if (savedir == NULL) {
478 syslog(LOG_ERR, "Cannot allocate memory");
479 exit(1);
480 }
481 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
482 switch(ch) {
483 case 'c':
484 clear = 1;
485 break;
486 case 'k':
487 keep = 1;
488 break;
489 case 'v':
490 verbose = 1;
491 break;
492 case 'f':
493 force = 1;
494 break;
495 case 'z':
496 compress = 1;
497 break;
498 case 'd': /* Obsolete */
499 case 'N':
500 case '?':
501 default:
502 usage();
503 }
504 argc -= optind;
505 argv += optind;
506 if (argc >= 1) {
507 error = chdir(argv[0]);
508 if (error) {
509 syslog(LOG_ERR, "chdir(%s): %m", argv[0]);
510 exit(1);
511 }
512 savedir = argv[0];
513 argc--;
514 argv++;
515 }
516 if (argc == 0) {
517 for (;;) {
518 fsp = getfsent();
519 if (fsp == NULL)
520 break;
521 if (strcmp(fsp->fs_vfstype, "swap") &&
522 strcmp(fsp->fs_vfstype, "dump"))
523 continue;
524 DoFile(savedir, fsp->fs_spec);
525 }
526 } else {
527 for (i = 0; i < argc; i++)
528 DoFile(savedir, argv[i]);
529 }
530
531 /* Emit minimal output. */
532 if (nfound == 0)
533 syslog(LOG_WARNING, "no dumps found");
534 else if (nsaved == 0) {
535 if (nerr != 0)
536 syslog(LOG_WARNING, "unsaved dumps found but not saved");
537 else
538 syslog(LOG_WARNING, "no unsaved dumps found");
539 }
540
541 return (0);
542}