diff -Nru tct-1.11/CHANGES tct-1.18/CHANGES --- tct-1.11/CHANGES 2002-10-05 18:48:52.000000000 +0100 +++ tct-1.18/CHANGES 2007-04-09 14:44:12.000000000 +0100 @@ -1,3 +1,54 @@ +Mon Apr 9 09:36:31 EDT 2007 + +o Bit-rot: the 64-bit workaround for LINUX lseek() is no + longer needed, and it didn't compile on some systems. + +Thu Jan 11 16:10:29 EST 2007 + +o Bugfix: the timeout command always reported zero exit status + after voluntary child process exit. + +Mon Jun 26 18:44:17 EDT 2006 + +o Bit-rot: update #include statements because code either + no longer compiled or compiled with warnings. + +Fri Mar 17 09:25:57 EST 2006 + +o Bit-rot: update #include statements because code either + no longer compiled or compiled with warnings. + +Tue Jan 6 12:25:32 EST 2004 + +o Workaround: mactime treated "," as a special character in + file names, now it's 0xff. + +o Support for ext[23]fs inode file sizes > 32bits. + +o Bugfix: ils file sizes larger than unsigned long. + +Tue Oct 14 18:23:49 EDT 2003 + +o pcat now fully supports FreeBSD systems that do not have + /proc mounted (it's no longer mounted by default with + FreeBSD 5). pcat tries to use /proc if it can, and uses + ptrace() and gropes kernel memory if it has to. Operation + without /proc requires super-user privileges. + +Thu Oct 2 09:14:00 EDT 2003 + +o Completed support for UFS1 and UFS2 in FreeBSD 5.x. However, + the pcat command still requires that the /proc file system + is mounted. This will be fixed later. + +Sat Aug 30 19:21:29 EDT 2003 + +o Preliminary FreeBSD 5.0 port. UFS2 support is still to be done. + +Fri Aug 1 10:07:39 EDT 2003 + +o RedHat 9.0 fix by Florin Andrei for the file command. + Sat Oct 5 13:47:29 EDT 2002 o Restored tctutils compatibility, which broke with 20020916. diff -Nru /tmp/BHdHZf2_d2/tct-1.11/bin/mactime /tmp/kIoa9vRMri/tct-1.18/bin/mactime --- tct-1.11/bin/mactime 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/bin/mactime 2008-05-08 11:44:52.000000000 +0100 @@ -454,10 +454,10 @@ # # If the date on the file is too old, don't put it in the array # - $all_files_used{"$st_mtime,$file"} .= "m" if $st_mtime > $in_seconds; - $all_files_used{"$st_atime,$file"} .= "a" if $st_atime > $in_seconds; - $all_files_used{"$st_ctime,$file"} .= "c" if $st_ctime > $in_seconds; - $all_files_used{"$st_dtime,$file"} .= "d" if $st_dtime > $in_seconds; + $all_files_used{"$st_mtime\377$file"} .= "m" if $st_mtime > $in_seconds; + $all_files_used{"$st_atime\377$file"} .= "a" if $st_atime > $in_seconds; + $all_files_used{"$st_ctime\377$file"} .= "c" if $st_ctime > $in_seconds; + $all_files_used{"$st_dtime\377$file"} .= "d" if $st_dtime > $in_seconds; $all_filenames{$file} = $file; @@ -515,7 +515,7 @@ next if $marker; - ($time, $file) = split(/,/,$key); + ($time, $file) = split(/\377/,$key); print "T-in minus Currfile time = ", $in_seconds - $time, "\n" if $debug; next if ($in_seconds > $time); diff -Nru /tmp/BHdHZf2_d2/tct-1.11/debian/changelog /tmp/kIoa9vRMri/tct-1.18/debian/changelog --- tct-1.11/debian/changelog 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/debian/changelog 2008-05-08 11:44:52.000000000 +0100 @@ -1,3 +1,12 @@ +tct (1.18-0ubuntu1) hardy; urgency=low + + * Update to upstream 1.18 to fix LP: #78742 + * Add watch file + * Modify Maintainer value to match the DebianMaintainerField + specification. + + -- Dan Sheridan Thu, 08 May 2008 11:43:11 +0100 + tct (1.11-6.5) unstable; urgency=low * Non-maintainer upload. diff -Nru /tmp/BHdHZf2_d2/tct-1.11/debian/control /tmp/kIoa9vRMri/tct-1.18/debian/control --- tct-1.11/debian/control 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/debian/control 2008-05-08 11:44:52.000000000 +0100 @@ -1,9 +1,11 @@ Source: tct Section: admin +Homepage: http://www.porcupine.org/forensics/tct.html Build-Depends: debhelper (>> 4.0.0), e2fslibs-dev Priority: optional -Maintainer: Andrew Stribblehill -Standards-Version: 3.5.7 +Maintainer: Ubuntu MOTU Developers +XSBC-Original-Maintainer: Andrew Stribblehill +Standards-Version: 3.7.3 Package: tct Architecture: any diff -Nru /tmp/BHdHZf2_d2/tct-1.11/debian/watch /tmp/kIoa9vRMri/tct-1.18/debian/watch --- tct-1.11/debian/watch 1970-01-01 01:00:00.000000000 +0100 +++ tct-1.18/debian/watch 2008-05-08 11:44:52.000000000 +0100 @@ -0,0 +1,4 @@ +version=3 + +http://www.porcupine.org/forensics/tct.html \ + tct-(.*).tar.gz \ No newline at end of file diff -Nru /tmp/BHdHZf2_d2/tct-1.11/extras/entropy/makedefs /tmp/kIoa9vRMri/tct-1.18/extras/entropy/makedefs --- tct-1.11/extras/entropy/makedefs 2002-03-22 19:44:10.000000000 +0000 +++ tct-1.18/extras/entropy/makedefs 2003-08-31 00:16:41.000000000 +0100 @@ -8,6 +8,8 @@ ;; FreeBSD.4*) DEFS="-DFREEBSD4" ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + ;; OpenBSD.2*) DEFS="-DOPENBSD2" ;; OpenBSD.3*) DEFS="-DOPENBSD3" diff -Nru /tmp/BHdHZf2_d2/tct-1.11/extras/findkey/makedefs /tmp/kIoa9vRMri/tct-1.18/extras/findkey/makedefs --- tct-1.11/extras/findkey/makedefs 2002-03-22 19:44:10.000000000 +0000 +++ tct-1.18/extras/findkey/makedefs 2003-08-31 00:16:51.000000000 +0100 @@ -8,6 +8,8 @@ ;; FreeBSD.4*) DEFS="-DFREEBSD4" ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + ;; OpenBSD.2*) DEFS="-DOPENBSD2" ;; OpenBSD.3*) DEFS="-DOPENBSD3" diff -Nru /tmp/BHdHZf2_d2/tct-1.11/lib/ostype.pl /tmp/kIoa9vRMri/tct-1.18/lib/ostype.pl --- tct-1.11/lib/ostype.pl 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/lib/ostype.pl 2008-05-08 11:44:52.000000000 +0100 @@ -11,6 +11,7 @@ "FREEBSD2", "FreeBSD.2", "FREEBSD3", "FreeBSD.3", "FREEBSD4", "FreeBSD.4", + "FREEBSD5", "FreeBSD.5", "OPENBSD2", "OpenBSD.2", "OPENBSD3", "OpenBSD.3", "BSDI2", "BSD\/OS.2", diff -Nru /tmp/BHdHZf2_d2/tct-1.11/man/man1/pcat.1 /tmp/kIoa9vRMri/tct-1.18/man/man1/pcat.1 --- tct-1.11/man/man1/pcat.1 2000-07-31 00:39:20.000000000 +0100 +++ tct-1.18/man/man1/pcat.1 2003-10-14 20:52:44.000000000 +0100 @@ -28,6 +28,7 @@ This option does not work on some Solaris versions. .IP "\fB-m\fR \fImapfile\fR" Print the process memory map to \fImapfile\fR, one entry per line. +Specify \fB-m-\fR to write to the standard error stream. Each map entry consists of a region start address and the first address beyond that region. Addresses are separated by space, and are printed as hexadecimal numbers (0xhhhh). diff -Nru /tmp/BHdHZf2_d2/tct-1.11/man/man1/timeout.1 /tmp/kIoa9vRMri/tct-1.18/man/man1/timeout.1 --- tct-1.11/man/man1/timeout.1 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/man/man1/timeout.1 2008-05-08 11:44:52.000000000 +0100 @@ -30,8 +30,16 @@ .fi timeout's exit status is the exit status of the specified command or 1 in case of a usage error. +.SH LICENSE +.na +.nf +The IBM PUBLIC LICENSE must be distributed with this +software. +.SH HISTORY +.na +.nf +This program was first released as part of SATAN. .SH AUTHOR(S) .na .nf Wietse Venema -This program is part of SATAN. diff -Nru /tmp/BHdHZf2_d2/tct-1.11/patchlevel /tmp/kIoa9vRMri/tct-1.18/patchlevel --- tct-1.11/patchlevel 2002-10-05 18:51:49.000000000 +0100 +++ tct-1.18/patchlevel 2003-10-02 14:52:11.000000000 +0100 @@ -1 +1 @@ -1.11 +1.14 diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/aux/error.h /tmp/kIoa9vRMri/tct-1.18/src/aux/error.h --- tct-1.11/src/aux/error.h 2000-07-31 00:39:20.000000000 +0100 +++ tct-1.18/src/aux/error.h 2003-04-29 14:25:13.000000000 +0100 @@ -11,9 +11,16 @@ /* * External interface. */ -extern void remark(char *,...); -extern void error(char *,...); -extern void panic(char *,...); +#ifndef PRINTFLIKE +#if __GNUC__ == 2 && __GNUC_MINOR__ >= 7 +#define PRINTFLIKE(x,y) __attribute__ ((format (printf, (x), (y)))) +#else +#define PRINTFLIKE(x,y) +#endif +#endif +extern void PRINTFLIKE(1, 2) remark(char *,...); +extern void PRINTFLIKE(1, 2) error(char *,...); +extern void PRINTFLIKE(1, 2) panic(char *,...); extern char *progname; extern int verbose; diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/aux/makedefs /tmp/kIoa9vRMri/tct-1.18/src/aux/makedefs --- tct-1.11/src/aux/makedefs 2002-03-22 19:44:10.000000000 +0000 +++ tct-1.18/src/aux/makedefs 2003-08-31 00:17:20.000000000 +0100 @@ -8,6 +8,8 @@ ;; FreeBSD.4*) DEFS="-DFREEBSD4" ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + ;; OpenBSD.2*) DEFS="-DOPENBSD2" ;; OpenBSD.3*) DEFS="-DOPENBSD3" diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/file/file.h /tmp/kIoa9vRMri/tct-1.18/src/file/file.h --- tct-1.11/src/file/file.h 2000-07-31 00:39:20.000000000 +0100 +++ tct-1.18/src/file/file.h 2003-08-01 15:04:49.000000000 +0100 @@ -102,7 +102,11 @@ +#ifdef NEED_ERRNO_H +#include +#else extern int errno; /* Some unixes don't define this.. */ +#endif extern char *progname; /* the program name */ extern char *magicfile; /* name of the magic file */ diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/file/makedefs /tmp/kIoa9vRMri/tct-1.18/src/file/makedefs --- tct-1.11/src/file/makedefs 2002-03-22 19:44:10.000000000 +0000 +++ tct-1.18/src/file/makedefs 2003-08-31 01:02:52.000000000 +0100 @@ -8,6 +8,8 @@ ;; FreeBSD.4*) DEFS="-DFREEBSD4" ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + ;; OpenBSD.2*) DEFS="-DOPENBSD2" ;; OpenBSD.3*) DEFS="-DOPENBSD3" @@ -26,9 +28,9 @@ SunOS.5*) DEFS="-DSUNOS5" RANLIB=":" ;; - Linux.2.4*) DEFS="-DLINUX2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" +Linux.2.[0-3].*) DEFS="-DLINUX2" ;; - Linux.2*) DEFS="-DLINUX2" + Linux.2.*) DEFS="-DLINUX2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DNEED_ERRNO_H" ;; *) echo unsupported system: $SYSTEM.$RELEASE 1>&2; exit 1 ;; diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/Makefile /tmp/kIoa9vRMri/tct-1.18/src/fstools/Makefile --- tct-1.11/src/fstools/Makefile 2000-07-31 00:39:20.000000000 +0100 +++ tct-1.18/src/fstools/Makefile 2003-10-02 14:23:22.000000000 +0100 @@ -5,7 +5,7 @@ INCL = -I../aux CFLAGS = $(DEFS) $(INCL) $(OPT) $(DEBUG) LIBOBJ = fs_buf.o fs_inode.o fs_io.o fs_copy_file.o fs_open.o ffs.o \ - ext2fs.o mylseek.o + ffs2.o ext2fs.o mylseek.o LIBS = ../aux/aux_lib.a LIB = fs_lib.a BIN_DIR = ../../bin @@ -57,6 +57,8 @@ ext2fs.o: fs_tools.h ffs.o: ffs.c ffs.o: fs_tools.h +ffs2.o: ffs2.c +ffs2.o: fs_tools.h fs_buf.o: fs_buf.c fs_buf.o: fs_tools.h fs_buf.o: ../aux/mymalloc.h diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/ext2fs.c /tmp/kIoa9vRMri/tct-1.18/src/fstools/ext2fs.c --- tct-1.11/src/fstools/ext2fs.c 2002-09-16 19:48:58.000000000 +0100 +++ tct-1.18/src/fstools/ext2fs.c 2006-03-17 14:33:03.000000000 +0000 @@ -194,6 +194,10 @@ fs_inode->mode = dino->i_mode; fs_inode->nlink = dino->i_links_count; fs_inode->size = dino->i_size; +#ifdef i_size_high + if (dino->i_size_high) + fs_inode->size |= (((OFF_T) dino->i_size_high) << 32); +#endif fs_inode->uid = dino->i_uid; fs_inode->gid = dino->i_gid; fs_inode->mtime = dino->i_mtime; @@ -467,8 +471,8 @@ /* * Other initialization: caches, callbacks. */ - ext2fs->inode_map = mymalloc(ext2fs->fs_info.block_size); - ext2fs->block_map = mymalloc(ext2fs->fs_info.block_size); + ext2fs->inode_map = (UCHAR *) mymalloc(ext2fs->fs_info.block_size); + ext2fs->block_map = (UCHAR *) mymalloc(ext2fs->fs_info.block_size); ext2fs->fs_info.seek_pos = -1; ext2fs->grpnum = -1; ext2fs->bmap_num = -1; diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/ffs.c /tmp/kIoa9vRMri/tct-1.18/src/fstools/ffs.c --- tct-1.11/src/fstools/ffs.c 2002-09-16 19:38:09.000000000 +0100 +++ tct-1.18/src/fstools/ffs.c 2003-10-01 22:01:05.000000000 +0100 @@ -395,7 +395,8 @@ if (read(ffs->fs_info.fd, (char *) ffs->fs, len) != len) error("%s: read superblock: %m", name); if (ffs->fs->fs_magic != FS_MAGIC) - error("%s: bad magic number in superblock", name); + error("%s: bad magic number 0x%x in superblock", + name, ffs->fs->fs_magic); /* * Translate some filesystem-specific information to generic form. diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/ffs2.c /tmp/kIoa9vRMri/tct-1.18/src/fstools/ffs2.c --- tct-1.11/src/fstools/ffs2.c 1970-01-01 01:00:00.000000000 +0100 +++ tct-1.18/src/fstools/ffs2.c 2003-10-02 01:59:37.000000000 +0100 @@ -0,0 +1,484 @@ +/*++ +/* NAME +/* ffs_open 3 +/* SUMMARY +/* fast file system support +/* SYNOPSIS +/* #include "fstools.h" +/* +/* FS_INFO *ffs_open(const char *name) +/* DESCRIPTION +/* ffs_open() opens the named block device and makes it accessible +/* for the standard file system operations described in fs_open(3). +/* This module supports both UFS1 (traditional FFS) and UFS2 (FFS +/* with expanded range). +/* BUGS +/* On-disk layout and byte order differ per FFS implementation, +/* therefore this code is likely to fail when confronted with +/* foreign file systems. +/* LICENSE +/* This software is distributed under the IBM Public License. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +#include "fs_tools.h" +#ifdef FS_UFS2_MAGIC +#include "mymalloc.h" +#include "error.h" + + /* + * Structure of a fast file system handle. + */ +union dinode { + struct ufs1_dinode u1; /* UFS1 disk inode */ + struct ufs2_dinode u2; /* UFS2 disk inode */ +}; + +typedef struct { + FS_INFO fs_info; /* super class */ + struct fs *fs; /* super block buffer */ + FS_BUF *cg_buf; /* cylinder block buffer */ + FS_BUF *dino_buf; /* inode block buffer */ + union dinode dinode; /* disk inode */ +} FFS_INFO; + +/* ffs_cgroup_lookup - look up cached cylinder group info */ + +static struct cg *ffs_cgroup_lookup(FFS_INFO *ffs, CGNUM_T cgnum) +{ + struct cg *cg; + DADDR_T addr; + + /* + * Sanity check + */ + if (cgnum < 0 || cgnum >= ffs->fs->fs_ncg) + error("invalid cylinder group number: %lu", (ULONG) cgnum); + + /* + * Allocate/read cylinder group info on the fly. Trust that a cylinder + * group always fits within a logical disk block (as promised in the + * 4.4BSD include file). + */ + addr = cgtod(ffs->fs, cgnum); + if (ffs->cg_buf == 0) + ffs->cg_buf = fs_buf_alloc(ffs->fs->fs_bsize); + cg = (struct cg *) ffs->cg_buf->data; + if (ffs->cg_buf->addr != addr) { + fs_read_block(&ffs->fs_info, ffs->cg_buf, ffs->cg_buf->size, addr, + "cylinder block"); + if (verbose) + fprintf(logfp, + "\tcyl group %lu: %lu/%lu/%lu free blocks/inodes/frags\n", + (ULONG) cgnum, (ULONG) cg->cg_cs.cs_nbfree, + (ULONG) cg->cg_cs.cs_nifree, + (ULONG) cg->cg_cs.cs_nffree); + } + return (cg); +} + +/* ffs_cgroup_free - destroy cylinder group info cache */ + +static void ffs_cgroup_free(FFS_INFO *ffs) +{ + if (ffs->cg_buf) + fs_buf_free(ffs->cg_buf); +} + +/* ffs_dinode_lookup - look up cached disk inode */ + +static union dinode *ffs_dinode_lookup(FFS_INFO *ffs, INUM_T inum) +{ + DADDR_T addr; + int offs; + + /* + * Sanity check. + */ + if (inum < ffs->fs_info.start_inum || inum > ffs->fs_info.last_inum) + error("invalid inode number: %lu", (ULONG) inum); + + /* + * Allocate/read the inode buffer on the fly. + */ + if (ffs->dino_buf == 0) + ffs->dino_buf = fs_buf_alloc(ffs->fs->fs_bsize); + addr = itod(ffs->fs, inum); + if (ffs->dino_buf->addr != addr) + fs_read_block(&ffs->fs_info, ffs->dino_buf, ffs->dino_buf->size, addr, + "inode block"); + + /* + * Copy the inode, in order to avoid alignment problems when accessing + * structure members. + */ + if (ffs->fs->fs_magic == FS_UFS2_MAGIC) { + offs = itoo(ffs->fs, inum) * sizeof(struct ufs2_dinode); + memcpy((char *) &ffs->dinode.u2, ffs->dino_buf->data + offs, + sizeof(struct ufs2_dinode)); + } else { + offs = itoo(ffs->fs, inum) * sizeof(struct ufs1_dinode); + memcpy((char *) &ffs->dinode.u1, ffs->dino_buf->data + offs, + sizeof(struct ufs1_dinode)); + } + return (&ffs->dinode); +} + +/* ffs_dinode_free - destroy disk inode cache */ + +static void ffs_dinode_free(FFS_INFO *ffs) +{ + if (ffs->dino_buf) + fs_buf_free(ffs->dino_buf); +} + +/* ffs_copy_inode - copy disk inode to generic inode */ + +static void ffs_copy_inode(struct fs * fs, union dinode * dino, FS_INODE *fs_inode) +{ + int i; + + if (fs->fs_magic == FS_UFS2_MAGIC) { + fs_inode->mode = dino->u2.di_mode; + fs_inode->nlink = dino->u2.di_nlink; + fs_inode->size = dino->u2.di_size; + fs_inode->uid = dino->u2.di_uid; + fs_inode->gid = dino->u2.di_gid; + fs_inode->mtime = INOTIME(dino->u2.di_mtime); + fs_inode->atime = INOTIME(dino->u2.di_atime); + fs_inode->ctime = INOTIME(dino->u2.di_ctime); + if (fs_inode->direct_count != NDADDR || fs_inode->indir_count != NIADDR) + fs_inode_realloc(fs_inode, NDADDR, NIADDR); + for (i = 0; i < NDADDR; i++) + fs_inode->direct_addr[i] = dino->u2.di_db[i]; + for (i = 0; i < NIADDR; i++) + fs_inode->indir_addr[i] = dino->u2.di_ib[i]; + } else { + fs_inode->mode = dino->u1.di_mode; + fs_inode->nlink = dino->u1.di_nlink; + fs_inode->size = dino->u1.di_size; + fs_inode->uid = dino->u1.di_uid; + fs_inode->gid = dino->u1.di_gid; + fs_inode->mtime = INOTIME(dino->u1.di_mtime); + fs_inode->atime = INOTIME(dino->u1.di_atime); + fs_inode->ctime = INOTIME(dino->u1.di_ctime); + if (fs_inode->direct_count != NDADDR || fs_inode->indir_count != NIADDR) + fs_inode_realloc(fs_inode, NDADDR, NIADDR); + for (i = 0; i < NDADDR; i++) + fs_inode->direct_addr[i] = dino->u1.di_db[i]; + for (i = 0; i < NIADDR; i++) + fs_inode->indir_addr[i] = dino->u1.di_ib[i]; + } +} + +/* ffs_inode_lookup - lookup inode, external interface */ + +static FS_INODE *ffs_inode_lookup(FS_INFO *fs, INUM_T inum) +{ + FFS_INFO *ffs = (FFS_INFO *) fs; + FS_INODE *fs_inode = fs_inode_alloc(NDADDR, NIADDR); + union dinode *dino = ffs_dinode_lookup(ffs, inum); + + ffs_copy_inode(ffs->fs, dino, fs_inode); + return (fs_inode); +} + +/* ffs_inode_walk - inode iterator */ + +void ffs_inode_walk(FS_INFO *fs, INUM_T start, INUM_T last, int flags, + FS_INODE_WALK_FN action, char *ptr) +{ + char *myname = "ffs_inode_walk"; + FFS_INFO *ffs = (FFS_INFO *) fs; + CGNUM_T cg_num; + struct cg *cg = 0; + INUM_T inum; + unsigned char *inosused; + union dinode *dino; + FS_INODE *fs_inode = fs_inode_alloc(NDADDR, NIADDR); + int myflags; + INUM_T ibase; + + /* + * Sanity checks. + */ + if (start < ffs->fs_info.start_inum || start > ffs->fs_info.last_inum) + error("%s: invalid start inode number: %lu", myname, (ULONG) start); + if (last < ffs->fs_info.start_inum || last > ffs->fs_info.last_inum) + error("%s: invalid last inode number: %lu", myname, (ULONG) last); + + /* + * Iterate. This is easy because inode numbers are contiguous, unlike + * data blocks which are interleaved with cylinder group blocks. + */ + for (inum = start; inum <= last; inum++) { + + /* + * Be sure to use the proper cylinder group data. + */ + cg_num = INO_TO_CG(ffs->fs, inum); + if (cg == 0 || cg->cg_cgx != cg_num) { + cg = ffs_cgroup_lookup(ffs, cg_num); + inosused = (unsigned char *) cg_inosused(cg); + ibase = cg_num * ffs->fs->fs_ipg; + } + + /* + * Apply the allocated/unallocated restriction. + */ + myflags = (isset(inosused, inum - ibase) ? + FS_FLAG_ALLOC : FS_FLAG_UNALLOC); + if ((flags & myflags) != myflags) + continue; + + /* + * Apply the linked/unlinked restriction. + */ +#define UFS_DINO_FIELD(fs, dino, field) ((fs)->fs_magic == FS_UFS2_MAGIC ? \ + dino->u2.field : dino->u1.field) + + dino = ffs_dinode_lookup(ffs, inum); + myflags |= (UFS_DINO_FIELD(ffs->fs, dino, di_nlink) ? + FS_FLAG_LINK : FS_FLAG_UNLINK); + if ((flags & myflags) != myflags) + continue; + + /* + * Apply the used/unused restriction. + */ + myflags |= (INOTIME(UFS_DINO_FIELD(ffs->fs, dino, di_ctime)) ? + FS_FLAG_USED : FS_FLAG_UNUSED); + if ((flags & myflags) != myflags) + continue; + + /* + * Fill in a file system-independent inode structure and pass control + * to the application. + */ + ffs_copy_inode(ffs->fs, dino, fs_inode); + action(inum, fs_inode, myflags, ptr); + } + + /* + * Cleanup. + */ + fs_inode_free(fs_inode); +} + +/* ffs_block_walk - block iterator */ + +void ffs_block_walk(FS_INFO *fs, DADDR_T start, DADDR_T last, int flags, + FS_BLOCK_WALK_FN action, char *ptr) +{ + char *myname = "ffs_block_walk"; + FFS_INFO *ffs = (FFS_INFO *) fs; + FS_BUF *fs_buf = fs_buf_alloc(fs->block_size * fs->block_frags); + CGNUM_T cg_num; + struct cg *cg = 0; + DADDR_T dbase; + DADDR_T dmin; /* first data block in group */ + DADDR_T sblock; /* super block in group */ + DADDR_T addr; + DADDR_T faddr; + unsigned char *freeblocks; + int myflags; + int want; + int frags; + char *null_block; + + /* + * Sanity checks. + */ + if (start < fs->start_block || start > fs->last_block) + error("%s: invalid start block number: %lu", myname, (ULONG) start); + if (last < fs->start_block || last > fs->last_block) + error("%s: invalid last block number: %lu", myname, (ULONG) last); + if ((flags & FS_FLAG_ALIGN) && (start % fs->block_frags) != 0) + error("%s: specify -b or specify block-aligned start block", myname); + + /* + * Other initialization. + */ + if (flags & FS_FLAG_ALIGN) { + null_block = mymalloc(fs->block_size); + memset(null_block, 0, fs->block_size); + } + + /* + * Iterate. This is not as tricky as it could be, because the free list + * map covers the entire disk partition, including blocks occupied by + * cylinder group maps, boot blocks, and other non-data blocks. + * + * Examine the disk one logical block at a time. A logical block may be + * composed of a number of fragment blocks. For example, the 4.4BSD + * filesystem has logical blocks of 8 fragments. + */ + for (addr = start; addr <= last; addr += fs->block_frags) { + + /* + * Be sure to use the right cylinder group information. + */ + cg_num = dtog(ffs->fs, addr); + if (cg == 0 || cg->cg_cgx != cg_num) { + cg = ffs_cgroup_lookup(ffs, cg_num); + freeblocks = (unsigned char *) cg_blksfree(cg); + dbase = cgbase(ffs->fs, cg_num); + dmin = cgdmin(ffs->fs, cg_num); + sblock = cgsblock(ffs->fs, cg_num); + } + if (addr < dbase) + remark("impossible: cyl group %lu: block %lu < cgbase %lu", + (unsigned long) cg_num, (unsigned long) addr, + (unsigned long) dbase); + + /* + * Prepare for file systems that have a partial last logical block. + */ + frags = (last + 1 - addr > fs->block_frags ? + fs->block_frags : last + 1 - addr); + + /* + * See if this logical block contains any fragments of interest. If + * not, skip the entire logical block. + */ + for (want = 0, faddr = addr; want == 0 && faddr < addr + frags; faddr++) + want = (flags & (isset(freeblocks, faddr - dbase) ? + FS_FLAG_UNALLOC : FS_FLAG_ALLOC)); + if (want == 0) + continue; + + /* + * Pass blocks of interest to the application, optionally padding the + * data with null blocks in order to maintain logical block + * alignment. + * + * Beware: FFS stores file data in the blocks between the start of a + * cylinder group and the start of its super block. + */ + for (faddr = addr; faddr < addr + frags; faddr++) { + myflags = (isset(freeblocks, faddr - dbase) ? + FS_FLAG_UNALLOC : FS_FLAG_ALLOC); + if (faddr >= sblock && faddr < dmin) + myflags |= FS_FLAG_META; + if ((myflags & FS_FLAG_META) && (myflags & FS_FLAG_UNALLOC)) + remark("impossible: unallocated meta block %lu!!", + (unsigned long) faddr); + if ((flags & myflags) != myflags) { + if (flags & FS_FLAG_ALIGN) + action(faddr, null_block, myflags, ptr); + } else { + if (fs_buf->addr < 0 + || faddr >= fs_buf->addr + fs->block_frags) + fs_read_block(fs, fs_buf, fs->block_size * frags, addr, + "data block"); + action(faddr, + fs_buf->data + fs->block_size * (faddr - fs_buf->addr), + myflags, ptr); + } + } + } + + /* + * Cleanup. + */ + if (flags & FS_FLAG_ALIGN) + free(null_block); + fs_buf_free(fs_buf); +} + +/* ffs_close - close a fast file system */ + +static void ffs_close(FS_INFO *fs) +{ + FFS_INFO *ffs = (FFS_INFO *) fs; + + close(ffs->fs_info.fd); + ffs_cgroup_free(ffs); + ffs_dinode_free(ffs); + free((char *) ffs->fs); + free(ffs); +} + +/* ffs_open - open a fast file system */ + +FS_INFO *ffs_open(const char *name) +{ + char *myname = "ffs_open"; + FFS_INFO *ffs = (FFS_INFO *) mymalloc(sizeof(*ffs)); + static off_t sblock_offs[] = SBLOCKSEARCH; + off_t *sp; + + /* + * Open the raw device and read the superblock. We must use a read buffer + * that is a multiple of the physical blocksize, because attempts to read + * a partial physical block can fail. XXX How does one know the physical + * blocksize without reading the disk? One assumes. + */ + if ((ffs->fs_info.fd = open(name, O_RDONLY)) < 0) + error("%s: open %s: %m", myname, name); + + /* + * Read the superblock. + */ + ffs->fs = (struct fs *) mymalloc(SBLOCKSIZE); + for (sp = sblock_offs; /* see below */ ; sp++) { + if (*sp < 0) + error("%s: no recognizable superblock found", name); + if (verbose) + remark("trying: offset %ld", (long) *sp); + if (LSEEK(ffs->fs_info.fd, *sp, SEEK_SET) != *sp) + error("%s: lseek: %m", myname); + if (read(ffs->fs_info.fd, (char *) ffs->fs, SBLOCKSIZE) != SBLOCKSIZE) + error("%s: read superblock: %m", name); + if (ffs->fs->fs_magic == FS_UFS2_MAGIC + || ffs->fs->fs_magic == FS_UFS1_MAGIC) + break; + } + if (verbose) + remark("UFS%d file system", ffs->fs->fs_magic == FS_UFS2_MAGIC ? + 2 : 1); + + /* + * Translate some filesystem-specific information to generic form. + */ + ffs->fs_info.inum_count = ffs->fs->fs_ncg * ffs->fs->fs_ipg; + ffs->fs_info.start_inum = 0; + ffs->fs_info.last_inum = ffs->fs_info.inum_count - 1; + ffs->fs_info.block_count = (ffs->fs->fs_magic == FS_UFS2_MAGIC ? + ffs->fs->fs_size : ffs->fs->fs_old_size); + ffs->fs_info.start_block = 0; + ffs->fs_info.last_block = ffs->fs_info.block_count - 1; + ffs->fs_info.block_size = ffs->fs->fs_fsize; + ffs->fs_info.file_bsize = ffs->fs->fs_bsize; + ffs->fs_info.addr_bsize = ffs->fs->fs_bsize; + ffs->fs_info.block_frags = ffs->fs->fs_frag; + + /* + * Other initialization: caches, callbacks. + */ + ffs->cg_buf = 0; + ffs->dino_buf = 0; + ffs->fs_info.seek_pos = -1; + ffs->fs_info.inode_walk = ffs_inode_walk; + ffs->fs_info.block_walk = ffs_block_walk; + ffs->fs_info.inode_lookup = ffs_inode_lookup; + ffs->fs_info.close = ffs_close; + + /* + * Print some stats. + */ + if (verbose) + fprintf(logfp, + "inodes %lu root ino %lu cyl groups %lu blocks %lu\n", + (ULONG) ffs->fs->fs_ncg * ffs->fs->fs_ipg, + (ULONG) ROOTINO, + (ULONG) ffs->fs->fs_ncg, + (ULONG) ffs->fs_info.block_count); + return (&ffs->fs_info); +} + +#endif diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/fs_tools.h /tmp/kIoa9vRMri/tct-1.18/src/fstools/fs_tools.h --- tct-1.11/src/fstools/fs_tools.h 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/src/fstools/fs_tools.h 2008-05-08 11:44:52.000000000 +0100 @@ -115,6 +115,24 @@ #define INO_TO_CG ino_to_cg #endif +#if defined(FREEBSD5) +#define SUPPORTED +#include +#include +#include +#include +#define LSEEK lseek +#define OFF_T off_t +#define STRTOUL strtoul +#define itod(fs,i) ino_to_fsba(fs,i) +#define itoo(fs,i) ino_to_fsbo(fs,i) +#define INOTIME(t) (t) +#define DADDR_T int64_t +#define UFS_TYPE "ufs" +#define DEF_FSTYPE UFS_TYPE +#define INO_TO_CG ino_to_cg +#endif + /* * BSD/OS can handle filesystems > 2GB. */ @@ -185,13 +203,13 @@ #define SUPPORTED #include #define HAVE_EXT2FS - -#if !defined(__ia64__) && !defined(__alpha__) && !defined(__x86_64__) +#define HAVE_DTIME +#if (_FILE_OFFSET_BITS == 64) +#define LSEEK lseek +#define OFF_T off_t +#else #define USE_MYLSEEK #define HAVE_LLSEEK -#endif - -#define HAVE_DTIME #if !defined(__ia64__) && !defined(__alpha__) && !defined(__x86_64__) #define LSEEK mylseek @@ -200,6 +218,7 @@ #endif #define OFF_T long long +#endif #define STRTOUL strtoul #define DADDR_T __u32 #define EXT2FS_TYPE "ext2fs" diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/ils.c /tmp/kIoa9vRMri/tct-1.18/src/fstools/ils.c --- tct-1.11/src/fstools/ils.c 2002-09-16 19:36:01.000000000 +0100 +++ tct-1.18/src/fstools/ils.c 2004-01-06 15:31:09.000000000 +0000 @@ -182,10 +182,16 @@ #ifdef HAVE_DTIME printf("|%lu", (ULONG) fs_inode->dtime); #endif - printf("|%lo|%d|%lu|%lu|%lu\n", - (ULONG) fs_inode->mode, (int) fs_inode->nlink, - (ULONG) fs_inode->size, (ULONG) fs_inode->direct_addr[0], - (ULONG) fs_inode->direct_addr[1]); + if (sizeof(fs_inode->size) <= sizeof(unsigned long)) + printf("|%lo|%d|%lu|%lu|%lu\n", + (ULONG) fs_inode->mode, (int) fs_inode->nlink, + (ULONG) fs_inode->size, (ULONG) fs_inode->direct_addr[0], + (ULONG) fs_inode->direct_addr[1]); + else + printf("|%lo|%d|%llu|%lu|%lu\n", + (ULONG) fs_inode->mode, (int) fs_inode->nlink, + (unsigned long long) fs_inode->size, (ULONG) fs_inode->direct_addr[0], + (ULONG) fs_inode->direct_addr[1]); } /* main - open file system, list inode info */ diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/makedefs /tmp/kIoa9vRMri/tct-1.18/src/fstools/makedefs --- tct-1.11/src/fstools/makedefs 2002-03-22 19:44:10.000000000 +0000 +++ tct-1.18/src/fstools/makedefs 2007-04-09 14:32:52.000000000 +0100 @@ -8,6 +8,8 @@ ;; FreeBSD.4*) DEFS="-DFREEBSD4" ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + ;; OpenBSD.2*) DEFS="-DOPENBSD2" ;; OpenBSD.3*) DEFS="-DOPENBSD3" @@ -27,9 +29,9 @@ SunOS.5*) DEFS="-DSUNOS5 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" RANLIB=":" ;; - Linux.2.4*) DEFS="-DLINUX2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" +Linux.2.[0-3].*)DEFS="-DLINUX2" ;; - Linux.2*) DEFS="-DLINUX2" + Linux.2.*) DEFS="-DLINUX2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" ;; *) echo unsupported system: $SYSTEM.$RELEASE 1>&2; exit 1 ;; @@ -37,5 +39,5 @@ unset MAKELEVEL # shut up chatty GNU make -make DEFS="$DEFS" CC="${CC-gcc -Wunused}" RANLIB="${RANLIB-ranlib}" \ +make DEFS="$DEFS" CC="${CC-gcc -Wunused -Wformat}" RANLIB="${RANLIB-ranlib}" \ AR="${AR-ar rv}" SYSLIBS="$SYSLIBS" all diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/fstools/mylseek.c /tmp/kIoa9vRMri/tct-1.18/src/fstools/mylseek.c --- tct-1.11/src/fstools/mylseek.c 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/src/fstools/mylseek.c 2008-05-08 11:44:52.000000000 +0100 @@ -23,7 +23,8 @@ #ifdef USE_MYLSEEK #ifdef HAVE_LLSEEK #include -#include +#include +#include /* * This is LINUX, live on the bleeding edge and watch your software break diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/lastcomm/Makefile /tmp/kIoa9vRMri/tct-1.18/src/lastcomm/Makefile --- tct-1.11/src/lastcomm/Makefile 2000-07-31 00:39:20.000000000 +0100 +++ tct-1.18/src/lastcomm/Makefile 2003-08-31 00:58:32.000000000 +0100 @@ -2,7 +2,7 @@ CC = gcc OPT = -O DEBUG = -g -INCL = +INCL = -I. CFLAGS = $(DEFS) $(INCL) $(OPT) $(DEBUG) OBJS = lastcomm.o $(MISSING_OBJS) BIN_DIR = ../../bin diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/lastcomm/makedefs /tmp/kIoa9vRMri/tct-1.18/src/lastcomm/makedefs --- tct-1.11/src/lastcomm/makedefs 2002-03-22 19:44:10.000000000 +0000 +++ tct-1.18/src/lastcomm/makedefs 2003-08-31 00:49:13.000000000 +0100 @@ -4,10 +4,12 @@ case "$SYSTEM.$RELEASE" in FreeBSD.2*) DEFS="-DFREEBSD2" ;; - FreeBSD.4*) DEFS="-DFREEBSD3" - ;; FreeBSD.3*) DEFS="-DFREEBSD3" ;; + FreeBSD.4*) DEFS="-DFREEBSD4" + ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + ;; OpenBSD.3*) DEFS="-DOPENBSD3" ;; OpenBSD.2*) DEFS="-DOPENBSD2" diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/lastcomm/sys_defs.h /tmp/kIoa9vRMri/tct-1.18/src/lastcomm/sys_defs.h --- tct-1.11/src/lastcomm/sys_defs.h 2008-05-08 11:44:51.000000000 +0100 +++ tct-1.18/src/lastcomm/sys_defs.h 2008-05-08 11:44:52.000000000 +0100 @@ -6,6 +6,7 @@ * This software is distributed under the IBM Public License. */ #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \ + || defined(FREEBSD5) \ || defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \ || defined(OPENBSD2) || defined(OPENBSD3) #define SUPPORTED diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/major_minor/makedefs /tmp/kIoa9vRMri/tct-1.18/src/major_minor/makedefs --- tct-1.11/src/major_minor/makedefs 2002-03-22 19:44:11.000000000 +0000 +++ tct-1.18/src/major_minor/makedefs 2003-08-31 00:59:37.000000000 +0100 @@ -6,7 +6,9 @@ ;; FreeBSD.3*) DEFS="-DFREEBSD3" ;; - FreeBSD.4*) DEFS="-DFREEBSD3" + FreeBSD.4*) DEFS="-DFREEBSD4" + ;; + FreeBSD.5*) DEFS="-DFREEBSD5" ;; OpenBSD.2*) DEFS="-DOPENBSD2" ;; diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/misc/makedefs /tmp/kIoa9vRMri/tct-1.18/src/misc/makedefs --- tct-1.11/src/misc/makedefs 2002-03-22 19:44:11.000000000 +0000 +++ tct-1.18/src/misc/makedefs 2003-08-31 00:18:41.000000000 +0100 @@ -8,6 +8,8 @@ ;; FreeBSD.4*) DEFS="-DFREEBSD4" ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + ;; OpenBSD.2*) DEFS="-DOPENBSD2" ;; OpenBSD.3*) DEFS="-DOPENBSD3" diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/misc/timeout.c /tmp/kIoa9vRMri/tct-1.18/src/misc/timeout.c --- tct-1.11/src/misc/timeout.c 2001-09-09 22:46:10.000000000 +0100 +++ tct-1.18/src/misc/timeout.c 2007-01-11 21:10:29.000000000 +0000 @@ -22,14 +22,19 @@ /* DIAGNOSTICS /* The command exit status is the exit status of the command /* (status 1 in case of a usage error). +/* LICENSE +/* The IBM PUBLIC LICENSE must be distributed with this +/* software. +/* HISTORY +/* This program was first released as part of SATAN. /* AUTHOR(S) /* Wietse Venema -/* This program is part of SATAN. /*--*/ /* System libraries. */ #include +#include #include #include #include @@ -103,6 +108,6 @@ alarm(time_to_run); while ((pid = wait(&status)) != -1 && pid != child_pid) /* void */ ; - return (pid == child_pid ? status : -1); + return (pid == child_pid ? WEXITSTATUS(status) | WTERMSIG(status) : -1); } } diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/pcat/makedefs /tmp/kIoa9vRMri/tct-1.18/src/pcat/makedefs --- tct-1.11/src/pcat/makedefs 2002-03-22 19:44:11.000000000 +0000 +++ tct-1.18/src/pcat/makedefs 2003-10-14 22:07:44.000000000 +0100 @@ -3,10 +3,16 @@ case "$SYSTEM.$RELEASE" in FreeBSD.2*) DEFS="-DFREEBSD2" + SYSLIBS="-lkvm" ;; FreeBSD.3*) DEFS="-DFREEBSD3" + SYSLIBS="-lkvm" ;; FreeBSD.4*) DEFS="-DFREEBSD4" + SYSLIBS="-lkvm" + ;; + FreeBSD.5*) DEFS="-DFREEBSD5" + SYSLIBS="-lkvm" ;; OpenBSD.2*) DEFS="-DOPENBSD2" SYSLIBS="-lkvm" diff -Nru /tmp/BHdHZf2_d2/tct-1.11/src/pcat/pcat.c /tmp/kIoa9vRMri/tct-1.18/src/pcat/pcat.c --- tct-1.11/src/pcat/pcat.c 2002-03-22 19:44:11.000000000 +0000 +++ tct-1.18/src/pcat/pcat.c 2006-03-17 14:25:43.000000000 +0000 @@ -22,6 +22,7 @@ /* This option does not work on some Solaris versions. /* .IP "\fB-m\fR \fImapfile\fR" /* Print the process memory map to \fImapfile\fR, one entry per line. +/* Specify \fB-m-\fR to write to the standard error stream. /* Each map entry consists of a region start address and the first /* address beyond that region. Addresses are separated by space, /* and are printed as hexadecimal numbers (0xhhhh). @@ -78,6 +79,7 @@ #include #include #include +#include /* * Solaris 2.x has /proc, which immensely simplifies our task. However, the @@ -103,10 +105,40 @@ /* * FreeBSD 2.x and later have /proc, which immensely simplifies our task. + * Unfortunately, FreeBSD 5.x no longer mounts /proc by default. We try to + * use /proc first and use ptrace() only if we have to. + * + * FreeBSD PTRACE_DETACH does not resume the target process so we must send + * SIGCONT, but only if the process was stopped by us. + * + * FreeBSD 5 no longer supports ptrace() access to the u area, so we have to + * grope kernel memory instead. */ -#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) +#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \ + || defined(FREEBSD5) #define SUPPORTED +#include +#include +#include +#include +#include +#include #define HAVE_PROC_MEM +#define HAVE_PTRACE_MEM +#define PTRACE_ATTACH PT_ATTACH +#define PTRACE_DETACH PT_DETACH +#define PTRACE_PEEKDATA PT_READ_D +#define PTRACE_ARG3_T caddr_t +#endif + +#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) +#define PROCP_STATUS(p) ((p)->kp_proc.p_stat) +#define PROCP_VMSPACE(p) ((p)->kp_proc.p_vmspace) +#endif + +#if defined(FREEBSD5) +#define PROCP_STATUS(p) ((p)->ki_stat) +#define PROCP_VMSPACE(p) ((p)->ki_vmspace) #endif /* @@ -223,12 +255,13 @@ /* * Structure to carry around process-related info. */ -typedef struct { +typedef struct PROC_INFO { #ifdef HAVE_PROC_MEM int mem_fd; /* process memory */ #endif pid_t pid; /* a process id */ int map_count; /* nr of map entries */ + void (*read_proc) (struct PROC_INFO *, char *, int, off_t); MAP_INFO map_info[1]; /* actually a bunch. */ } PROC_INFO; @@ -430,11 +463,12 @@ #endif -/* read_proc - read block of memory at specified position */ +#ifdef HAVE_PROC_MEM + +/* read_proc_mem - read block of memory at specified position */ -static void read_proc(PROC_INFO *proc, char *data, int len, off_t offset) +static void read_proc_mem(PROC_INFO *proc, char *data, int len, off_t offset) { -#ifdef HAVE_PROC_MEM if (verbose) fprintf(stderr, "read seek to 0x%lx\n", (long) offset); #ifdef USE_PREAD @@ -446,11 +480,19 @@ if (read(proc->mem_fd, data, len) != len) error("read: %m"); #endif +} #endif #ifdef HAVE_PTRACE_MEM + +/* read_ptrace_mem - read block of memory at specified position */ + +static void read_ptrace_mem(PROC_INFO *proc, char *data, int len, off_t offset) +{ #ifdef USE_PTRACE_READDATA + if (verbose) + fprintf(stderr, "read seek to 0x%lx\n", (long) offset); if (ptrace(PTRACE_READDATA, proc->pid, (int) offset, len, data) < 0) error("PTRACE_READDATA: %m%s", errno == EIO ? "; did you use GCC with another machine's header files?" : ""); @@ -463,6 +505,8 @@ * XXX This breaks when memory segments aren't word-aligned or when * memory segments sizes aren't a multiple of the word size. Tough. */ + if (verbose) + fprintf(stderr, "read seek to 0x%lx\n", (long) offset); if (offset % sizeof(int)) panic("read_proc: offset 0x%lx is not word-aligned", (long) offset); if (len % sizeof(int)) @@ -473,9 +517,9 @@ words[n] = call_ptrace(PTRACE_PEEKDATA, proc->pid, addr, 0); memcpy(data, (char *) words, len); #endif +} #endif -} /* write_here - write a block at specified position */ @@ -509,7 +553,7 @@ where = proc->map_info[n].start; while (size > 0) { len = (size > sizeof(buf) ? sizeof(buf) : size); - read_proc(proc, buf, len, where); + proc->read_proc(proc, buf, len, where); if (keep_holes) { write_here(out_fd, buf, len, where); } else { @@ -526,44 +570,121 @@ static PROC_INFO *open_process(pid_t pid) { -#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) +#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \ + || defined(FREEBSD5) PROC_INFO *proc = (PROC_INFO *) mymalloc(sizeof(*proc)); - char buf[READ_BUFSIZ_CHARS]; MAP_INFO *mp; + struct kinfo_proc *procp; + kvm_t *kd; + struct vmspace vmspace; + struct vm_map_entry entry; + u_long addr; + int cnt; + char buf[READ_BUFSIZ_CHARS]; FILE *map_fp; /* - * Attach to process memory. XXX Suspend/resume the process if it isn't - * stopped. + * Attach to process memory. Try to use /proc first. XXX Suspend/resume + * the process if it isn't stopped. */ - sprintf(buf, "/proc/%ld/mem", (long) pid); - if ((proc->mem_fd = open(buf, O_RDONLY)) < 0) - error("open %s: %m", buf); init_cleanup(pid); + sprintf(buf, "/proc/%ld/mem", (long) pid); + if ((proc->mem_fd = open(buf, O_RDONLY)) >= 0) { + proc->read_proc = read_proc_mem; + + /* + * Look up the process memory map. + * + * XXX The map must fit inside one read operation. If the read fails + * with EFBIG then we should increase the read buffer size and retry. + */ + sprintf(buf, "/proc/%ld/map", (long) pid); + if ((map_fp = fopen(buf, "r")) == 0) + error("open %s: %m", buf); + + for (proc->map_count = 0; fgets(buf, sizeof(buf), map_fp) != 0; proc->map_count++) { + if (proc->map_count > 0) + proc = (PROC_INFO *) myrealloc((char *) proc, + sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); + mp = proc->map_info + proc->map_count; + if (sscanf(buf, "%lx %lx", &mp->start, &mp->end) != 2) + error("unexpected map format: %s", buf); + if (verbose) + fprintf(stderr, "map entry: 0x%lx 0x%lx\n", mp->start, mp->end); + if (map_out) + fprintf(map_out, "0x%lx 0x%lx\n", mp->start, mp->end); + } + if (ferror(map_fp)) + error("map read: %m"); + (void) fclose(map_fp); + } /* - * Look up the process memory map. - */ - sprintf(buf, "/proc/%ld/map", (long) pid); - if ((map_fp = fopen(buf, "r")) == 0) - error("open %s: %m", buf); + * We can't use /proc so we fall back to ptrace() and to peeking at + * kernel memory. Look up the process status before attaching to it: 1) + * the ptrace() detach operation will resume a stopped process, so we + * must re-suspend it; 2) the ptrace() detach operation will not resume a + * process that wasn't stopped, so we must resume it. + */ + else { + proc->read_proc = read_ptrace_mem; + + /* + * Look up the process status before attaching to it: PTRACE_DETACH + * will resume a stopped process, so we must re-suspend it. + */ + if ((kd = kvm_open((char *) 0, (char *) 0, (char *) 0, O_RDONLY, "pcat")) == 0) + error("kvm_open: %m"); + if ((procp = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt)) == 0 || cnt != 1) + error("kvm_getprocs: %m"); + if (PROCP_STATUS(procp) & SSTOP) + pre_detach_signal = post_detach_signal = SIGSTOP; + else + pre_detach_signal = SIGCONT; + + /* + * Attach to process memory and stop the process. + */ + init_cleanup(pid); + if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) + error("ptrace PTRACE_ATTACH: %m"); + ptrace_attach_wait(pid); + + /* + * Look up the process memory map. With FreeBSD 5 the u area is no + * longer accessible via ptrace() so we must grope kernel memory. + * This requires root privileges. + */ + if (kvm_read(kd, (u_long) PROCP_VMSPACE(procp), + (void *) &vmspace, sizeof(vmspace)) != sizeof(vmspace)) + error("struct vmspace kvm_read: %m"); + + /* + * Copied from the code that implements /proc/pid/map. + */ + for (proc->map_count = 0, addr = (u_long) vmspace.vm_map.header.next; + addr != (u_long) PROCP_VMSPACE(procp) + + offsetof(struct vmspace, vm_map) + + offsetof(struct vm_map, header); + proc->map_count++, addr = (u_long) entry.next) { + + if (kvm_read(kd, addr, (void *) &entry, + sizeof(entry)) != sizeof(entry)) + error("struct vm_map_entry kvm_read: %m"); + if (proc->map_count > 0) + proc = (PROC_INFO *) myrealloc((char *) proc, + sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); + mp = proc->map_info + proc->map_count; + mp->start = entry.start; + mp->end = entry.end; + if (verbose) + fprintf(stderr, "map entry: 0x%lx 0x%lx\n", mp->start, mp->end); + if (map_out) + fprintf(map_out, "0x%lx 0x%lx\n", mp->start, mp->end); + } - for (proc->map_count = 0; fgets(buf, sizeof(buf), map_fp) != 0; proc->map_count++) { - if (proc->map_count > 0) - proc = (PROC_INFO *) myrealloc((char *) proc, - sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); - mp = proc->map_info + proc->map_count; - if (sscanf(buf, "%lx %lx", &mp->start, &mp->end) != 2) - error("unexpected map format: %s", buf); - if (verbose) - fprintf(stderr, "map entry: 0x%lx 0x%lx\n", mp->start, mp->end); - if (map_out) - fprintf(map_out, "0x%lx 0x%lx\n", mp->start, mp->end); + kvm_close(kd); } - if (ferror(map_fp)) - error("map read: %m"); - (void) fclose(map_fp); - proc->pid = pid; return (proc); @@ -576,6 +697,8 @@ struct prmap *pr; MAP_INFO *mp; + proc->read_proc = read_proc_mem; + /* * Attach to process memory. XXX Suspend/resume the process if it isn't * stopped. @@ -590,6 +713,8 @@ */ if (ioctl(proc->mem_fd, PIOCNMAP, (char *) &proc->map_count) < 0) error("ioctl PIOCNMAP: %m"); + proc = (PROC_INFO *) myrealloc((char *) proc, + sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); prmap = (struct prmap *) mymalloc((proc->map_count + 1) * sizeof(*prmap)); if (ioctl(proc->mem_fd, PIOCMAP, (char *) prmap) < 0) error("ioctl PIOCMAP: %m"); @@ -615,6 +740,8 @@ MAP_INFO *mp; FILE *map_fp; + proc->read_proc = read_proc_mem; + /* * Attach to process memory. XXX Suspend/resume the process if it isn't * stopped. @@ -663,11 +790,13 @@ */ init_cleanup(pid); #ifdef HAVE_PROC_MEM + proc->read_proc = read_proc_mem; sprintf(buf, "/proc/%ld/mem", (long) pid); if ((proc->mem_fd = open(buf, O_RDONLY)) < 0) error("open %s: %m", buf); #endif #ifdef HAVE_PTRACE_MEM + proc->read_proc = read_ptrace_mem; if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) error("ptrace PTRACE_ATTACH: %m"); ptrace_attach_wait(pid); @@ -731,6 +860,7 @@ */ proc = (PROC_INFO *) mymalloc(sizeof(*proc) + 2 * sizeof(MAP_INFO)); proc->map_count = 3; + proc->read_proc = read_ptrace_mem; /* * Attach to process memory and stop the process. @@ -818,6 +948,7 @@ */ proc = (PROC_INFO *) mymalloc(sizeof(*proc) + 2 * sizeof(MAP_INFO)); proc->map_count = 3; + proc->read_proc = read_ptrace_mem; /* * Attach to process memory and stop the process. @@ -896,6 +1027,7 @@ */ proc = (PROC_INFO *) mymalloc(sizeof(*proc) + 2 * sizeof(MAP_INFO)); proc->map_count = 3; + proc->read_proc = read_ptrace_mem; /* * Attach to process memory and stop the process. @@ -957,7 +1089,7 @@ static void close_process(PROC_INFO *proc) { #ifdef HAVE_PROC_MEM - if (close(proc->mem_fd) < 0) + if (proc->mem_fd >= 0 && close(proc->mem_fd) < 0) error("close memory: %m"); #endif free((char *) proc); @@ -992,8 +1124,12 @@ keep_holes = 1; break; case 'm': - if ((map_out = fopen(optarg, "w")) == 0) - error("create map file %s: %m", optarg); + if (strcmp(optarg, "-") == 0) { + map_out = stderr; + } else { + if ((map_out = fopen(optarg, "w")) == 0) + error("create map file %s: %m", optarg); + } break; case 'v': verbose++;