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) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
39 #pragma ident "%Z%%M% %I% %E% SMI"
42 * ncheck -- obtain file names from reading filesystem
45 #define MAXNINDIR (MAXBSIZE / sizeof (daddr_t))
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/vnode.h>
50 #include <sys/fs/ufs_inode.h>
51 #include <sys/fs/ufs_fs.h>
52 #include <sys/fs/ufs_fsdir.h>
63 char xxx
[SBSIZE
]; /* because fs is variable length */
65 #define sblock real_fs.sblk
80 int ilist_size
= 0; /* size of ilist[] */
81 int ilist_index
= 0; /* current index for storing into ilist; */
82 #define ILIST_SZ_INCR 1000 /* initial size, amount to incr sz of ilist */
83 #define MAX_ILIST_INDEX() (ilist_size - 1)
89 int h_name_index
; /* index into string table */
91 unsigned htab_size
; /* how much malloc'd for htab */
94 * string table: used to hold filenames.
99 #define STRNGTAB_INCR (1024*16) /* amount to grow strngtab */
100 #define MAX_STRNGTAB_INDEX() (strngtab_size - 1)
101 #define AVG_PATH_LEN 30 /* average (?) length of name */
114 int iflg
= 0; /* number of inodes being searched for */
123 daddr_t
bmap(daddr_t
);
124 void bread(diskaddr_t bno
, char *buf
, int cnt
);
125 void check(char *file
);
126 int dotname(struct direct
*dp
);
128 struct htab
*lookup(ino_t i
, int ef
);
129 void pass1(struct dinode
*ip
);
130 void pass2(struct dinode
*ip
);
131 void pass3(struct dinode
*ip
);
132 void pname(ino_t i
, int lev
);
135 struct direct
*dreaddir();
137 int extend_strngtab(unsigned int size
);
138 uchar_t
*extend_tbl(uchar_t
*tbl
, unsigned int *current_size
,
139 unsigned int new_size
);
151 main(int argc
, char *argv
[])
155 char *suboptions
, *value
;
161 while ((opt
= getopt(argc
, argv
, "ao:i:s")) != EOF
) {
170 * ufs specific options.
173 while (*suboptions
!= '\0') {
174 suboption
= getsubopt(&suboptions
,
189 while ((p
= (char *)strtok((first
++ == 0 ? optarg
: 0),
191 if ((n
= atoi(p
)) == 0)
196 if (iflg
> MAX_ILIST_INDEX())
210 (void) fprintf(stdout
, "ncheck -F ufs ");
211 for (opt_count
= 1; opt_count
< argc
;
213 opt_text
= argv
[opt_count
];
215 (void) fprintf(stdout
, " %s ",
218 (void) fprintf(stdout
, "\n");
227 argv
= &argv
[optind
];
240 fi
= open64(file
, 0);
242 (void) fprintf(stderr
, "ncheck: cannot open %s\n", file
);
247 (void) printf("%s:\n", file
);
249 bread((diskaddr_t
)SBLOCK
, (char *)&sblock
, SBSIZE
);
250 if ((sblock
.fs_magic
!= FS_MAGIC
) &&
251 (sblock
.fs_magic
!= MTB_UFS_MAGIC
)) {
252 (void) printf("%s: not a ufs file system\n", file
);
257 if ((sblock
.fs_magic
== FS_MAGIC
) &&
258 ((sblock
.fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2
) &&
259 (sblock
.fs_version
!= UFS_VERSION_MIN
))) {
260 (void) printf("%s: unrecognized ufs version number %d\n",
261 file
, sblock
.fs_version
);
266 if ((sblock
.fs_magic
== MTB_UFS_MAGIC
) &&
267 ((sblock
.fs_version
> MTB_UFS_VERSION_1
) ||
268 (sblock
.fs_version
< MTB_UFS_VERSION_MIN
))) {
269 (void) printf("%s: unrecognized ufs version number %d\n",
270 file
, sblock
.fs_version
);
275 /* If fs is logged, roll the log. */
276 if (sblock
.fs_logbno
) {
277 switch (rl_roll_log(file
)) {
280 * Reread the superblock. Rolling the log may have
283 bread((diskaddr_t
)SBLOCK
, (char *)&sblock
, SBSIZE
);
286 (void) printf("Warning: cannot roll log for %s. %s\n",
287 file
, strerror(errno
));
290 (void) printf("Warning: cannot roll log for %s.\n",
296 itab
= (struct dinode
*)extend_tbl((uchar_t
*)itab
, &itab_size
,
297 (unsigned)(sblock
.fs_ipg
* sizeof (struct dinode
)));
299 (void) fprintf(stderr
,
300 "ncheck: not enough memory for itab table\n");
305 hsize
= sblock
.fs_ipg
* sblock
.fs_ncg
- sblock
.fs_cstotal
.cs_nifree
+ 1;
307 htab
= (struct htab
*)extend_tbl((uchar_t
*)htab
, &htab_size
,
308 (unsigned)(hsize
* sizeof (struct htab
)));
310 (void) fprintf(stderr
,
311 "ncheck: not enough memory for htab table\n");
316 if (!extend_strngtab(AVG_PATH_LEN
* hsize
)) {
317 (void) printf("not enough memory to allocate tables\n");
324 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
325 bread(fsbtodb(&sblock
, cgimin(&sblock
, c
)), (char *)itab
,
326 (int)(sblock
.fs_ipg
* sizeof (struct dinode
)));
327 for (j
= 0; j
< sblock
.fs_ipg
; j
++) {
328 if (itab
[j
].di_smode
!= 0) {
329 itab
[j
].di_mode
= itab
[j
].di_smode
;
330 if (itab
[j
].di_suid
!= UID_LONG
)
331 itab
[j
].di_uid
= itab
[j
].di_suid
;
332 if (itab
[j
].di_sgid
!= GID_LONG
)
333 itab
[j
].di_gid
= itab
[j
].di_sgid
;
339 ilist
[ilist_index
++].ino
= 0;
340 if (ilist_index
> MAX_ILIST_INDEX())
343 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
344 bread(fsbtodb(&sblock
, cgimin(&sblock
, c
)), (char *)itab
,
345 (int)(sblock
.fs_ipg
* sizeof (struct dinode
)));
346 for (j
= 0; j
< sblock
.fs_ipg
; j
++) {
348 if (itab
[j
].di_smode
!= 0) {
349 itab
[j
].di_mode
= itab
[j
].di_smode
;
356 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
357 bread(fsbtodb(&sblock
, cgimin(&sblock
, c
)), (char *)itab
,
358 (int)(sblock
.fs_ipg
* sizeof (struct dinode
)));
359 for (j
= 0; j
< sblock
.fs_ipg
; j
++) {
360 if (itab
[j
].di_smode
!= 0) {
361 itab
[j
].di_mode
= itab
[j
].di_smode
;
370 * Clear those elements after inodes specified by "-i" out of
373 for (i
= iflg
; i
< ilist_index
; i
++) {
380 pass1(struct dinode
*ip
)
385 for (i
= 0; i
< iflg
; i
++)
386 if (ino
== ilist
[i
].ino
) {
387 ilist
[i
].mode
= ip
->di_mode
;
388 ilist
[i
].uid
= ip
->di_uid
;
389 ilist
[i
].gid
= ip
->di_gid
;
392 if ((ip
->di_mode
& IFMT
) != IFDIR
) {
395 if ((ip
->di_mode
& IFMT
) == IFBLK
||
396 (ip
->di_mode
& IFMT
) == IFCHR
||
397 ip
->di_mode
&(ISUID
|ISGID
)) {
398 ilist
[ilist_index
].ino
= ino
;
399 ilist
[ilist_index
].mode
= ip
->di_mode
;
400 ilist
[ilist_index
].uid
= ip
->di_uid
;
401 ilist
[ilist_index
].gid
= ip
->di_gid
;
402 if (++ilist_index
> MAX_ILIST_INDEX())
407 (void) lookup(ino
, 1);
411 pass2(struct dinode
*ip
)
414 struct dirstuff dirp
;
418 if ((ip
->di_mode
&IFMT
) != IFDIR
)
423 for (dp
= dreaddir(&dirp
); dp
!= NULL
; dp
= dreaddir(&dirp
)) {
429 hp
= lookup(dp
->d_ino
, 0);
436 nmlen
= strlen(dp
->d_name
);
438 if (strngloc
+ nmlen
+ 1 > MAX_STRNGTAB_INDEX()) {
439 if (!extend_strngtab(STRNGTAB_INCR
)) {
440 perror("ncheck: can't grow string table\n");
445 hp
->h_name_index
= strngloc
;
446 (void) strcpy(&strngtab
[strngloc
], dp
->d_name
);
447 strngloc
+= nmlen
+ 1;
452 pass3(struct dinode
*ip
)
455 struct dirstuff dirp
;
458 if ((ip
->di_mode
&IFMT
) != IFDIR
)
463 for (dp
= dreaddir(&dirp
); dp
!= NULL
; dp
= dreaddir(&dirp
)) {
464 if (aflg
== 0 && dotname(dp
))
467 if (sflg
== 0 && iflg
== 0)
469 for (k
= 0; k
< ilist_index
&& ilist
[k
].ino
!= 0; k
++) {
470 if (ilist
[k
].ino
== dp
->d_ino
) {
474 if (ilist
[k
].ino
== 0)
477 (void) printf("mode %-6o uid %-5ld gid %-5ld ino ",
478 ilist
[k
].mode
, ilist
[k
].uid
, ilist
[k
].gid
);
480 (void) printf("%-5u\t", dp
->d_ino
);
482 (void) printf("/%s", dp
->d_name
);
483 if (lookup(dp
->d_ino
, 0))
490 * get next entry in a directory.
493 dreaddir(struct dirstuff
*dirp
)
500 if (dirp
->loc
>= (int)dirp
->ip
->di_size
)
502 if (blkoff(&sblock
, dirp
->loc
) == 0) {
504 lbn
= lblkno(&sblock
, dirp
->loc
);
510 bread(fsbtodb(&sblock
, d
), dirp
->dbuf
,
511 (int)dblksize(&sblock
, dirp
->ip
, (int)lbn
));
514 dp
= (struct direct
*)
515 (dirp
->dbuf
+ blkoff(&sblock
, dirp
->loc
));
516 dirp
->loc
+= dp
->d_reclen
;
517 if (dp
->d_ino
== 0) {
525 dotname(struct direct
*dp
)
528 if (dp
->d_name
[0] == '.') {
529 if (dp
->d_name
[1] == 0 ||
530 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == 0))
537 pname(ino_t i
, int lev
)
544 if ((hp
= lookup(i
, 0)) == 0) {
545 (void) printf("???");
549 (void) printf("...");
552 pname(hp
->h_pino
, ++lev
);
553 (void) printf("/%s", &(strngtab
[hp
->h_name_index
]));
558 lookup(ino_t i
, int ef
)
562 for (hp
= &htab
[(int)i
%hsize
]; hp
->h_ino
; ) {
565 if (++hp
>= &htab
[hsize
])
571 if (++nhent
>= hsize
) {
572 (void) fprintf(stderr
, "ncheck: hsize of %ld is too small\n",
581 bread(diskaddr_t bno
, char *buf
, int cnt
)
586 if (llseek(fi
, (offset_t
)bno
* DEV_BSIZE
, 0) == -1) {
587 (void) fprintf(stderr
, "ncheck: lseek error %lld\n",
588 (offset_t
)bno
* DEV_BSIZE
);
590 for (i
= 0; i
< cnt
; i
++) {
597 got
= read((int)fi
, buf
, cnt
);
600 (void) fprintf(stderr
,
601 "ncheck: read error at block %lld (wanted %d got %d)\n",
604 for (i
= 0; i
< cnt
; i
++)
612 daddr_t ibuf
[MAXNINDIR
];
615 return (gip
->di_db
[i
]);
617 if (i
> NINDIR(&sblock
)) {
618 (void) fprintf(stderr
, "ncheck: %lu - huge directory\n", ino
);
622 bread(fsbtodb(&sblock
, gip
->di_ib
[0]), (char *)ibuf
, sizeof (ibuf
));
630 (void) fprintf(stderr
,
632 "ufs usage: ncheck [-F ufs] [generic options] [-a -i #list -s] [-o m] special\n");
638 * Extend or create the inode list;
639 * this is used to contains the list of inodes we've been
640 * asked to check using the "-i" flag and to hold the
641 * inode numbers of files which we detect as being
642 * blk|char|setuid|setgid ("-s" flag support).
643 * Preserves contents.
648 ilist_size
+= ILIST_SZ_INCR
;
649 ilist
= (struct ilist
*)realloc(ilist
,
650 (ilist_size
* sizeof (struct ilist
)));
653 perror("ncheck: not enough memory to grow ilist\n");
659 * Extend or create the string table.
660 * Preserves contents.
661 * Return non-zero for success.
664 extend_strngtab(unsigned int size
)
666 strngtab_size
+= size
;
667 strngtab
= (char *)realloc(strngtab
, strngtab_size
);
669 return ((int)strngtab
);
673 * Extend or create a table, throwing away previous
675 * Return null on failure.
678 extend_tbl(uchar_t
*tbl
, unsigned int *current_size
, unsigned int new_size
)
681 * if we've already allocated tbl,
682 * but it is too small, free it.
683 * we don't realloc because we are throwing
687 if (tbl
&& (*current_size
< new_size
)) {
693 tbl
= (uchar_t
*)malloc(new_size
);
695 return ((uchar_t
*)0);
697 *current_size
= new_size
;
699 (void) memset(tbl
, 0, new_size
);