4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
34 #pragma ident "%Z%%M% %I% %E% SMI"
37 * ff -- obtain file names from reading filesystem
41 #define MAXNINDIR (MAXBSIZE / sizeof (daddr32_t))
43 #include <sys/param.h>
44 #include <sys/types.h>
45 #include <sys/mntent.h>
46 #include <sys/vnode.h>
47 #include <sys/fs/ufs_inode.h>
49 #include <sys/fs/ufs_fs.h>
50 #include <sys/fs/ufs_fsdir.h>
60 #define MIN_PHYS_READ BBSIZE
61 #define DAY (24*60*60)
66 char xxx
[SBSIZE
]; /* because fs is variable length */
68 #define sblock real_fs.sblk
70 struct dinode
*itab
; /* = (struct dinode *)itab; */
85 int h_name_index
; /* index into string table */
91 #define STRNGTAB_INCR (1024*16) /* amount to grow strngtab */
92 #define MAX_STRNGTAB_INDEX() (strngtab_size - 1)
93 #define AVG_PATH_LEN 30 /* average (?) length of name */
100 int Aflg
= 0; /* accessed in n days */
101 int Mflg
= 0; /* modified in n days */
102 int Nflg
= 0; /* modified more recently than 'file' */
103 int Cflg
= 0; /* changed within n days */
104 int aflg
= 0; /* print the names `.' and `..' */
105 int sflg
= 0; /* print only special files and files with set-user-ID mode */
106 int Sflg
= 0; /* print file size */
107 int iflg
= 0; /* number of inodes being searched for */
108 int Iflg
= 0; /* do not print i-number */
109 int Lflg
= 0; /* supplementary list of multiply linked files */
111 int pflg
= 0; /* a prefix exists */
112 int uflg
= 0; /* print the owner's login name */
117 int imax
; /* highest inode number */
120 int Adelay
; /* Access delay */
121 int Asign
; /* Access sign */
122 int Mdelay
; /* Modify delay */
123 int Msign
; /* Modify sign */
124 int Cdelay
; /* change delay */
125 int Csign
; /* change sign */
126 time_t Nage
; /* Last modification time of the file */
127 char *Lname
; /* filename for supplementary list */
128 FILE *Lfile
; /* file for supplementary list */
131 * Function prototypes
133 void check(char *file
);
134 void pass1(struct dinode
*ip
);
135 void pass2(struct dinode
*ip
);
136 void pass3(struct dinode
*ip
);
137 struct direct
*dreaddir(struct dirstuff
*dirp
);
138 int dotname(struct direct
*dp
);
139 void pname(FILE *stream
, ino_t i
, int lev
);
140 struct htab
*lookup(ino_t i
, int ef
);
141 void bread(diskaddr_t bno
, char *buf
, int cnt
);
142 diskaddr_t
bmap(diskaddr_t i
);
143 struct dinode
*ginode(ino_t inumber
);
144 char *user_name(int uid
);
145 int cmp(int a
, int b
, int s
);
146 time_t mod_time(char *file
);
147 void out_multilinks();
149 int extend_strngtab(unsigned int size
);
174 main(int argc
, char *argv
[])
178 char *suboptions
, *value
;
182 Today
= time((time_t *)0);
183 while ((opt
= getopt(argc
, argv
, "Ia:c:i:lm:n:o:p:su")) != EOF
) {
188 Adelay
= atoi(optarg
);
198 Cdelay
= atoi(optarg
);
204 Lname
= tmpnam((char *)0);
205 if ((Lfile
= fopen(Lname
, "w+")) == NULL
) {
207 (void) fprintf(stderr
,
208 "ff: unable to open temp file, -l ignored\n");
215 Mdelay
= atoi(optarg
);
221 Nage
= mod_time(optarg
);
226 * ufs specific options.
230 if (*suboptions
== '\0')
232 while (*suboptions
!= '\0') {
233 switch ((getsubopt(&suboptions
,
255 while ((p
= (char *)strtok(((first
++ == 0) ?
256 optarg
: ((char *)0)), ", ")) != NULL
) {
257 if ((n
= atoi(p
)) == 0)
283 argv
= &argv
[optind
];
301 fi
= open64(file
, 0);
303 (void) fprintf(stderr
, "ff: cannot open %s\n", file
);
308 (void) printf("%s:\n", file
);
310 bread(SBLOCK
, (char *)&sblock
, SBSIZE
);
311 if ((sblock
.fs_magic
!= FS_MAGIC
) &&
312 (sblock
.fs_magic
!= MTB_UFS_MAGIC
)) {
313 (void) fprintf(stderr
, "%s: not a ufs file system\n", file
);
318 if (sblock
.fs_magic
== FS_MAGIC
&&
319 (sblock
.fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2
&&
320 sblock
.fs_version
!= UFS_VERSION_MIN
)) {
321 (void) fprintf(stderr
, "%s: unrecognized version of UFS: %d\n",
322 file
, sblock
.fs_version
);
327 if (sblock
.fs_magic
== MTB_UFS_MAGIC
&&
328 (sblock
.fs_version
> MTB_UFS_VERSION_1
||
329 sblock
.fs_version
< MTB_UFS_VERSION_MIN
)) {
330 (void) fprintf(stderr
, "%s: unrecognized version of UFS: %d\n",
331 file
, sblock
.fs_version
);
336 /* If fs is logged, roll the log. */
337 if (sblock
.fs_logbno
) {
338 switch (rl_roll_log(file
)) {
341 * Reread the superblock. Rolling the log may have
344 bread(SBLOCK
, (char *)&sblock
, SBSIZE
);
347 (void) printf("Warning: Cannot roll log for %s. %s\n",
348 file
, strerror(errno
));
351 (void) printf("Warning: Cannot roll log for %s.\n ",
358 itab
= (struct dinode
*)calloc(sblock
.fs_ipg
, sizeof (struct dinode
));
359 imax
= sblock
.fs_ncg
* sblock
.fs_ipg
;
361 hsize
= sblock
.fs_ipg
* sblock
.fs_ncg
- sblock
.fs_cstotal
.cs_nifree
+ 1;
362 htab
= (struct htab
*)calloc(hsize
, sizeof (struct htab
));
364 if (!extend_strngtab(AVG_PATH_LEN
* hsize
)) {
365 (void) printf("not enough memory to allocate tables\n");
371 if ((itab
== NULL
) || (htab
== NULL
)) {
372 (void) printf("not enough memory to allocate tables\n");
377 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
378 bread(fsbtodb(&sblock
, cgimin(&sblock
, c
)), (char *)itab
,
379 (int)(sblock
.fs_ipg
* sizeof (struct dinode
)));
380 for (j
= 0; j
< sblock
.fs_ipg
; j
++) {
381 if (itab
[j
].di_smode
!= 0) {
382 itab
[j
].di_mode
= itab
[j
].di_smode
;
383 if (itab
[j
].di_suid
!= (o_uid_t
)UID_LONG
)
384 itab
[j
].di_uid
= (unsigned int)itab
[j
].di_suid
;
385 if (itab
[j
].di_sgid
!= GID_LONG
)
386 itab
[j
].di_gid
= (unsigned int)itab
[j
].di_sgid
;
392 ilist
[nxfile
+1].ino
= 0;
394 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
395 bread(fsbtodb(&sblock
, cgimin(&sblock
, c
)), (char *)itab
,
396 (int)(sblock
.fs_ipg
* sizeof (struct dinode
)));
397 for (j
= 0; j
< sblock
.fs_ipg
; j
++) {
398 if (itab
[j
].di_smode
!= 0) {
399 itab
[j
].di_mode
= itab
[j
].di_smode
;
406 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
407 bread(fsbtodb(&sblock
, cgimin(&sblock
, c
)), (char *)itab
,
408 (int)(sblock
.fs_ipg
* sizeof (struct dinode
)));
409 for (j
= 0; j
< sblock
.fs_ipg
; j
++) {
410 if (itab
[j
].di_smode
!= 0) {
411 itab
[j
].di_mode
= itab
[j
].di_smode
;
418 for (i
= iflg
; i
< NB
; i
++)
427 pass1(struct dinode
*ip
)
432 for (i
= 0; i
< iflg
; i
++)
433 if (ino
== ilist
[i
].ino
) {
434 ilist
[i
].mode
= ip
->di_mode
;
435 ilist
[i
].uid
= ip
->di_uid
;
436 ilist
[i
].gid
= ip
->di_gid
;
438 if ((ip
->di_mode
& IFMT
) != IFDIR
) {
439 if (sflg
== 0 || nxfile
>= NB
)
441 if ((ip
->di_mode
&IFMT
) == IFBLK
||
442 (ip
->di_mode
&IFMT
) == IFCHR
|| ip
->di_mode
&(ISUID
|ISGID
)) {
443 ilist
[nxfile
].ino
= ino
;
444 ilist
[nxfile
].mode
= ip
->di_mode
;
445 ilist
[nxfile
].uid
= ip
->di_uid
;
446 ilist
[nxfile
++].gid
= ip
->di_gid
;
450 (void) lookup(ino
, 1);
454 pass2(struct dinode
*ip
)
457 struct dirstuff dirp
;
460 if ((ip
->di_mode
&IFMT
) != IFDIR
)
465 for (dp
= dreaddir(&dirp
); dp
!= NULL
; dp
= dreaddir(&dirp
)) {
470 hp
= lookup(dp
->d_ino
, 0);
476 nmlen
= strlen(dp
->d_name
);
478 if (strngloc
+ nmlen
+ 1 > MAX_STRNGTAB_INDEX()) {
479 if (!extend_strngtab(STRNGTAB_INCR
)) {
480 perror("ncheck: can't grow string table\n");
485 hp
->h_name_index
= strngloc
;
486 (void) strcpy(&strngtab
[strngloc
], dp
->d_name
);
487 strngloc
+= nmlen
+ 1;
492 pass3(struct dinode
*ip
)
495 struct dirstuff dirp
;
499 if ((ip
->di_mode
&IFMT
) != IFDIR
)
504 for (dp
= dreaddir(&dirp
); dp
!= NULL
; dp
= dreaddir(&dirp
)) {
505 if (aflg
== 0 && dotname(dp
))
507 if (sflg
== 0 && iflg
== 0)
509 for (k
= 0; ilist
[k
].ino
!= 0; k
++)
510 if (ilist
[k
].ino
== dp
->d_ino
)
512 if (ilist
[k
].ino
== 0)
515 (void) printf("mode %-6o uid %-5ld gid %-5ld ino ",
516 ilist
[k
].mode
, ilist
[k
].uid
, ilist
[k
].gid
);
518 if (Sflg
|| uflg
|| Aflg
|| Mflg
|| Cflg
|| Nflg
|| Lflg
)
519 dip
= ginode(dp
->d_ino
);
521 cmp((Today
- dip
->di_un
.di_icom
.ic_atime
)/DAY
, Adelay
,
523 (!Mflg
|| cmp((Today
- dip
->di_un
.di_icom
.ic_mtime
)/DAY
,
525 (!Cflg
|| cmp((Today
- dip
->di_un
.di_icom
.ic_mtime
)/DAY
,
527 (!Nflg
|| cmp(dip
->di_un
.di_icom
.ic_mtime
, Nage
, '+'))) {
529 (void) printf("%-5u\t", dp
->d_ino
);
530 pname(stdout
, ino
, 0);
531 (void) printf("/%s", dp
->d_name
);
532 if (lookup(dp
->d_ino
, 0))
535 (void) printf("\t%6lld",
536 dip
->di_un
.di_icom
.ic_lsize
);
538 (void) printf("\t%s",
539 user_name(dip
->di_un
.di_icom
.ic_uid
));
541 if (Lflg
&& (dip
->di_un
.di_icom
.ic_nlink
> 1)) {
542 (void) fprintf(Lfile
, "%-5u\t",
544 (void) fprintf(Lfile
, "%-5u\t",
545 dip
->di_un
.di_icom
.ic_nlink
);
546 pname(Lfile
, ino
, 0);
547 (void) fprintf(Lfile
, "/%s\n", dp
->d_name
);
556 * get next entry in a directory.
559 dreaddir(struct dirstuff
*dirp
)
565 if (dirp
->loc
>= (int)dirp
->ip
->di_size
)
567 if (blkoff(&sblock
, dirp
->loc
) == 0) {
568 lbn
= lblkno(&sblock
, dirp
->loc
);
572 bread(fsbtodb(&sblock
, d
), dirp
->dbuf
,
573 (int)dblksize(&sblock
, dirp
->ip
, (int)lbn
));
575 dp
= (struct direct
*)
576 (dirp
->dbuf
+ blkoff(&sblock
, dirp
->loc
));
577 dirp
->loc
+= dp
->d_reclen
;
585 dotname(struct direct
*dp
)
588 if (dp
->d_name
[0] == '.')
589 if (dp
->d_name
[1] == 0 ||
590 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == 0))
596 pname(FILE *stream
, ino_t i
, int lev
)
602 if ((hp
= lookup(i
, 0)) == 0) {
603 (void) fprintf(stream
, "???");
607 (void) fprintf(stream
, "...");
610 pname(stream
, hp
->h_pino
, ++lev
);
612 (void) fprintf(stream
, "%s/%s", prefix
,
613 &(strngtab
[hp
->h_name_index
]));
615 (void) fprintf(stream
, "/%s",
616 &(strngtab
[hp
->h_name_index
]));
620 lookup(ino_t i
, int ef
)
624 for (hp
= &htab
[(int)i
%hsize
]; hp
->h_ino
; ) {
627 if (++hp
>= &htab
[hsize
])
632 if (++nhent
>= hsize
) {
633 (void) fprintf(stderr
,
634 "ff: hsize of %ld is too small\n", hsize
);
642 bread(diskaddr_t bno
, char *buf
, int cnt
)
648 offset
= (offset_t
)bno
* DEV_BSIZE
;
649 if (llseek(fi
, offset
, 0) == (offset_t
)-1) {
650 (void) fprintf(stderr
,
651 "ff: llseek error %lx %lx\n",
652 ((long *)&offset
)[0], ((long *)&offset
)[1]);
653 for (i
= 0; i
< cnt
; i
++)
658 got
= read((int)fi
, buf
, cnt
);
661 (void) fprintf(stderr
,
662 "ff: (wanted %d got %d blk %lld)\n", cnt
, got
, bno
);
663 for (i
= 0; i
< cnt
; i
++)
671 daddr32_t ibuf
[MAXNINDIR
];
674 return ((diskaddr_t
)gip
->di_db
[i
]);
676 if (i
> NINDIR(&sblock
)) {
677 (void) fprintf(stderr
, "ff : %lu - huge directory\n", ino
);
678 return ((diskaddr_t
)0);
680 bread(fsbtodb(&sblock
, gip
->di_ib
[0]), (char *)ibuf
, sizeof (ibuf
));
681 return ((diskaddr_t
)ibuf
[i
]);
685 ginode(ino_t inumber
)
690 static diskaddr_t curr_dblk
;
691 static char buf
[MIN_PHYS_READ
];
694 if (inumber
< UFSROOTINO
|| (int)inumber
> imax
) {
695 (void) fprintf(stderr
,
696 "bad inode number %ld to ginode\n", inumber
);
699 iblk
= itod(&sblock
, (int)inumber
);
700 dblk
= fsbtodb(&sblock
, iblk
);
701 ioff
= itoo(&sblock
, (int)inumber
);
702 if (dblk
!= curr_dblk
) {
703 bread(dblk
, &buf
[0], sizeof (buf
));
707 ibuf
= (struct dinode
*)&buf
[0];
712 #define HASHNAMESIZE 16
715 struct name_ent
*name_nxt
;
719 struct name_ent
*hashtable
[HASHNAMESIZE
];
726 struct passwd
*pwent
;
728 h_index
= uid
% HASHNAMESIZE
;
729 for (hp
= hashtable
[h_index
]; hp
!= NULL
; hp
= hp
->name_nxt
) {
730 if (hp
->name_uid
== uid
) {
731 return (hp
->name_string
);
734 hp
= (struct name_ent
*)calloc(1, sizeof (struct name_ent
));
735 hp
->name_nxt
= hashtable
[h_index
];
737 hashtable
[h_index
] = hp
;
738 if ((pwent
= getpwuid(uid
)) == NULL
) {
739 hp
->name_string
= "unknown";
741 hp
->name_string
= (char *)strdup(pwent
->pw_name
);
745 return (hp
->name_string
);
749 cmp(int a
, int b
, int s
)
759 * We can't do this one by reading the disk directly, since there
760 * is no guarantee that the file is even on a local disk.
765 struct stat64 stat_buf
;
767 if (stat64(file
, &stat_buf
) < 0) {
768 (void) fprintf(stderr
, "ff: can't stat '%s' - ignored\n", file
);
771 return (stat_buf
.st_mtime
);
779 if ((length
= fseek(Lfile
, 0L, 2)) < 0) {
783 if ((length
= ftell(Lfile
)) > 0) {
784 (void) fprintf(stdout
,
785 "\nmultilink files\nIno\tLinks\tPathname\n\n");
788 (void) putc(getc(Lfile
), stdout
);
790 (void) fprintf(stdout
, "No multilink files\n");
791 (void) fclose(Lfile
);
797 (void) fprintf(stderr
,
798 "ufs usage: ff [-F ufs] [generic options] [-o a,m,s] special\n");
803 * Extend or create the string table.
804 * Preserves contents.
805 * Return non-zero for success.
808 extend_strngtab(unsigned int size
)
810 strngtab_size
+= size
;
811 strngtab
= (char *)realloc(strngtab
, strngtab_size
);
813 return ((int)strngtab
);