/* * Copy one copy table entry form /proc/vmcore to dump partition */ static int copy_table_entry_write(int fdin, int fdout, struct copy_table_entry *entry, unsigned long offset) { unsigned long buf_size, bytes_left, off; void *map; if (entry->size == 0) return 0; off = entry->off; bytes_left = entry->size; if (lseek(fdout, entry->off + offset, SEEK_SET) < 0) return -1; while (bytes_left > 0) { buf_size = MIN(COPY_BUF_SIZE, bytes_left); map = mmap(0, buf_size, PROT_READ, MAP_SHARED, fdin, off); if (map == (void *)-1) { PRINT_PERR("Mapping failed\n"); return -1; } if (write(fdout, map, buf_size) < 0) { PRINT_PERR("Write to partition failed\n"); return -1; } munmap(map, buf_size); bytes_left -= buf_size; off += buf_size; show_progress(buf_size); } return 0; }
/* * Mount the dump device * Return: 0 - ok * != 0 - error */ static int mount_dump_device(void) { int pid; char dump_part[16]; PRINT_TRACE("e2fsck\n"); sprintf(dump_part, "%s%i", DEV_SCSI, atoi(g.parm_part)); pid = fork(); if (pid < 0) { PRINT_PERR("fork failed\n"); return -1; } else if (pid == 0) { execl("/bin/e2fsck", "e2fsck", dump_part, "-y", NULL); execl("/sbin/e2fsck", "e2fsck", dump_part, "-y", NULL); exit(1); } else { waitpid(pid, NULL, 0); } PRINT_TRACE("mount\n"); if (mount(dump_part, DUMP_DIR, "ext3", 0, NULL) == 0) return 0; if (mount(dump_part, DUMP_DIR, "ext2", 0, NULL) != 0) { PRINT_PERR("mount failed\n"); return -1; } return 0; }
/* * Get dump parameters from /proc/cmdline * Return: 0 - ok * (!= 0) - error */ static int parse_parmline(void) { int fh, i, count, token_cnt; char *token; char *parms[KERN_PARM_MAX]; /* setting defaults */ g.parm_compress = PARM_COMP_DFLT; g.parm_dir = PARM_DIR_DFLT; g.parm_part = PARM_PART_DFLT; g.parm_debug = PARM_DEBUG_DFLT; g.parm_mode = PARM_MODE_NUM_DFLT; g.parm_mem = PARM_MEM_DFLT; fh = open(PROC_CMDLINE, O_RDONLY); if (fh == -1) { PRINT_PERR("open %s failed\n", PROC_CMDLINE); return -1; } count = read(fh, g.parmline, CMDLINE_MAX_LEN); if (count == -1) { PRINT_PERR("read %s failed\n", PROC_CMDLINE); close(fh); return -1; } g.parmline[count-1] = '\0'; /* remove \n */ token_cnt = 0; token = strtok(g.parmline, " \t\n"); while (token != NULL) { parms[token_cnt] = token; token = strtok(NULL, " \t\n"); token_cnt++; if (token_cnt >= KERN_PARM_MAX) { PRINT_WARN("More than %i kernel parmameters " "specified\n", KERN_PARM_MAX); break; } } for (i = 0; i < token_cnt; i++) { if (parse_parameter(parms[i])) { close(fh); return -1; } } PRINT_TRACE("dump dir : %s\n", g.parm_dir); PRINT_TRACE("dump part : %s\n", g.parm_part); PRINT_TRACE("dump comp : %s\n", g.parm_compress); PRINT_TRACE("dump debug: %d\n", g.parm_debug); PRINT_TRACE("dump mem: %llx\n", (unsigned long long) g.parm_mem); if (g.parm_mode == PARM_MODE_AUTO_NUM) PRINT_TRACE("dump mode : %s\n", PARM_MODE_AUTO); if (g.parm_mode == PARM_MODE_INTERACT_NUM) PRINT_TRACE("dump mode : %s\n", PARM_MODE_INTERACT); sprintf(g.dump_dir, "%s/%s", DUMP_DIR, g.parm_dir); close(fh); return 0; }
/* * unmount the dump device * Return: 0 - ok * != 0 - error */ static int umount_dump_device(void) { if (umount(DUMP_DIR) != 0) { PRINT_PERR("umount failed\n"); return -1; } return 0; }
/* * Update superblock checksum on SCSI disk */ static int csum_update(int fd) { /* Write crc into zfcpdump header */ if (csum_get(dump_sb.part_start + dump_sb.csum_off, dump_sb.csum_size, &dump_sb.csum)) { PRINT_ERR("Get check sum failed\n"); return -1; } if (lseek(fd, mbr.boot_info.sb_off, SEEK_SET) < 0) { PRINT_PERR("Seek failed\n"); return -1; } if (write(fd, &dump_sb, sizeof(dump_sb)) < 0) { PRINT_PERR("Write failed\n"); return -1; } return 0; }
static int write_to_file(const char *file, const char *command) { int fh; PRINT_TRACE("Write: %s - %s\n", file, command); fh = open(file, O_WRONLY); if (fh == -1) { PRINT_PERR("Could not open %s\n", file); return -1; } if (write(fh, command, strlen(command)) == -1) { PRINT_PERR("Write to %s failed\n", file); close(fh); return -1; }; close(fh); return 0; }
static int read_file(const char *file, char *buf, int size) { int fh; PRINT_TRACE("Read: %s:\n", file); fh = open(file, O_RDONLY); if (fh == -1) { PRINT_PERR("open %s failed\n", file); return -1; } if (read(fh, buf, size) < 0) { PRINT_PERR("read %s failed\n", file); close(fh); return -1; } if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0; /* strip newline */ close(fh); PRINT_TRACE("'%s'\n", buf); return 0; }
/* * Read file at given offset */ static int pread_file(const char *path, char *buf, int size, uint64_t off) { int fd; PRINT_TRACE("Read: %s:\n", path); fd = open(path, O_RDONLY); if (fd == -1) { PRINT_PERR("open %s failed\n", path); return -1; } if (lseek(fd, off, SEEK_SET) < 0) { PRINT_PERR("seek %s offset %llu failed\n", path, (unsigned long long) off); return -1; } if (read(fd, buf, size) < 0) { PRINT_PERR("read %s failed\n", path); close(fd); return -1; } close(fd); return 0; }
/* * Finds the matching partition to a given start and end. If a matching * partition is found, the partition number is returned. */ int find_part_num(uint64_t start, uint64_t size) { struct hd_geometry geo; uint32_t block_size; uint64_t part_size; char path[11]; int fd, i; PRINT_TRACE("Partiton to dump start: 0x%llx end: 0x%llx\n", (unsigned long long) start, (unsigned long long) size); for (i = 1; i < 16; i++) { snprintf(path, sizeof(path), DEV_SCSI "%d", i); fd = open(path, O_RDONLY); if (fd == -1) continue; if (ioctl(fd, HDIO_GETGEO, &geo) != 0) { PRINT_PERR("Could not retrieve partition" " geometry information\n"); return -1; } if (ioctl(fd, BLKGETSIZE64, &part_size)) { PRINT_PERR("Could not retrieve partition" " size information\n"); return -1; } if (ioctl(fd, BLKSSZGET, &block_size)) { PRINT_PERR("Could not get blocksize"); return -1; } PRINT_TRACE("Partiton %s start: 0x%llx end: 0x%llx\n", path, (unsigned long long) geo.start * block_size, (unsigned long long) part_size); if ((start == geo.start * block_size) && (size == part_size)) return i; } return -1; }
/* * Get dump number of either new dump or dump to erase * Parameter: dumpdir - dump directory (absolute path) * mode - DUMP_FIRST: Find smallest dump number in directory * - DUMP_LAST: Find highest dump number in directory * Return: >= 0 - dump number * -1 - no dump found in directory * <-1 - error */ static int get_dump_num(const char *dumpdir, int mode) { DIR *dir = NULL; struct dirent *dir_ent; int dump_found, rc; rc = 0; dump_found = 0; dir = opendir(dumpdir); if (!dir) { PRINT_PERR("Cannot evalute dump number\n"); return -2; } while ((dir_ent = readdir(dir))) { int num; if (sscanf(dir_ent->d_name, "dump.%ui", &num) == 1) { char suffix[1024] = {}; /* * check if we have something like dump.001 * this is not treated as dump, since we do not allow * leading zeros. * Also files like dump.-1, dump.-10 are ignored. */ sscanf(dir_ent->d_name, "dump.%s", suffix); if (suffix[0] == '-') continue; if ((suffix[0] == '0') && isdigit(suffix[1])) continue; if (!dump_found) { dump_found = 1; rc = num; } else if (mode == DUMP_LAST) { rc = MAX(num, rc); } else if (mode == DUMP_FIRST) { rc = MIN(num, rc); } } } if (!dump_found) rc = NO_DUMP; closedir(dir); return rc; }
/* * Erase oldest dump in dump directory * Return: 0 - ok * !=0 - error */ static int erase_oldest_dump(void) { int dump_nr; char dname[1024] = {}; char answ[1024] = {}; dump_nr = get_dump_num(g.dump_dir, DUMP_FIRST); if (dump_nr < 0) { PRINT_ERR("Internal error: dump number cannot be evaluated\n"); return -1; } sprintf(dname, "dump.%i", dump_nr); if (dump_nr == g.dump_nr) { PRINT_ERR("Sorry, cannot delete any more dumps!\n"); return -1; } if (g.parm_mode == PARM_MODE_AUTO_NUM) { PRINT("Removing oldest dump: '%s'\n", dname); } else { while ((strcmp(answ, "y") != 0) && (strcmp(answ, "n") != 0)) { PRINT("Remove oldest dump: '%s' (y/n)? ", dname); scanf("%s", answ); } if (strcmp(answ, "n") == 0) return -1; } sprintf(dname, "%s/dump.%i", g.dump_dir, dump_nr); if (unlink(dname) == -1) { PRINT_PERR("Could not remove dump\n"); return -1; } sync(); /* * Wait some seconds in order to give ext3 time to discover that file * has been removed. */ sleep(WAIT_TIME_ERASE); PRINT("Dump removed!\n"); return 0; }