overwrite ".." if first entry, "." if second entry in directory
[unix-history] / usr / src / sbin / savecore / savecore.c
CommitLineData
261f5d78 1#ifndef lint
ce4fd43b 2static char *sccsid = "@(#)savecore.c 4.13 (Berkeley) 83/07/02";
261f5d78
SL
3#endif
4
d112e9ff 5/*
97d6da0b 6 * savecore
d112e9ff 7 */
d112e9ff
BJ
8#include <stdio.h>
9#include <nlist.h>
10#include <sys/param.h>
11#include <sys/dir.h>
12#include <sys/stat.h>
ce4fd43b 13#include <sys/time.h>
d112e9ff 14
97d6da0b
BJ
15#define DAY (60L*60L*24L)
16#define LEEWAY (3*DAY)
17
18#define eq(a,b) (!strcmp(a,b))
261f5d78 19#ifdef vax
97d6da0b 20#define ok(number) ((number)&0x7fffffff)
261f5d78
SL
21#else
22#define ok(number) (number)
23#endif
97d6da0b 24
d112e9ff 25#define SHUTDOWNLOG "/usr/adm/shutdownlog"
d112e9ff
BJ
26
27struct nlist nl[] = {
28#define X_DUMPDEV 0
29 { "_dumpdev" },
30#define X_DUMPLO 1
31 { "_dumplo" },
32#define X_TIME 2
33 { "_time" },
261f5d78
SL
34#define X_DUMPSIZE 3
35 { "_dumpsize" },
d112e9ff
BJ
36#define X_VERSION 4
37 { "_version" },
38#define X_PANICSTR 5
39 { "_panicstr" },
261f5d78
SL
40#define X_DUMPMAG 6
41 { "_dumpmag" },
42 { "" },
d112e9ff
BJ
43};
44
f6cc4b0d 45char *system;
97d6da0b
BJ
46char *dirname; /* directory to save dumps in */
47char *ddname; /* name of dump device */
48char *find_dev();
49dev_t dumpdev; /* dump device */
50time_t dumptime; /* time the dump was taken */
51int dumplo; /* where dump starts on dumpdev */
261f5d78
SL
52int dumpsize; /* amount of memory dumped */
53int dumpmag; /* magic number in dump */
97d6da0b
BJ
54time_t now; /* current date */
55char *path();
56unsigned malloc();
57char *ctime();
58char vers[80];
59char core_vers[80];
60char panic_mesg[80];
61int panicstr;
97d6da0b
BJ
62off_t lseek();
63off_t Lseek();
d112e9ff
BJ
64
65main(argc, argv)
97d6da0b
BJ
66 char **argv;
67 int argc;
d112e9ff 68{
97d6da0b 69
f6cc4b0d
BJ
70 if (argc != 2 && argc != 3) {
71 fprintf(stderr, "usage: savecore dirname [ system ]\n");
d112e9ff
BJ
72 exit(1);
73 }
74 dirname = argv[1];
f6cc4b0d
BJ
75 if (argc == 3)
76 system = argv[2];
97d6da0b 77 if (access(dirname, 2) < 0) {
d112e9ff 78 perror(dirname);
97d6da0b 79 exit(1);
d112e9ff 80 }
d112e9ff 81 read_kmem();
d112e9ff
BJ
82}
83
739955be
KM
84int
85dump_exists()
86{
87 register int dumpfd;
88 int word;
89
90 dumpfd = Open(ddname, 0);
261f5d78 91 Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_DUMPMAG].n_value)), 0);
739955be
KM
92 Read(dumpfd, (char *)&word, sizeof word);
93 close(dumpfd);
261f5d78 94 return (word == dumpmag);
739955be
KM
95}
96
97clear_dump()
98{
99 register int dumpfd;
100 int zero = 0;
101
102 dumpfd = Open(ddname, 1);
261f5d78 103 Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_DUMPMAG].n_value)), 0);
739955be
KM
104 Write(dumpfd, (char *)&zero, sizeof zero);
105 close(dumpfd);
106}
107
97d6da0b
BJ
108char *
109find_dev(dev, type)
110 register dev_t dev;
111 register int type;
d112e9ff 112{
d112e9ff 113 struct stat statb;
f0326588 114 char *dp;
d112e9ff
BJ
115
116 strcpy(devname, "/dev/");
97d6da0b 117 if (stat(devname, &statb)) {
d112e9ff 118 perror(devname);
97d6da0b
BJ
119 continue;
120 }
121 if ((statb.st_mode&S_IFMT) != type)
122 continue;
123 if (dev == statb.st_rdev) {
97d6da0b
BJ
124 dp = (char *)malloc(strlen(devname)+1);
125 strcpy(dp, devname);
126 return dp;
d112e9ff
BJ
127 }
128 }
261f5d78
SL
129 fprintf(stderr, "savecore: Can't find device %d,%d\n",
130 major(dev), minor(dev));
97d6da0b
BJ
131 exit(1);
132 /*NOTREACHED*/
d112e9ff
BJ
133}
134
d112e9ff
BJ
135read_kmem()
136{
137 int kmem;
138 FILE *fp;
139 register char *cp;
140
141 nlist("/vmunix", nl);
97d6da0b 142 if (nl[X_DUMPDEV].n_value == 0) {
261f5d78 143 fprintf(stderr, "savecore: /vmunix: dumpdev not in namelist\n");
97d6da0b 144 exit(1);
d112e9ff 145 }
97d6da0b 146 if (nl[X_DUMPLO].n_value == 0) {
261f5d78 147 fprintf(stderr, "savecore: /vmunix: dumplo not in namelist\n");
97d6da0b 148 exit(1);
d112e9ff 149 }
97d6da0b 150 if (nl[X_TIME].n_value == 0) {
261f5d78 151 fprintf(stderr, "savecore: /vmunix: time not in namelist\n");
97d6da0b 152 exit(1);
d112e9ff 153 }
261f5d78
SL
154 if (nl[X_DUMPSIZE].n_value == 0) {
155 fprintf(stderr, "savecore: /vmunix: dumpsize not in namelist\n");
97d6da0b 156 exit(1);
d112e9ff 157 }
97d6da0b 158 if (nl[X_VERSION].n_value == 0) {
261f5d78 159 fprintf(stderr, "savecore: /vmunix: version not in namelist\n");
97d6da0b 160 exit(1);
d112e9ff 161 }
97d6da0b 162 if (nl[X_PANICSTR].n_value == 0) {
261f5d78 163 fprintf(stderr, "savecore: /vmunix: panicstr not in namelist\n");
97d6da0b 164 exit(1);
d112e9ff 165 }
261f5d78
SL
166 if (nl[X_DUMPMAG].n_value == 0) {
167 fprintf(stderr, "savecore: /vmunix: dumpmag not in namelist\n");
739955be
KM
168 exit(1);
169 }
d112e9ff 170 kmem = Open("/dev/kmem", 0);
97d6da0b 171 Lseek(kmem, (long)nl[X_DUMPDEV].n_value, 0);
261f5d78 172 Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
97d6da0b 173 Lseek(kmem, (long)nl[X_DUMPLO].n_value, 0);
261f5d78 174 Read(kmem, (char *)&dumplo, sizeof (dumplo));
261f5d78
SL
175 Lseek(kmem, (long)nl[X_DUMPMAG].n_value, 0);
176 Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
d112e9ff
BJ
177 dumplo *= 512L;
178 ddname = find_dev(dumpdev, S_IFBLK);
97d6da0b 179 if ((fp = fdopen(kmem, "r")) == NULL) {
261f5d78 180 fprintf(stderr, "savecore: Couldn't fdopen kmem\n");
97d6da0b 181 exit(1);
d112e9ff 182 }
f6cc4b0d
BJ
183 if (system)
184 return;
97d6da0b 185 fseek(fp, (long)nl[X_VERSION].n_value, 0);
d112e9ff
BJ
186 fgets(vers, sizeof vers, fp);
187 fclose(fp);
798fe693
SL
188}
189
5638c7c2
SL
190check_kmem()
191{
798fe693
SL
192 FILE *fp;
193 register char *cp;
194
97d6da0b 195 if ((fp = fopen(ddname, "r")) == NULL) {
d112e9ff 196 perror(ddname);
97d6da0b 197 exit(1);
d112e9ff 198 }
97d6da0b 199 fseek(fp, (off_t)(dumplo+ok(nl[X_VERSION].n_value)), 0);
d112e9ff
BJ
200 fgets(core_vers, sizeof core_vers, fp);
201 fclose(fp);
40dd70fc 202 if (!eq(vers, core_vers))
261f5d78
SL
203 fprintf(stderr,
204 "savecore: Warning: vmunix version mismatch:\n\t%sand\n\t%s",
205 vers, core_vers);
97d6da0b
BJ
206 fp = fopen(ddname, "r");
207 fseek(fp, (off_t)(dumplo + ok(nl[X_PANICSTR].n_value)), 0);
208 fread((char *)&panicstr, sizeof panicstr, 1, fp);
209 if (panicstr) {
210 fseek(fp, dumplo + ok(panicstr), 0);
d112e9ff
BJ
211 cp = panic_mesg;
212 do
213 *cp = getc(fp);
214 while (*cp++);
d112e9ff 215 }
97d6da0b 216 fclose(fp);
f6cc4b0d 217}
d112e9ff 218
97d6da0b
BJ
219get_crashtime()
220{
d112e9ff 221 int dumpfd;
20f89b8d 222 time_t clobber = (time_t)0;
d112e9ff 223
f6cc4b0d
BJ
224 if (system)
225 return (1);
97d6da0b
BJ
226 Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_TIME].n_value)), 0);
227 Read(dumpfd, (char *)&dumptime, sizeof dumptime);
d112e9ff 228 close(dumpfd);
261f5d78
SL
229 if (dumptime == 0)
230 return (0);
d112e9ff
BJ
231 printf("System went down at %s", ctime(&dumptime));
232 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
233 printf("Dump time is unreasonable\n");
261f5d78 234 return (0);
d112e9ff 235 }
261f5d78 236 return (1);
d112e9ff
BJ
237}
238
97d6da0b
BJ
239char *
240path(file)
241 char *file;
d112e9ff 242{
97d6da0b 243 register char *cp = (char *)malloc(strlen(file) + strlen(dirname) + 2);
d112e9ff 244
97d6da0b
BJ
245 (void) strcpy(cp, dirname);
246 (void) strcat(cp, "/");
247 (void) strcat(cp, file);
261f5d78 248 return (cp);
d112e9ff
BJ
249}
250
d112e9ff
BJ
251check_space()
252{
253 struct stat dsb;
254 register char *ddev;
e84afc49 255 int dfd, spacefree;
798fe693 256 struct fs fs;
d112e9ff 257
97d6da0b
BJ
258 if (stat(dirname, &dsb) < 0) {
259 perror(dirname);
260 exit(1);
261 }
d112e9ff
BJ
262 ddev = find_dev(dsb.st_dev, S_IFBLK);
263 dfd = Open(ddev, 0);
798fe693
SL
264 Lseek(dfd, (long)(SBLOCK * DEV_BSIZE), 0);
265 Read(dfd, (char *)&fs, sizeof fs);
d112e9ff 266 close(dfd);
e84afc49
SL
267 spacefree = fs.fs_cstotal.cs_nbfree * fs.fs_bsize / 1024;
268 if (read_number("minfree") > spacefree) {
261f5d78
SL
269 fprintf(stderr,
270 "savecore: Dump omitted, not enough space on device\n");
97d6da0b 271 return (0);
d112e9ff 272 }
798fe693
SL
273 if (fs.fs_cstotal.cs_nbfree * fs.fs_frag + fs.fs_cstotal.cs_nffree <
274 fs.fs_dsize * fs.fs_minfree / 100)
275 fprintf(stderr,
276 "Dump performed, but free space threshold crossed\n");
97d6da0b 277 return (1);
d112e9ff
BJ
278}
279
d112e9ff 280read_number(fn)
97d6da0b 281 char *fn;
d112e9ff
BJ
282{
283 char lin[80];
284 register FILE *fp;
285
286 if ((fp = fopen(path(fn), "r")) == NULL)
261f5d78 287 return (0);
97d6da0b
BJ
288 if (fgets(lin, 80, fp) == NULL) {
289 fclose(fp);
261f5d78 290 return (0);
d112e9ff 291 }
97d6da0b 292 fclose(fp);
261f5d78 293 return (atoi(lin));
d112e9ff
BJ
294}
295
296save_core()
297{
298 register int n;
97d6da0b 299 char buffer[32*NBPG];
d112e9ff
BJ
300 register char *cp = buffer;
301 register int ifd, ofd, bounds;
302 register FILE *fp;
303
304 bounds = read_number("bounds");
f6cc4b0d 305 ifd = Open(system?system:"/vmunix", 0);
d112e9ff
BJ
306 while((n = Read(ifd, cp, BUFSIZ)) > 0)
307 Write(ofd, cp, n);
308 close(ifd);
309 close(ofd);
d112e9ff 310 ifd = Open(ddname, 0);
5638c7c2
SL
311 Lseek(ifd, (off_t)(dumplo + ok(nl[X_DUMPSIZE].n_value)), 0);
312 Read(ifd, (char *)&dumpsize, sizeof (dumpsize));
798fe693
SL
313 sprintf(cp, "vmcore.%d", bounds);
314 ofd = Create(path(cp), 0644);
97d6da0b 315 Lseek(ifd, (off_t)dumplo, 0);
261f5d78
SL
316 printf("Saving %d bytes of image in vmcore.%d\n", NBPG*dumpsize,
317 bounds);
318 while (dumpsize > 0) {
319 n = Read(ifd, cp, (dumpsize > 32 ? 32 : dumpsize) * NBPG);
d112e9ff 320 Write(ofd, cp, n);
261f5d78 321 dumpsize -= n/NBPG;
d112e9ff
BJ
322 }
323 close(ifd);
324 close(ofd);
325 fp = fopen(path("bounds"), "w");
326 fprintf(fp, "%d\n", bounds+1);
327 fclose(fp);
328}
329
330char *days[] = {
331 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
332};
333
334char *months[] = {
335 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
336 "Oct", "Nov", "Dec"
337};
338
339log_entry()
340{
341 FILE *fp;
342 struct tm *tm, *localtime();
343
344 tm = localtime(&now);
97d6da0b
BJ
345 fp = fopen("/usr/adm/shutdownlog", "a");
346 if (fp == 0)
347 return;
d112e9ff
BJ
348 fseek(fp, 0L, 2);
349 fprintf(fp, "%02d:%02d %s %s %2d, %4d. Reboot", tm->tm_hour,
350 tm->tm_min, days[tm->tm_wday], months[tm->tm_mon],
351 tm->tm_mday, tm->tm_year + 1900);
352 if (panicstr)
97d6da0b 353 fprintf(fp, " after panic: %s\n", panic_mesg);
d112e9ff
BJ
354 else
355 putc('\n', fp);
356 fclose(fp);
357}
97d6da0b
BJ
358
359/*
360 * Versions of std routines that exit on error.
361 */
362
363Open(name, rw)
364 char *name;
365 int rw;
366{
367 int fd;
368
369 if ((fd = open(name, rw)) < 0) {
370 perror(name);
371 exit(1);
372 }
373 return fd;
374}
375
376Read(fd, buff, size)
377 int fd, size;
378 char *buff;
379{
380 int ret;
381
382 if ((ret = read(fd, buff, size)) < 0) {
383 perror("read");
384 exit(1);
385 }
386 return ret;
387}
388
389off_t
390Lseek(fd, off, flag)
391 int fd, flag;
392 long off;
393{
394 long ret;
395
396 if ((ret = lseek(fd, off, flag)) == -1L) {
397 perror("lseek");
398 exit(1);
399 }
400 return ret;
401}
402
403Create(file, mode)
404 char *file;
405 int mode;
406{
407 register int fd;
408
409 if ((fd = creat(file, mode)) < 0) {
410 perror(file);
411 exit(1);
412 }
413 return fd;
414}
415
416Write(fd, buf, size)
417 int fd, size;
418 char *buf;
97d6da0b
BJ
419{
420
421 if (write(fd, buf, size) < size) {
422 perror("write");
423 exit(1);
424 }
425}