| /* |
| * Copyright (c) 2000-2004 Silicon Graphics, Inc. |
| * All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #include "libxfs.h" |
| #include "libxlog.h" |
| |
| #include "logprint.h" |
| |
| #define OP_PRINT 0 |
| #define OP_PRINT_TRANS 1 |
| #define OP_DUMP 2 |
| #define OP_COPY 3 |
| |
| int print_data; |
| int print_only_data; |
| int print_inode; |
| int print_quota; |
| int print_buffer; |
| int print_overwrite; |
| int print_no_data; |
| int print_no_print; |
| int print_exit = 1; /* -e is now default. specify -c to override */ |
| int print_operation = OP_PRINT; |
| |
| void |
| usage(void) |
| { |
| fprintf(stderr, _("Usage: %s [options...] <device>\n\n\ |
| Options:\n\ |
| -c try to continue if error found in log\n\ |
| -C <filename> copy the log from the filesystem to filename\n\ |
| -d dump the log in log-record format\n\ |
| -e exit when an error is found in the log\n\ |
| -f specified device is actually a file\n\ |
| -l <device> filename of external log\n\ |
| -n don't try and interpret log data\n\ |
| -o print buffer data in hex\n\ |
| -s <start blk> block # to start printing\n\ |
| -v print \"overwrite\" data\n\ |
| -t print out transactional view\n\ |
| -b in transactional view, extract buffer info\n\ |
| -i in transactional view, extract inode info\n\ |
| -q in transactional view, extract quota info\n\ |
| -D print only data; no decoding\n\ |
| -V print version information\n"), |
| progname); |
| exit(1); |
| } |
| |
| int |
| logstat(xfs_mount_t *mp) |
| { |
| int fd; |
| char buf[BBSIZE]; |
| xfs_sb_t *sb; |
| |
| /* On Linux we always read the superblock of the |
| * filesystem. We need this to get the length of the |
| * log. Otherwise we end up seeking forever. -- mkp |
| */ |
| if ((fd = open(x.dname, O_RDONLY)) == -1) { |
| fprintf(stderr, _(" Can't open device %s: %s\n"), |
| x.dname, strerror(errno)); |
| exit(1); |
| } |
| lseek(fd, 0, SEEK_SET); |
| if (read(fd, buf, sizeof(buf)) != sizeof(buf)) { |
| fprintf(stderr, _(" read of XFS superblock failed\n")); |
| exit(1); |
| } |
| close (fd); |
| |
| if (!x.disfile) { |
| /* |
| * Conjure up a mount structure |
| */ |
| sb = &mp->m_sb; |
| libxfs_sb_from_disk(sb, (xfs_dsb_t *)buf); |
| mp->m_blkbb_log = sb->sb_blocklog - BBSHIFT; |
| |
| x.logBBsize = XFS_FSB_TO_BB(mp, sb->sb_logblocks); |
| x.logBBstart = XFS_FSB_TO_DADDR(mp, sb->sb_logstart); |
| x.lbsize = BBSIZE; |
| if (xfs_sb_version_hassector(sb)) |
| x.lbsize <<= (sb->sb_logsectlog - BBSHIFT); |
| |
| if (!x.logname && sb->sb_logstart == 0) { |
| fprintf(stderr, _(" external log device not specified\n\n")); |
| usage(); |
| /*NOTREACHED*/ |
| } |
| } else { |
| struct stat s; |
| |
| stat(x.dname, &s); |
| x.logBBsize = s.st_size >> 9; |
| x.logBBstart = 0; |
| x.lbsize = BBSIZE; |
| } |
| |
| |
| if (x.logname && *x.logname) { /* External log */ |
| if ((fd = open(x.logname, O_RDONLY)) == -1) { |
| fprintf(stderr, _("Can't open file %s: %s\n"), |
| x.logname, strerror(errno)); |
| exit(1); |
| } |
| close(fd); |
| } else { /* Internal log */ |
| x.logdev = x.ddev; |
| } |
| |
| return 0; |
| } |
| |
| int |
| main(int argc, char **argv) |
| { |
| int print_start = -1; |
| int c; |
| int logfd; |
| char *copy_file = NULL; |
| struct xlog log = {0}; |
| xfs_mount_t mount; |
| |
| setlocale(LC_ALL, ""); |
| bindtextdomain(PACKAGE, LOCALEDIR); |
| textdomain(PACKAGE); |
| memset(&mount, 0, sizeof(mount)); |
| |
| progname = basename(argv[0]); |
| while ((c = getopt(argc, argv, "bC:cdefl:iqnors:tDVv")) != EOF) { |
| switch (c) { |
| case 'D': |
| print_only_data++; |
| print_data++; |
| break; |
| case 'b': |
| print_buffer++; |
| break; |
| case 'c': |
| /* default is to stop on error. |
| * -c turns this off. |
| */ |
| print_exit = 0; |
| break; |
| case 'e': |
| /* -e is now default |
| */ |
| print_exit++; |
| break; |
| case 'C': |
| print_operation = OP_COPY; |
| copy_file = optarg; |
| break; |
| case 'd': |
| print_operation = OP_DUMP; |
| break; |
| case 'f': |
| print_skip_uuid++; |
| x.disfile = 1; |
| break; |
| case 'l': |
| x.logname = optarg; |
| x.lisfile = 1; |
| break; |
| case 'i': |
| print_inode++; |
| break; |
| case 'q': |
| print_quota++; |
| break; |
| case 'n': |
| print_no_data++; |
| break; |
| case 'o': |
| print_data++; |
| break; |
| case 's': |
| print_start = atoi(optarg); |
| break; |
| case 't': |
| print_operation = OP_PRINT_TRANS; |
| break; |
| case 'v': |
| print_overwrite++; |
| break; |
| case 'V': |
| printf(_("%s version %s\n"), progname, VERSION); |
| exit(0); |
| case '?': |
| usage(); |
| } |
| } |
| |
| if (argc - optind != 1) |
| usage(); |
| |
| x.dname = argv[optind]; |
| |
| if (x.dname == NULL) |
| usage(); |
| |
| x.isreadonly = LIBXFS_ISINACTIVE; |
| printf(_("xfs_logprint:\n")); |
| if (!libxfs_init(&x)) |
| exit(1); |
| |
| logstat(&mount); |
| libxfs_buftarg_init(&mount, x.ddev, x.logdev, x.rtdev); |
| |
| logfd = (x.logfd < 0) ? x.dfd : x.logfd; |
| |
| printf(_(" data device: 0x%llx\n"), (unsigned long long)x.ddev); |
| |
| if (x.logname) { |
| printf(_(" log file: \"%s\" "), x.logname); |
| } else { |
| printf(_(" log device: 0x%llx "), (unsigned long long)x.logdev); |
| } |
| |
| printf(_("daddr: %lld length: %lld\n\n"), |
| (long long)x.logBBstart, (long long)x.logBBsize); |
| |
| ASSERT(x.logBBsize <= INT_MAX); |
| |
| log.l_dev = mount.m_logdev_targp; |
| log.l_logBBstart = x.logBBstart; |
| log.l_logBBsize = x.logBBsize; |
| log.l_sectBBsize = BTOBB(x.lbsize); |
| log.l_mp = &mount; |
| |
| switch (print_operation) { |
| case OP_PRINT: |
| xfs_log_print(&log, logfd, print_start); |
| break; |
| case OP_PRINT_TRANS: |
| xfs_log_print_trans(&log, print_start); |
| break; |
| case OP_DUMP: |
| xfs_log_dump(&log, logfd, print_start); |
| break; |
| case OP_COPY: |
| xfs_log_copy(&log, logfd, copy_file); |
| break; |
| } |
| exit(0); |
| } |