Import version 1.8.3
[s390-tools.git] / zdump / zgetdump.c
blob1ef312cf907ecc1b3a0b7006dccc6deab12630fb
1 /*
2 * zgetdump
3 * Description: The zgetdump tool takes as input the dump device
4 * and writes its contents to standard output,
5 * which you can redirect to a specific file.
7 * Copyright IBM Corp. 2001, 2006.
8 * Author(s): Despina Papadopoulou
9 * Frank Munzert <munzert@de.ibm.com>
12 #include "zgetdump.h"
13 #include "zt_common.h"
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/time.h>
21 #include <sys/utsname.h>
22 #include <fcntl.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include <time.h>
26 #include <getopt.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <errno.h>
30 #include <sys/mtio.h>
32 /* from linux/fs.h */
33 #define BLKSSZGET _IO(0x12,104)
34 #define BLKFLSBUF _IO(0x12,97)
36 #define HEADER_SIZE 4096
37 #define BLOCK_SIZE 32768
38 #define MVDUMPER_SIZE 4096
39 #define PARTN_MASK ((1 << 2) - 1)
40 #define MAGIC_BLOCK_OFFSET_ECKD 3
41 #define MAGIC_OFFSET_FBA -0x1000
42 #define HEXINSTR "\x0d\x10\x47\xf0" /* BASR + 1st halfword of BC */
43 #define ARCH_S390 1
44 #define ARCH_S390X 2
45 #define VERSION_NO_DUMP_DEVICE -1
47 #define SYSFS_BUSDIR "/sys/bus/ccw/devices"
49 #if defined(__s390x__)
50 #define FMT64 "l"
51 #else
52 #define FMT64 "ll"
53 #endif
55 /* definitions */
57 char *help_text =
58 "The zgetdump tool takes as input the dump device and writes its contents\n"\
59 "to standard output, which you can redirect to a specific file.\n"\
60 "zgetdump can also check, whether a DASD device contains a valid dumper.\n\n"\
61 "Usage:\n"\
62 "Copy dump from <dumpdevice> to stdout:\n"\
63 " > zgetdump <dumpdevice>\n"\
64 "Print dump header and check if dump is valid - for single tape or DASD:\n"\
65 " > zgetdump [-i | --info] <dumpdevice>\n"\
66 "Print dump header and check if dump is valid - for all volumes of a\n"
67 "multi-volume tape dump:\n"\
68 " > zgetdump [-i | --info] [-a | --all] <dumpdevice>\n"\
69 "Check dump device:\n"\
70 " > zgetdump [-d | --device] <dasd_device>\n"\
71 "Print version info:\n"\
72 " > zgetdump [-v | --version]\n"\
73 "Print this text:\n"\
74 " > zgetdump [-h | --help]\n\n"\
75 "Examples for single-volume DASD:\n"\
76 "> zgetdump -d /dev/dasdc\n"\
77 "> zgetdump -i /dev/dasdc1\n"\
78 "> zgetdump /dev/dasdc1 > dump_file\n";
80 char *usage_note =
81 "Usage:\n"\
82 "> zgetdump <dumpdevice>\n"\
83 "> zgetdump -i <dumpdevice>\n"\
84 "> zgetdump -i -a <dumpdevice>\n"\
85 "> zgetdump -d <device>\n"\
86 "More info:\n"\
87 "> zgetdump -h\n";
89 /* Version info */
90 static const char version_text[] = "zgetdump: version "RELEASE_STRING;
92 /* Copyright notice */
93 static const char copyright_notice[] = "Copyright IBM Corp. 2001, 2008";
95 /* global variables */
97 s390_dump_header_t header;
98 s390_dump_end_marker_t end_marker;
99 char read_buffer[BLOCK_SIZE];
100 struct timeval h_time_begin, h_time_end;
102 int option_a_set;
103 int option_i_set;
104 int option_d_set;
105 char dump_device[PATH_MAX];
107 /* end of definitions */
109 /* Use uname to check whether we run s390x kernel */
110 int check_kernel_mode()
112 struct utsname uname_struct;
113 if (uname(&uname_struct)) {
114 fprintf(stderr, "Unable to get name and information about "
115 "current kernel. \n");
116 perror("");
117 return 1;
119 if (strncmp(uname_struct.machine, "s390x", 5) == 0) {
120 fprintf(stderr, "=========================================="
121 "=======\n");
122 fprintf(stderr, "WARNING: You are running an s390x (ESAME) "
123 "kernel.\n");
124 fprintf(stderr, " Your dump tool however is s390 "
125 "(ESA).\n");
126 fprintf(stderr, "=========================================="
127 "=======\n");
129 return 0;
132 /* Read dump tool from DASD device */
133 int read_dumper(int fd, int32_t offset, struct dump_tool *buffer, int whence)
135 if (lseek(fd, offset, whence) == -1) {
136 perror("Cannot seek on device");
137 return 1;
139 if (read(fd, buffer, sizeof(struct dump_tool)) !=
140 sizeof(struct dump_tool)) {
141 perror("Cannot read dump tool from device");
142 return 1;
144 return 0;
147 /* Use stat to check whether user provided input is a block device or a
148 * partition */
149 enum devnode_type check_device(char *device, int print)
151 struct stat stat_struct;
153 if (stat(device, &stat_struct)) {
154 fprintf(stderr, "Unable to get device status for "
155 "'%s'. \n", device);
156 perror("");
157 return IS_NOBLOCK;
159 if (!(S_ISBLK(stat_struct.st_mode))) {
160 fprintf(stderr, "'%s' is not a block device. \n", dump_device);
161 return IS_NOBLOCK;
163 if (minor(stat_struct.st_rdev) & PARTN_MASK) {
164 if (print)
165 fprintf(stderr, "Partition '%s' (%d/%d) specified where"
166 " device is required.\n", dump_device,
167 (unsigned short) major(stat_struct.st_rdev),
168 (unsigned short) minor(stat_struct.st_rdev));
169 return IS_PARTITION;
171 return IS_DEVICE;
174 /* Allocate SIZE bytes of memory. Upon success, return pointer to memory.
175 * Return NULL otherwise. */
176 void *misc_malloc(size_t size)
178 void* result;
180 result = malloc(size);
181 if (result == NULL) {
182 fprintf(stderr, "Could not allocate %lld bytes of memory",
183 (unsigned long long) size);
185 return result;
188 char* misc_make_path(char* dirname, char* filename)
190 char* result;
191 size_t len;
193 len = strlen(dirname) + strlen(filename) + 2;
194 result = (char *) misc_malloc(len);
195 if (result == NULL)
196 return NULL;
197 sprintf(result, "%s/%s", dirname, filename);
198 return result;
201 #define TEMP_DEV_MAX_RETRIES 1000
203 /* Make temporary device node for input device identified by its dev_t */
204 int make_temp_devnode(dev_t dev, char** device_node)
206 char* result;
207 char* pathname[] = { getenv("TMPDIR"), "/tmp",
208 getenv("HOME"), "." , "/"};
209 char filename[] = "zgetdump0000";
210 mode_t mode;
211 unsigned int path;
212 int retry;
213 int rc;
214 int fd;
216 mode = S_IFBLK | S_IRWXU;
217 /* Try several locations as directory for the temporary device
218 * node. */
219 for (path=0; path < sizeof(pathname) / sizeof(pathname[0]); path++) {
220 if (pathname[path] == NULL)
221 continue;
222 for (retry=0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
223 sprintf(filename, "zgetdump%04d", retry);
224 result = misc_make_path(pathname[path], filename);
225 if (result == NULL)
226 return 1;
227 rc = mknod(result, mode, dev);
228 if (rc == 0) {
229 /* Need this test to cover 'nodev'-mounted
230 * filesystems. */
231 fd = open(result, O_RDWR);
232 if (fd != -1) {
233 close(fd);
234 *device_node = result;
235 return 0;
237 remove(result);
238 retry = TEMP_DEV_MAX_RETRIES;
239 } else if (errno != EEXIST)
240 retry = TEMP_DEV_MAX_RETRIES;
241 free(result);
244 fprintf(stderr, "Unable to create temporary device node: %s",
245 strerror(errno));
246 return 1;
249 /* Delete temporary device node and free memory allocated for device name. */
250 void free_temp_devnode(char* device_node)
252 if (remove(device_node)) {
253 fprintf(stderr, "Warning: Could not remove "
254 "temporary file %s: %s",
255 device_node, strerror(errno));
257 free(device_node);
261 int open_block_device(char *device)
263 int fd;
265 if (check_device(device, 1) != IS_DEVICE)
266 return -1;
267 fd = open(device, O_RDONLY);
268 if (fd == -1) {
269 fprintf(stderr, "Cannot open device '%s'. \n", device);
270 perror("");
272 return fd;
275 /* Check sysfs, whether a device specified by its bus id is defined and online.
276 * Find out the corresponding dev_t */
277 enum device_status get_device_from_busid(char* bus_id, dev_t *device)
279 char dev_file[PATH_MAX];
280 char temp_file[PATH_MAX];
281 char buffer[10];
282 struct dirent *direntp;
283 int fd, minor, major;
284 DIR *fd1;
286 fd1 = opendir(SYSFS_BUSDIR);
287 if (!fd1) {
288 fprintf(stderr, "Could not open %s (err = %i).\n",
289 SYSFS_BUSDIR, errno);
290 exit(1); /* sysfs info not available */
292 closedir(fd1);
293 snprintf(dev_file, PATH_MAX, "%s/%s", SYSFS_BUSDIR, bus_id);
294 fd1 = opendir(dev_file);
295 if (!fd1)
296 return UNDEFINED; /* device with devno does not exist */
297 snprintf(temp_file, PATH_MAX, "%s/online", dev_file);
298 fd = open(temp_file, O_RDONLY);
299 if (read(fd, buffer, 1) == -1) {
300 perror("Could not read online attribute.");
301 exit(1);
303 close(fd);
304 if (buffer[0] != '1')
305 return OFFLINE; /* device with devno is not online */
306 while ((direntp = readdir(fd1)))
307 if (strncmp(direntp->d_name, "block:", 6) == 0)
308 break;
309 closedir(fd1);
310 if (direntp == NULL) {
311 snprintf(dev_file, PATH_MAX, "%s/%s/block", SYSFS_BUSDIR,
312 bus_id);
313 fd1 = opendir(dev_file);
314 if (!fd1) {
315 fprintf(stderr, "Could not open %s (err = %i).\n",
316 dev_file, errno);
317 exit(1);
319 while ((direntp = readdir(fd1)))
320 if (strncmp(direntp->d_name, "dasd", 4) == 0)
321 break;
322 closedir(fd1);
323 if (direntp == NULL) {
324 fprintf(stderr, "Problem with contents of %s.\n",
325 dev_file);
326 exit(1);
329 snprintf(temp_file, PATH_MAX, "%s/%s/dev", dev_file, direntp->d_name);
330 fd = open(temp_file, O_RDONLY);
331 if (read(fd, buffer, sizeof(buffer)) == -1) {
332 perror("Could not read dev file.");
333 exit(1);
335 close(fd);
336 if (sscanf(buffer, "%i:%i", &major, &minor) != 2) {
337 fprintf(stderr, "Malformed content of %s: %s\n",
338 temp_file, buffer);
339 exit(1);
341 *device = makedev(major, minor);
342 return ONLINE;
345 /* Read dump tool, multi-volume dump parameter table, and dump header from the
346 * input dump volume. Check input dump volume for
347 * - identical dump parameter table (that is it belongs to the same dump set)
348 * - valid magic number in the dump tool
349 * - valid dump signature in the dump header
350 * and set the volume's signature accordingly */
351 int get_mvdump_volume_info(struct disk_info *vol, uint32_t vol_nr, off_t offset,
352 struct mvdump_parm_table *table)
354 int fd, rc;
355 ssize_t n_read;
356 char* temp_devnode;
357 struct dump_tool dumper;
358 struct mvdump_parm_table vol_table;
360 vol->signature = INVALID;
361 rc = make_temp_devnode(vol->device, &temp_devnode);
362 if (rc)
363 return 1;
364 fd = open_block_device(temp_devnode);
365 if (fd == -1) {
366 free_temp_devnode(temp_devnode);
367 return 1;
369 /* We read partition data via the device node. If another process
370 * has changed partition data via the partition node, the corresponding
371 * device node might still have old data in its buffers. Flush buffers
372 * to keep things in sync */
373 if (ioctl(fd, BLKFLSBUF, 0)) {
374 perror("BLKFLSBUF failed");
375 goto out;
377 if (read_dumper(fd, offset, &dumper, SEEK_SET))
378 goto out;
379 if (lseek(fd, offset + MVDUMPER_SIZE, SEEK_SET) !=
380 offset + MVDUMPER_SIZE) {
381 perror("Cannot seek on device");
382 goto out;
384 n_read = read(fd, &vol_table, sizeof(vol_table));
385 if (n_read == -1) {
386 perror("Cannot read multi-volume dump table");
387 goto out;
389 /* Check whether dump table on user specified dump device is
390 * identical to the one found on this device */
391 if (memcmp(&vol_table, table, sizeof(vol_table))) {
392 printf("ERROR: Orphaned multi-volume dump device '%s'\n",
393 dump_device);
394 goto out;
396 if (lseek(fd, vol->start_offset, SEEK_SET) != vol->start_offset) {
397 perror("Cannot seek on device");
398 goto out;
400 n_read = read(fd, &header, HEADER_SIZE);
401 if (n_read == -1) {
402 perror("Cannot read dump header");
403 goto out;
405 free_temp_devnode(temp_devnode);
406 close(fd);
407 if ((header.dh_mvdump_signature == DUMP_MAGIC_S390) &&
408 (strncmp(dumper.magic, "ZMULT64", 7) == 0)) {
409 vol->signature = VALID;
410 if ((header.dh_volnr == vol_nr) && (header.dh_memory_size != 0))
411 vol->signature = ACTIVE;
413 return 0;
414 out:
415 free_temp_devnode(temp_devnode);
416 close(fd);
417 return 1;
420 /* Read multi-volume dump parameter table from dump device and fill in the
421 * fields of the disk_info array */
422 int get_mvdump_info(int fd, int block_size, int *count,
423 struct disk_info vol[])
425 int i, rc = 0;
426 off_t offset;
427 ssize_t n_read;
428 struct mvdump_parm_table table;
430 offset = MAGIC_BLOCK_OFFSET_ECKD * block_size + MVDUMPER_SIZE;
431 if (lseek(fd, offset, SEEK_SET) != offset) {
432 fprintf(stderr, "Cannot seek on device '%s'.\n",
433 dump_device);
434 perror("");
435 return 1;
437 n_read = read(fd, &table, sizeof(table));
438 if (n_read == -1) {
439 perror("Cannot read multi-volume dump table");
440 return 1;
442 *count = table.num_param;
443 for (i = 0; i < table.num_param; i++) {
444 sprintf(vol[i].bus_id, "0.0.%04x", table.param[i].devno);
445 vol[i].start_offset = table.param[i].start_blk;
446 vol[i].start_offset *= table.param[i].blocksize << 8;
447 vol[i].part_size = (table.param[i].end_blk -
448 table.param[i].start_blk + 1);
449 vol[i].part_size *= table.param[i].blocksize << 8;
450 vol[i].status = get_device_from_busid(vol[i].bus_id,
451 &vol[i].device);
452 if (vol[i].status == ONLINE) {
453 offset = MAGIC_BLOCK_OFFSET_ECKD *
454 table.param[i].blocksize << 8;
455 rc = get_mvdump_volume_info(&vol[i], i, offset,
456 &table);
457 if (rc)
458 return rc;
461 return 0;
464 /* Print dump size limit as specified in zipl -d or zipm -M */
465 void print_size_limit_info(uint64_t memory)
467 fprintf(stderr, "Dump size limit: ");
468 if (memory == (uint64_t) -1)
469 fprintf(stderr, "none\n");
470 else
471 fprintf(stderr, "%lldMB\n", (unsigned long long) memory /
472 (1024LL * 1024LL));
475 /* Print multi-volume dump device information for --device option */
476 void print_mvdump_info(int version, int count, struct disk_info vol[],
477 uint64_t memory, int force)
479 int i;
481 fprintf(stderr, "'%s' is part of Version %i multi-volume dump,\n"
482 "which is spread along the following DASD volumes:\n",
483 dump_device, version);
484 for (i = 0; i < count; i++) {
485 switch(vol[i].status) {
486 case UNDEFINED:
487 fprintf(stderr, "%s (not defined)\n", vol[i].bus_id);
488 break;
489 case OFFLINE:
490 fprintf(stderr, "%s (offline)\n", vol[i].bus_id);
491 break;
492 case ONLINE:
493 fprintf(stderr, "%s (online, ", vol[i].bus_id);
494 if (vol[i].signature == INVALID)
495 fprintf(stderr, "invalid)\n");
496 else
497 fprintf(stderr, "valid)\n");
498 break;
501 print_size_limit_info(memory);
502 fprintf(stderr, "Force option specified: ");
503 if (force)
504 fprintf(stderr, "yes\n");
505 else
506 fprintf(stderr, "no\n");
509 /* Print single-volume dump device information for --device option */
510 int print_dump_info(int version, int dumper_arch, uint64_t memory)
512 int rc = 0;
514 if (version > 0) {
515 if (dumper_arch == ARCH_S390) {
516 fprintf(stderr, "'%s' is Version %i s390 (ESA) "
517 "dump device.\n", dump_device, version);
518 if (check_kernel_mode())
519 rc = 1;
520 } else
521 fprintf(stderr, "'%s' is Version %i s390x (ESAME) "
522 "dump device.\n", dump_device, version);
523 } else
524 fprintf(stderr, "'%s' is Version 0 dump device. \n",
525 dump_device);
526 print_size_limit_info(memory);
527 return rc;
530 /* Read dump tool on FBA disk and check its magic number */
531 int check_dump_tool_fba(int fd, int *version, int *arch, uint64_t *memory)
533 struct dump_tool dumper;
535 if (read_dumper(fd, MAGIC_OFFSET_FBA, &dumper, SEEK_END))
536 return 1;
537 *memory = dumper.mem;
538 if (strncmp(dumper.magic, "ZDFBA31", 7) == 0) {
539 *version = dumper.version;
540 *arch = ARCH_S390;
541 } else if (strncmp(dumper.magic, "ZDFBA64", 7) == 0) {
542 *version = dumper.version;
543 *arch = ARCH_S390X;
544 } else if ((memcmp(dumper.magic, HEXINSTR, 4) == 0) &&
545 (dumper.code[0] == '\x0d') && (dumper.code[1] == '\xd0'))
546 /* We found basr r13,0 (old dumper) */
547 *version = 0;
548 else
549 *version = VERSION_NO_DUMP_DEVICE;
550 return 0;
553 /* Read dump tool on ECKD disk and check its magic number */
554 int check_dump_tool_eckd(int fd, int *version, int *arch, int *dasd_mv_flag,
555 int *block_size, int *force_specified,
556 uint64_t *memory)
558 struct dump_tool dumper;
560 if (ioctl(fd, BLKSSZGET, block_size)) {
561 fprintf(stderr, "Cannot get blocksize of device %s.\n",
562 dump_device);
563 perror("");
564 return 1;
566 if (read_dumper(fd, MAGIC_BLOCK_OFFSET_ECKD * *block_size, &dumper,
567 SEEK_SET))
568 return 1;
569 *memory = dumper.mem;
570 if (strncmp(dumper.magic, "ZECKD31", 7) == 0) {
571 *version = dumper.version;
572 *arch = ARCH_S390;
573 } else if (strncmp(dumper.magic, "ZECKD64", 7) == 0) {
574 *version = dumper.version;
575 *arch = ARCH_S390X;
576 } else if (strncmp(dumper.magic, "ZMULT64", 7) == 0) {
577 *version = dumper.version;
578 *arch = ARCH_S390X;
579 *dasd_mv_flag = 1;
580 *force_specified = dumper.force;
581 } else if ((memcmp(dumper.magic, HEXINSTR, 4) == 0) &&
582 (dumper.code[0] == '\x0d') && (dumper.code[1] == '\xd0'))
583 /* We found basr r13,0 (old dumper) */
584 *version = 0;
585 else
586 *version = VERSION_NO_DUMP_DEVICE;
587 return 0;
590 void s390_tod_to_timeval(uint64_t todval, struct timeval *xtime)
592 /* adjust todclock to 1970 */
593 todval -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
595 todval >>= 12;
596 xtime->tv_sec = todval / 1000000;
597 xtime->tv_usec = todval % 1000000;
601 int open_dump(char *pathname)
603 int fd;
605 fd = open(pathname, O_RDONLY);
606 if (fd == -1) {
607 perror("Cannot open dump device");
608 exit(1);
609 } else
610 fprintf(stderr, "Dump device: %s\n", pathname);
611 return fd;
615 /* check if device is dasd or tape */
616 enum dump_type dev_type(int fd)
618 struct mtget mymtget;
620 if (ioctl(fd, MTIOCGET, &mymtget) == -1)
621 return IS_DASD;
622 else
623 return IS_TAPE;
626 /* print lkcd header information */
627 void print_lkcd_header(int fd)
629 dump_header_4_1_t dump_header;
631 lseek(fd, 0, SEEK_SET);
632 if (read(fd, &dump_header, sizeof(dump_header)) == -1) {
633 perror("Could not read dump header.");
634 exit(1);
636 fprintf(stderr, "\nThis is a lkcd dump:\n\n");
637 fprintf(stderr,
638 "Memory start : 0x%"FMT64"x\n", dump_header.dh_memory_start);
639 fprintf(stderr,
640 "Memory end : 0x%"FMT64"x\n", dump_header.dh_memory_end);
641 fprintf(stderr,
642 "Physical memory: %"FMT64"d\n", dump_header.dh_memory_size);
643 fprintf(stderr,
644 "Panic string : %s\n", dump_header.dh_panic_string);
645 fprintf(stderr,
646 "Number of pages: %d\n", dump_header.dh_num_dump_pages);
647 fprintf(stderr,
648 "Page size : %d\n", dump_header.dh_dump_page_size);
649 fprintf(stderr,
650 "Magic number : 0x%"FMT64"x\n", dump_header.dh_magic_number);
651 fprintf(stderr,
652 "Version number : %d\n", dump_header.dh_version);
655 void print_s390_header(enum dump_type d_type)
657 s390_tod_to_timeval(header.dh_tod, &h_time_begin);
659 /* as from version 2 of the dump tools */
660 /* volume numbers are used */
662 if ((d_type == IS_TAPE) && (header.dh_version >= 2)) {
663 fprintf(stderr, "\nTape Volume %i", header.dh_volnr);
664 if (header.dh_volnr != 0)
665 fprintf(stderr, " of a multi volume dump.\n");
666 else
667 fprintf(stderr, "\n");
670 /* don't print header */
671 /* for all subsequent tapes/disks */
672 /* of a multi-volume tape/disk dump */
674 if ((d_type == IS_DASD) || (header.dh_volnr == 0)) {
675 if (header.dh_magic_number != DUMP_MAGIC_S390) {
676 fprintf(stderr, "===================================="
677 "===============\n");
678 fprintf(stderr, "WARNING: This does not look like a "
679 "valid s390 dump!\n");
680 fprintf(stderr, "===================================="
681 "===============\n");
683 fprintf(stderr, "\n>>> Dump header information <<<\n");
684 fprintf(stderr, "Dump created on: %s\n",
685 ctime(&h_time_begin.tv_sec));
686 fprintf(stderr, "Magic number:\t 0x%"FMT64"x\n",
687 header.dh_magic_number);
688 fprintf(stderr, "Version number:\t %d\n", header.dh_version);
689 fprintf(stderr, "Header size:\t %d\n", header.dh_header_size);
690 fprintf(stderr, "Page size:\t %d\n", header.dh_page_size);
691 fprintf(stderr, "Dumped memory:\t %"FMT64"d\n",
692 header.dh_memory_size);
693 fprintf(stderr, "Dumped pages:\t %u\n", header.dh_num_pages);
694 if (header.dh_version >= 3) {
695 fprintf(stderr, "Real memory:\t %"FMT64"d\n",
696 header.dh_real_memory_size);
698 fprintf(stderr, "cpu id:\t\t 0x%"FMT64"x\n", header.dh_cpu_id);
699 if (header.dh_version >= 2) {
700 switch (header.dh_arch) {
701 case 1: fprintf(stderr, "System Arch:\t s390 (ESA)\n");
702 break;
703 case 2: fprintf(stderr,
704 "System Arch:\t s390x (ESAME)\n");
705 break;
706 default:
707 fprintf(stderr, "System Arch:\t <unknown>\n");
708 break;
710 switch (header.dh_build_arch) {
711 case 1: fprintf(stderr, "Build Arch:\t s390 (ESA)\n");
712 break;
713 case 2: fprintf(stderr,
714 "Build Arch:\t s390x (ESAME)\n");
715 break;
716 default:
717 fprintf(stderr, "Build Arch:\t <unknown>\n");
718 break;
721 fprintf(stderr, ">>> End of Dump header <<<\n\n");
725 /* print header information */
726 void get_header(int fd)
728 ssize_t n_read;
730 n_read = read(fd, &header, HEADER_SIZE);
731 if (n_read == -1) {
732 perror("Cannot read dump header");
733 close(fd);
734 exit(1);
738 /* copy header to stdout */
739 void write_header()
741 ssize_t rc;
743 memcpy(read_buffer, &header, sizeof(header));
744 rc = write(STDOUT_FILENO, read_buffer, header.dh_header_size);
745 if (rc == -1) {
746 perror("\nwrite failed");
747 exit(1);
749 if (rc < header.dh_header_size) {
750 fprintf(stderr, "\nwrite failed: No space left on device\n");
751 exit(1);
755 /* copy partition containing multi-volume dump data to stdout */
756 int mvdump_copy(int fd, uint64_t partsize, uint64_t *totalsize)
758 ssize_t n_read, n_written;
759 uint64_t part_offset;
760 int done = 0;
761 size_t count;
763 part_offset = HEADER_SIZE;
764 do {
765 count = MIN(header.dh_memory_size - *totalsize, BLOCK_SIZE);
766 if (count < BLOCK_SIZE)
767 done = 1;
768 if (partsize - part_offset < count) {
769 count = partsize - part_offset;
770 done = 1;
772 n_read = read(fd, read_buffer, count);
773 if (n_read == -1) {
774 perror("\nread failed");
775 return 1;
777 n_read = (n_read >> 12) << 12;
778 n_written = write(STDOUT_FILENO, read_buffer, n_read);
779 if (n_written == -1) {
780 perror("\nwrite failed");
781 return 1;
783 if (n_written < n_read) {
784 fprintf(stderr, "\nwrite failed: "
785 "No space left on device\n");
786 return 1;
788 part_offset += n_written;
789 *totalsize += n_written;
790 if (part_offset % (header.dh_memory_size / 32) == HEADER_SIZE)
791 fprintf(stderr, ".");
792 } while (!done);
793 fprintf(stderr, "\n");
794 return 0;
797 /* copy the dump to stdout */
798 int get_dump(int fd, int d_type)
800 int ret, bsr;
801 ssize_t n_read, n_written;
802 struct mtop mymtop;
803 uint64_t i;
805 ret = 0;
806 if (d_type == IS_DASD) {
807 i = 0;
808 do {
809 n_read = read(fd, read_buffer, BLOCK_SIZE);
810 n_written = write(STDOUT_FILENO, read_buffer, n_read);
811 if (n_written == -1) {
812 perror("\nwrite failed");
813 exit(1);
815 if (n_written < n_read) {
816 fprintf(stderr, "\nwrite failed: "
817 "No space left on device\n");
818 exit(1);
820 i += n_read;
821 if (i % (header.dh_memory_size / 32) == 0)
822 fprintf(stderr, ".");
823 } while (i < header.dh_memory_size && n_read != 0
824 && n_written >= 0);
825 } else if (d_type == IS_TAPE) {
826 /* write to stdout while not ENDOFVOL or DUMP_END */
827 if (header.dh_volnr != 0)
828 fprintf(stderr, "Reading dump content ");
829 for (i = 0; i < (header.dh_memory_size/BLOCK_SIZE); i++) {
830 n_read = read(fd, read_buffer, BLOCK_SIZE);
831 if (i % ((header.dh_memory_size/BLOCK_SIZE) / 32) == 0)
832 fprintf(stderr, ".");
833 if (strncmp(read_buffer, "ENDOFVOL", 8) == 0) {
834 fprintf(stderr, "\nEnd of Volume reached.\n");
835 ret = 1;
836 break;
837 } else if (strncmp(read_buffer, "DUMP_END", 8) == 0) {
838 ret = 2;
839 break;
840 } else {
841 n_written = write(STDOUT_FILENO, read_buffer,
842 n_read);
843 if (n_written == -1) {
844 perror("\nwrite failed");
845 exit(1);
847 if (n_written < n_read) {
848 fprintf(stderr, "\nwrite failed: "
849 "No space left on device\n");
850 exit(1);
854 if (ret == 2) {
855 /* we go back a record, so dump_end_times gets called */
856 mymtop.mt_count = 1;
857 mymtop.mt_op = MTBSR;
858 bsr = ioctl(fd, MTIOCTOP, &mymtop);
859 if (bsr != 0) {
860 fprintf(stderr,
861 "Tape operation MTBSR failed.\n");
862 exit(1);
866 return ret;
869 /* check for DUMP_END and see */
870 /* if dump ended after it started (!!!) */
871 int dump_end_times(int fd)
873 int ret;
875 if (read(fd, &end_marker, sizeof(end_marker)) == -1) {
876 perror("Could not read end marker.");
877 exit(1);
879 s390_tod_to_timeval(end_marker.end_time, &h_time_end);
880 if ((strncmp(end_marker.end_string, "DUMP_END", 8) == 0) &&
881 ((h_time_end.tv_sec - h_time_begin.tv_sec) >= 0)) {
882 fprintf(stderr, "\nDump ended on:\t %s\n",
883 ctime(&h_time_end.tv_sec));
884 ret = 0;
885 } else
886 ret = -1;
887 return ret;
890 int check_and_write_end_marker(int fd)
892 if (dump_end_times(fd) == 0) {
893 ssize_t rc;
894 rc = write(STDOUT_FILENO, &end_marker,
895 sizeof(end_marker));
896 if (rc == -1) {
897 perror("\nwrite failed");
898 return 1;
900 if (rc < (ssize_t) sizeof(end_marker)) {
901 fprintf(stderr, "\nwrite failed: "
902 "No space left on device\n");
903 return 1;
905 fprintf(stderr, "\nDump End Marker found: "
906 "this dump is valid.\n");
907 return 0;
908 } else {
909 fprintf(stderr, "\nThis dump is NOT valid.\n");
910 return 1;
914 /* if a tape is part of the dump (not the last) */
915 /* it should have and ENDOFVOL marker */
916 int vol_end(void)
918 int ret;
920 ret = strncmp(end_marker.end_string, "ENDOFVOL", 8);
921 return ret;
924 /* position the tape in front of an end marker */
925 /* with FSFM and BSR */
926 void tape_forwards(int fd)
928 int ret;
929 struct mtop mymtop;
931 mymtop.mt_count = 1;
932 mymtop.mt_op = MTFSFM;
933 ret = ioctl(fd, MTIOCTOP, &mymtop);
934 if (ret != 0) {
935 fprintf(stderr, "Tape operation FSFM failed.\n");
936 exit(1);
939 mymtop.mt_count = 1;
940 mymtop.mt_op = MTBSR;
941 ret = ioctl(fd, MTIOCTOP, &mymtop);
942 if (ret != 0) {
943 fprintf(stderr, "Tape operation BSR failed.\n");
944 exit(1);
948 /* put current tape offline */
949 /* load & rewind next tape */
950 void load_next(int fd)
952 int ret;
953 struct mtop mymtop;
955 mymtop.mt_count = 1;
956 mymtop.mt_op = MTOFFL;
957 ret = ioctl(fd, MTIOCTOP, &mymtop);
958 if (ret != 0) {
959 fprintf(stderr, "Tape operation OFFL failed.\n");
960 exit(1);
963 mymtop.mt_count = 1;
964 mymtop.mt_op = MTLOAD;
965 ret = ioctl(fd, MTIOCTOP, &mymtop);
966 if (ret != 0) {
967 fprintf(stderr, "Tape operation LOAD failed.\n");
968 exit(1);
969 } else
970 fprintf(stderr, "done\n");
972 mymtop.mt_count = 1;
973 mymtop.mt_op = MTREW;
974 ret = ioctl(fd, MTIOCTOP, &mymtop);
975 if (ret != 0) {
976 fprintf(stderr, "Tape operation REW failed.\n");
977 exit(1);
981 /* parse the commandline options */
982 void parse_opts(int argc, char *argv[])
984 int opt, index;
985 static struct option long_options[] = {
986 {"info", no_argument, 0, 'i'},
987 {"help", no_argument, 0, 'h'},
988 {"version", no_argument, 0, 'v'},
989 {"all", no_argument, 0, 'a'},
990 {"device", no_argument, 0, 'd'},
991 {0, 0, 0, 0 }
993 static const char option_string[] = "iavhd";
995 while ((opt = getopt_long(argc, argv, option_string, long_options,
996 &index)) != -1) {
997 switch (opt) {
998 case 'd':
999 option_d_set = 1;
1000 break;
1001 case 'a':
1002 option_a_set = 1;
1003 break;
1004 case 'i':
1005 option_i_set = 1;
1006 break;
1007 case 'h':
1008 printf(help_text);
1009 exit(0);
1010 case 'v':
1011 printf("%s\n", version_text);
1012 printf("%s\n", copyright_notice);
1013 exit(0);
1014 default:
1015 fprintf(stderr, "Try 'zgetdump --help' for more"
1016 " information.\n");
1017 exit(1);
1021 /* check if -a and -i options are used correctly and check */
1022 /* if devicename has been specified */
1024 if ((option_a_set && !option_i_set) || (optind != argc-1)
1025 || (option_d_set && option_i_set)) {
1026 printf(help_text);
1027 exit(1);
1031 strcpy(dump_device, argv[optind]);
1034 /* Loop along all involved volumes (dump partitions) and either check (for
1035 * option --info) or pick up dump data */
1036 int mvdump_check_or_copy(int vol_count, struct disk_info vol[])
1038 int i, fd, rc = 1;
1039 uint64_t data_size, total_size = 0;
1040 char* temp_devnode;
1042 for (i = 0; i < vol_count; i++) {
1043 if (vol[i].status != ONLINE) {
1044 fprintf(stderr, "============================="
1045 "=======================\n");
1046 fprintf(stderr, "ERROR: Dump device %s is not "
1047 "available.\n", vol[i].bus_id);
1048 fprintf(stderr, "============================="
1049 "=======================\n");
1050 return 1;
1052 if (vol[i].signature != ACTIVE) {
1053 fprintf(stderr, "============================="
1054 "=======================\n");
1055 fprintf(stderr, "ERROR: Invalid dump data on "
1056 "%s.\n", vol[i].bus_id);
1057 fprintf(stderr, "============================="
1058 "=======================\n");
1059 return 1;
1061 if (make_temp_devnode(vol[i].device, &temp_devnode))
1062 return 1;
1063 fd = open_block_device(temp_devnode);
1064 if (fd == -1) {
1065 free_temp_devnode(temp_devnode);
1066 return 1;
1068 if (lseek(fd, vol[i].start_offset, SEEK_SET) !=
1069 vol[i].start_offset) {
1070 perror("Cannot seek on device");
1071 goto out;
1073 get_header(fd);
1074 print_s390_header(IS_MULT_DASD);
1075 fprintf(stderr, "\nMulti-volume dump: Disk %i (of %i)\n",
1076 i + 1, vol_count);
1077 if (option_i_set) {
1078 data_size = ((vol[i].part_size >> 12) << 12) -
1079 HEADER_SIZE;
1080 if (total_size + data_size > header.dh_memory_size) {
1081 if (lseek(fd, header.dh_memory_size -
1082 total_size, SEEK_CUR) == -1) {
1083 perror("Cannot seek on device");
1084 goto out;
1086 fprintf(stderr, "Checking dump contents on "
1087 "%s\n", vol[i].bus_id);
1088 if (dump_end_times(fd) == 0) {
1089 fprintf(stderr, "Dump End Marker "
1090 "found: "
1091 "this dump is valid.\n\n");
1092 rc = 0;
1093 goto out;
1094 } else {
1095 fprintf(stderr, "Dump End Marker not "
1096 "found: "
1097 "this dump is NOT valid.\n\n");
1098 goto out;
1100 } else if (i == vol_count - 1) {
1101 fprintf(stderr, "Dump End Marker not found: "
1102 "this dump is NOT valid.\n\n");
1103 goto out;
1105 total_size += data_size;
1106 fprintf(stderr, "Skipping dump contents on %s\n",
1107 vol[i].bus_id);
1108 } else {
1109 if (i == 0)
1110 write_header();
1111 fprintf(stderr, "Reading dump contents from %s",
1112 vol[i].bus_id);
1113 if (mvdump_copy(fd, vol[i].part_size, &total_size))
1114 goto out;
1115 if ((i == vol_count - 1) ||
1116 (total_size == header.dh_memory_size)) {
1117 rc = check_and_write_end_marker(fd);
1118 goto out;
1121 free_temp_devnode(temp_devnode);
1122 close(fd);
1124 return 0;
1125 out:
1126 free_temp_devnode(temp_devnode);
1127 close(fd);
1128 return rc;
1131 int main(int argc, char *argv[])
1133 uint64_t cur_time, size_limit;
1134 int vol_count, fd = -1;
1135 int version, dumper_arch, dasd_mv_flag = 0, block_size, rc;
1136 int force_specified = 0;
1137 enum dump_type d_type;
1138 enum devnode_type type;
1139 struct disk_info vol[MAX_DUMP_VOLUMES];
1140 uint32_t cur_volnr;
1142 rc = 0;
1143 parse_opts(argc, argv);
1145 if (option_d_set) {
1146 fd = open_block_device(dump_device);
1147 if (fd == -1) {
1148 rc = 1;
1149 goto out;
1151 rc = check_dump_tool_fba(fd, &version, &dumper_arch,
1152 &size_limit);
1153 if (rc)
1154 goto out;
1155 if (version >= 0)
1156 goto is_dump_device;
1157 else
1158 rc = check_dump_tool_eckd(fd, &version, &dumper_arch,
1159 &dasd_mv_flag, &block_size,
1160 &force_specified,
1161 &size_limit);
1162 if (rc)
1163 goto out;
1164 if (version >= 0)
1165 goto is_dump_device;
1166 fprintf(stderr, "'%s' is no dump device.\n", dump_device);
1167 rc = 1;
1168 goto out;
1170 is_dump_device:
1171 if (dasd_mv_flag) {
1172 rc = get_mvdump_info(fd, block_size, &vol_count, vol);
1173 if (rc)
1174 goto out;
1175 print_mvdump_info(version, vol_count, vol, size_limit,
1176 force_specified);
1177 } else
1178 rc = print_dump_info(version, dumper_arch,
1179 size_limit);
1180 goto out; /* do not consider any other options */
1183 fd = open_dump(dump_device);
1184 get_header(fd);
1185 d_type = dev_type(fd);
1186 if ((d_type == IS_DASD) &&
1187 ((header.dh_magic_number == DUMP_MAGIC_LKCD)
1188 || (header.dh_magic_number == DUMP_MAGIC_LIVE))) {
1189 print_lkcd_header(fd);
1190 exit(0);
1192 if (d_type != IS_TAPE) {
1193 type = check_device(dump_device, 0);
1194 if (type == IS_DEVICE) {
1195 /* This is a valid block device node, no partition */
1196 rc = check_dump_tool_eckd(fd, &version, &dumper_arch,
1197 &dasd_mv_flag, &block_size,
1198 &force_specified,
1199 &size_limit);
1200 if (rc)
1201 goto out;
1202 if (!dasd_mv_flag) {
1203 fprintf(stderr, "Device '%s' specified where"
1204 " partition is required.\n", dump_device);
1205 rc = 1;
1206 goto out;
1207 } else
1208 d_type = IS_MULT_DASD;
1209 } else if ((type == IS_PARTITION) &&
1210 (header.dh_mvdump_signature == DUMP_MAGIC_S390)) {
1211 fprintf(stderr, "'%s' is a multi-volume dump "
1212 "partition.\nSpecify the corresponding device "
1213 "node instead.\n", dump_device);
1214 rc = 1;
1215 goto out;
1219 if (dasd_mv_flag) {
1220 rc = get_mvdump_info(fd, block_size, &vol_count, vol);
1221 if (rc)
1222 goto out;
1223 rc = mvdump_check_or_copy(vol_count, vol);
1224 goto out;
1227 if (!option_i_set) { /* copy the dump to stdout */
1228 print_s390_header(d_type);
1229 write_header();
1230 fprintf(stderr, "Reading dump content ");
1232 /* now get_dump returns 1 for all */
1233 /* except the last tape of a multi-volume dump */
1235 while (get_dump(fd, d_type) == 1) {
1236 fprintf(stderr, "\nWaiting for next volume to be "
1237 "loaded... ");
1238 load_next(fd);
1239 get_header(fd);
1240 print_s390_header(d_type);
1243 /* if dev is DASD and dump is copied */
1244 /* check if the dump is valid */
1246 if (d_type == IS_DASD)
1247 lseek(fd, header.dh_header_size + header.dh_memory_size,
1248 SEEK_SET);
1250 if (!check_and_write_end_marker(fd))
1251 goto out;
1252 } else if (!option_a_set) { /* "-i" option */
1253 fprintf(stderr, "\n> \"zgetdump -i\" checks if a dump on "
1254 "either\n");
1255 fprintf(stderr, "> a dasd volume or single tape is valid.\n");
1256 fprintf(stderr, "> If the tape is part of a multi-volume tape "
1257 "dump,\n");
1258 fprintf(stderr, "> it checks if it is a valid portion of "
1259 "the dump.\n");
1260 print_s390_header(d_type);
1261 if (d_type == IS_DASD)
1262 lseek(fd,
1263 header.dh_header_size + header.dh_memory_size,
1264 SEEK_SET);
1265 else {
1266 fprintf(stderr, "Checking if the dump is valid - "
1267 "this might take a while...\n");
1268 tape_forwards(fd);
1270 if (dump_end_times(fd) == 0) {
1271 fprintf(stderr, "Dump End Marker found: ");
1272 if (header.dh_volnr != 0)
1273 fprintf(stderr, "this is a valid part of "
1274 "a dump.\n\n");
1275 else
1276 fprintf(stderr, "this dump is valid.\n\n");
1277 goto out;
1278 } else if (d_type == IS_DASD) {
1279 fprintf(stderr, "Dump End Marker not found: "
1280 "this dump is NOT valid.\n\n");
1281 rc = 1;
1282 goto out;
1283 } else
1284 fprintf(stderr, "Checking for End of Volume...\n");
1285 if (vol_end() != 0) {
1286 fprintf(stderr, "End of Volume not found: "
1287 "this dump is NOT valid.\n\n");
1288 rc = 1;
1289 goto out;
1290 } else {
1291 fprintf(stderr, "Reached End of Volume %i of a "
1292 "multi-volume tape dump.\n", header.dh_volnr);
1293 fprintf(stderr, "This part of the dump is valid.\n\n");
1294 goto out;
1296 } else { /* "-i -a" option */
1297 fprintf(stderr, "\n> \"zgetdump -i -a\" checks if a "
1298 "multi-volume tape dump is valid.\n");
1299 fprintf(stderr, "> Please make sure that all volumes are "
1300 "loaded in sequence.\n");
1301 if (d_type == IS_DASD) {
1302 fprintf(stderr, "\"-i -a\" is used for validation of "
1303 "multi-volume tape dumps.\n\n");
1304 rc = 1;
1305 goto out;
1307 print_s390_header(d_type);
1308 cur_volnr = header.dh_volnr;
1309 cur_time = header.dh_tod;
1310 fprintf(stderr, "\nChecking if the dump is valid - "
1311 "this might take a while...\n");
1312 tape_forwards(fd);
1313 if (dump_end_times(fd) == 0) {
1314 fprintf(stderr, "Dump End Marker found: "
1315 "this dump is valid.\n\n");
1316 goto out;
1317 } else if (vol_end() != 0) {
1318 fprintf(stderr, "End of Volume not found: "
1319 "this dump is NOT valid.\n\n");
1320 rc = 1;
1321 goto out;
1323 while (vol_end() == 0) {
1324 cur_volnr += 1;
1325 fprintf(stderr, "Reached End of Volume %i.\n",
1326 header.dh_volnr);
1327 fprintf(stderr, "Waiting for Volume %i to be "
1328 "loaded... ", cur_volnr);
1329 load_next(fd);
1330 get_header(fd);
1331 print_s390_header(d_type);
1332 if (header.dh_volnr != cur_volnr) {
1333 fprintf(stderr, "This is not Volume %i\n",
1334 cur_volnr);
1335 rc = 1;
1336 goto out;
1337 } else if (header.dh_tod != cur_time) {
1338 fprintf(stderr, "Time stamp of this volume "
1339 "does not match the previous one.\n");
1340 rc = 1;
1341 goto out;
1343 tape_forwards(fd);
1344 if (dump_end_times(fd) == 0) {
1345 fprintf(stderr, "Dump End found: "
1346 "this dump is valid.\n\n");
1347 goto out;
1348 } else if (vol_end() != 0) {
1349 fprintf(stderr, "End of Volume not found: "
1350 "this dump is NOT valid.\n\n");
1351 rc = 1;
1352 goto out;
1356 out:
1357 if (fd != -1)
1358 close(fd);
1359 return(rc);