xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/fsck.h (revision 39542a18)
17c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
37c478bd9Sstevel@tonic-gate 
47c478bd9Sstevel@tonic-gate /*
57c478bd9Sstevel@tonic-gate  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
67c478bd9Sstevel@tonic-gate  * All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
97c478bd9Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
107c478bd9Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
117c478bd9Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
127c478bd9Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
137c478bd9Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
147c478bd9Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
157c478bd9Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
167c478bd9Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
177c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
187c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
197c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
207c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
24*39542a18Sabalfour  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #ifndef	_FSCK_FSCK_H
297c478bd9Sstevel@tonic-gate #define	_FSCK_FSCK_H
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.3   */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
347c478bd9Sstevel@tonic-gate extern "C" {
357c478bd9Sstevel@tonic-gate #endif
367c478bd9Sstevel@tonic-gate 
37355d6bb5Sswilcox #include <stdio.h>
38355d6bb5Sswilcox #include <stdarg.h>
39355d6bb5Sswilcox #include <search.h>
40355d6bb5Sswilcox #include <sys/param.h>
41355d6bb5Sswilcox #include <sys/types.h>
42355d6bb5Sswilcox #include <sys/mnttab.h>
43355d6bb5Sswilcox #include <sys/vfstab.h>
44355d6bb5Sswilcox #include <sys/fs/ufs_fs.h>
45355d6bb5Sswilcox #include <sys/fs/ufs_inode.h>
46355d6bb5Sswilcox 
477c478bd9Sstevel@tonic-gate #define	MAXDUP		10	/* limit on dup blks (per inode) */
487c478bd9Sstevel@tonic-gate #define	MAXBAD		10	/* limit on bad blks (per inode) */
49355d6bb5Sswilcox #define	MAXBUFSPACE	40*1024 /* initial space to allocate to buffers */
507c478bd9Sstevel@tonic-gate #define	INOBUFSIZE	56*1024	/* size of buffer to read inodes in pass1 */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #ifndef BUFSIZ
53355d6bb5Sswilcox #define	BUFSIZ MAXPATHLEN
547c478bd9Sstevel@tonic-gate #endif
557c478bd9Sstevel@tonic-gate 
56355d6bb5Sswilcox /*
57355d6bb5Sswilcox  * Inode states in statemap[].
58355d6bb5Sswilcox  */
59355d6bb5Sswilcox #define	USTATE	0x01		/* inode not allocated */
60355d6bb5Sswilcox #define	FSTATE	0x02		/* inode is file */
61355d6bb5Sswilcox #define	DSTATE	0x04		/* inode is directory */
62355d6bb5Sswilcox #define	SSTATE	0x08		/* inode is a shadow/acl */
63355d6bb5Sswilcox #define	STMASK	0x0f		/* pick off the basic state/type */
64355d6bb5Sswilcox 
65355d6bb5Sswilcox /* flags OR'd into the above */
66355d6bb5Sswilcox #define	INZLINK  0x0010		/* inode has zero links */
67355d6bb5Sswilcox #define	INFOUND  0x0020		/* inode was found during descent */
68355d6bb5Sswilcox #define	INCLEAR  0x0040		/* inode is to be cleared */
69355d6bb5Sswilcox #define	INORPHAN 0x0080		/* inode is a known orphan (pass3 only) */
70355d6bb5Sswilcox #define	INDELAYD 0x0200		/* link count update delayed */
71355d6bb5Sswilcox #define	INMASK   0xfff0		/* pick off the modifiers */
72355d6bb5Sswilcox 
73355d6bb5Sswilcox #define	FZLINK	(FSTATE | INZLINK)
74355d6bb5Sswilcox #define	DZLINK	(DSTATE | INZLINK)
75355d6bb5Sswilcox #define	SZLINK	(SSTATE | INZLINK)
76355d6bb5Sswilcox 
77355d6bb5Sswilcox #define	DFOUND	(DSTATE | INFOUND)
78355d6bb5Sswilcox 
79355d6bb5Sswilcox #define	DCLEAR	(DSTATE | INCLEAR)
80355d6bb5Sswilcox #define	FCLEAR	(FSTATE | INCLEAR)
81355d6bb5Sswilcox #define	SCLEAR	(SSTATE | INCLEAR)
82355d6bb5Sswilcox 
83355d6bb5Sswilcox /*
84355d6bb5Sswilcox  * These tests depend on the state/type defines above not overlapping bits.
85355d6bb5Sswilcox  *
86355d6bb5Sswilcox  *     	DUNFOUND === (state == DSTATE || state == DZLINK)
87355d6bb5Sswilcox  *          INCLEAR is irrelevant to the determination of
88355d6bb5Sswilcox  *          connectedness, so it's not included in this test.
89355d6bb5Sswilcox  *
90355d6bb5Sswilcox  *     	DVALID   === (state == DSTATE || state == DZLINK || state == DFOUND)
91355d6bb5Sswilcox  */
92355d6bb5Sswilcox #define	S_IS_DUNFOUND(state)	(((state) & (DSTATE | INZLINK)) \
93355d6bb5Sswilcox 				== (state))
94355d6bb5Sswilcox #define	S_IS_DVALID(state)	(((state) & (DSTATE | INZLINK | INFOUND | \
95355d6bb5Sswilcox 				INORPHAN)) == (state))
96355d6bb5Sswilcox #define	S_IS_ZLINK(state)	(((state) & INZLINK) != 0)
97355d6bb5Sswilcox #define	INO_IS_DUNFOUND(ino)	S_IS_DUNFOUND(statemap[ino])
98355d6bb5Sswilcox #define	INO_IS_DVALID(ino)	S_IS_DVALID(statemap[ino])
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  * buffer cache structure.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate struct bufarea {
1047c478bd9Sstevel@tonic-gate 	struct bufarea	*b_next;		/* free list queue */
1057c478bd9Sstevel@tonic-gate 	struct bufarea	*b_prev;		/* free list queue */
106355d6bb5Sswilcox 	diskaddr_t	b_bno;			/* physical sector number */
1077c478bd9Sstevel@tonic-gate 	int	b_size;
1087c478bd9Sstevel@tonic-gate 	int	b_errs;
1097c478bd9Sstevel@tonic-gate 	int	b_flags;
1107c478bd9Sstevel@tonic-gate 	int	b_cnt;				/* reference cnt */
1117c478bd9Sstevel@tonic-gate 	union {
1127c478bd9Sstevel@tonic-gate 		char	*b_buf;			/* buffer space */
1137c478bd9Sstevel@tonic-gate 		daddr32_t	*b_indir;	/* indirect block */
1147c478bd9Sstevel@tonic-gate 		struct	fs *b_fs;		/* super block */
1157c478bd9Sstevel@tonic-gate 		struct	cg *b_cg;		/* cylinder group */
1167c478bd9Sstevel@tonic-gate 		struct	dinode *b_dinode;	/* inode block */
1177c478bd9Sstevel@tonic-gate 	} b_un;
1187c478bd9Sstevel@tonic-gate 	char	b_dirty;
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate #define	B_INUSE 1
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate #define	MINBUFS		5	/* minimum number of buffers required */
1247c478bd9Sstevel@tonic-gate struct bufarea bufhead;		/* head of list of other blks in filesys */
1257c478bd9Sstevel@tonic-gate struct bufarea sblk;		/* file system superblock */
126355d6bb5Sswilcox struct bufarea asblk;		/* alternate superblock */
1277c478bd9Sstevel@tonic-gate struct bufarea cgblk;		/* cylinder group blocks */
1287c478bd9Sstevel@tonic-gate struct bufarea *pbp;		/* pointer to inode data in buffer pool */
1297c478bd9Sstevel@tonic-gate struct bufarea *pdirbp;		/* pointer to directory data in buffer pool */
1307c478bd9Sstevel@tonic-gate 
131355d6bb5Sswilcox #define	sbdirty()	dirty(&sblk)
132355d6bb5Sswilcox #define	cgdirty()	dirty(&cgblk)
1337c478bd9Sstevel@tonic-gate #define	sblock		(*sblk.b_un.b_fs)
1347c478bd9Sstevel@tonic-gate #define	cgrp		(*cgblk.b_un.b_cg)
1357c478bd9Sstevel@tonic-gate 
136355d6bb5Sswilcox /*
137355d6bb5Sswilcox  * inodesc.id_fix values.  See inode.c for a description of their usage.
138355d6bb5Sswilcox  */
139355d6bb5Sswilcox enum fixstate {
140355d6bb5Sswilcox 	DONTKNOW, NOFIX, FIX, IGNORE
141355d6bb5Sswilcox };
142355d6bb5Sswilcox 
143355d6bb5Sswilcox /*
144355d6bb5Sswilcox  * Tells truncino() whether or not to attempt to update the parent
145355d6bb5Sswilcox  * directory's link count.  Also, TI_NODUP flags when we're discarding
146355d6bb5Sswilcox  * fragments that are beyond the original end of the file, and so
147355d6bb5Sswilcox  * should not be considered duplicate-claim candidates.
148355d6bb5Sswilcox  */
149355d6bb5Sswilcox #define	TI_NOPARENT	0x0001	/* leave parent's di_nlink alone */
150355d6bb5Sswilcox #define	TI_PARENT	0x0002	/* update parent's di_nlink */
151355d6bb5Sswilcox #define	TI_NODUP	0x0004	/* not a dup candidate */
152355d6bb5Sswilcox 
153355d6bb5Sswilcox /*
154355d6bb5Sswilcox  * Modes for ckinode() and ckinode_common().
155355d6bb5Sswilcox  *
156355d6bb5Sswilcox  * CKI_TRAVERSE is the common case, and requests a traditional
157355d6bb5Sswilcox  * traversal of blocks or directory entries.
158355d6bb5Sswilcox  *
159355d6bb5Sswilcox  * CKI_TRUNCATE indicates that we're truncating the file, and that any
160355d6bb5Sswilcox  * block indices beyond the end of the target length should be cleared
161355d6bb5Sswilcox  * after the callback has returned (i.e., this is a superset of
162355d6bb5Sswilcox  * CKI_TRAVERSE).  idesc->id_truncto is the first logical block number
163355d6bb5Sswilcox  * to clear.  If it is less than zero, then the traversal will be
164355d6bb5Sswilcox  * equivalent to a simple CKI_TRAVERSE.
165355d6bb5Sswilcox  */
166355d6bb5Sswilcox enum cki_action { CKI_TRAVERSE, CKI_TRUNCATE };
167355d6bb5Sswilcox 
168355d6bb5Sswilcox /*
169355d6bb5Sswilcox  * The general definition of an ino_t is an unsigned quantity.
170355d6bb5Sswilcox  * However, the on-disk version is an int32_t, which is signed.
171355d6bb5Sswilcox  * Since we really want to be able to detect wrapped-around
172355d6bb5Sswilcox  * inode numbers and such, we'll use something that's compatible
173355d6bb5Sswilcox  * with what's on disk since that's the only context that really
174355d6bb5Sswilcox  * matters.  If an int32_t is found not to be sufficiently large,
175355d6bb5Sswilcox  * this will make it much easier to change later.
176355d6bb5Sswilcox  *
177355d6bb5Sswilcox  * Note that there is one unsigned inode field in the on-disk
178355d6bb5Sswilcox  * inode, ic_oeftflag.  Since all other inode fields are signed,
179355d6bb5Sswilcox  * no legitimate inode number can be put into ic_oeftflag that
180355d6bb5Sswilcox  * would overflow into the high bit.  Essentially, it should
181355d6bb5Sswilcox  * actually be declared as int32_t just like all the others, and
182355d6bb5Sswilcox  * we're going to pretend that it was.
183355d6bb5Sswilcox  *
184355d6bb5Sswilcox  * None of the routines that we use in ufs_subr.c do anything with
185355d6bb5Sswilcox  * inode numbers.  If that changes, then great care will be needed
186355d6bb5Sswilcox  * to deal with the differences in definition of ino_t and fsck_ino_t.
187355d6bb5Sswilcox  * Lint is your friend.
188355d6bb5Sswilcox  */
189355d6bb5Sswilcox typedef int32_t		fsck_ino_t;
1907c478bd9Sstevel@tonic-gate 
191355d6bb5Sswilcox /*
192355d6bb5Sswilcox  * See the full discussion of the interactions between struct inodesc
193355d6bb5Sswilcox  * and ckinode() in inode.c
194355d6bb5Sswilcox  */
1957c478bd9Sstevel@tonic-gate struct inodesc {
1967c478bd9Sstevel@tonic-gate 	enum fixstate id_fix;	/* policy on fixing errors */
197355d6bb5Sswilcox 	int (*id_func)(struct inodesc *);
198355d6bb5Sswilcox 				/* function to be applied to blocks of inode */
199355d6bb5Sswilcox 	fsck_ino_t id_number;	/* inode number described */
200355d6bb5Sswilcox 	fsck_ino_t id_parent;	/* for DATA nodes, their parent */
201355d6bb5Sswilcox 				/* also used for extra (*id_func) parameter */
202355d6bb5Sswilcox 				/* and return values */
203355d6bb5Sswilcox 	daddr32_t id_lbn;	/* logical fragment number of current block */
204355d6bb5Sswilcox 	daddr32_t id_blkno;	/* physical fragment number being examined */
2057c478bd9Sstevel@tonic-gate 	int id_numfrags;	/* number of frags contained in block */
206355d6bb5Sswilcox 	daddr32_t id_truncto;	/* # blocks to truncate to, -1 for no trunc. */
2077c478bd9Sstevel@tonic-gate 	offset_t id_filesize;	/* for DATA nodes, the size of the directory */
208355d6bb5Sswilcox 	uint_t id_loc;		/* for DATA nodes, current location in dir */
209355d6bb5Sswilcox 	daddr32_t id_entryno;	/* for DATA nodes, current dir entry number */
210355d6bb5Sswilcox 	daddr32_t id_firsthole;	/* for DATA inode, logical block that is */
211355d6bb5Sswilcox 				/* zero but shouldn't be, -1 for no holes */
2127c478bd9Sstevel@tonic-gate 	struct direct *id_dirp;	/* for DATA nodes, ptr to current entry */
213355d6bb5Sswilcox 	caddr_t id_name;	/* for DATA nodes, name to find or enter */
2147c478bd9Sstevel@tonic-gate 	char id_type;		/* type of descriptor, DATA or ADDR */
2157c478bd9Sstevel@tonic-gate };
216355d6bb5Sswilcox 
217355d6bb5Sswilcox /* file types (0 is reserved for catching bugs) */
218355d6bb5Sswilcox #define	DATA	1	/* a directory */
219355d6bb5Sswilcox #define	ACL	2	/* an acl/shadow */
220355d6bb5Sswilcox #define	ADDR	3	/* anything but a directory or an acl/shadow */
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
223355d6bb5Sswilcox  * OR'd flags for find_dup_ref()'s mode argument
2247c478bd9Sstevel@tonic-gate  */
225355d6bb5Sswilcox #define	DB_CREATE	0x01	/* if dup record found, make one */
226355d6bb5Sswilcox #define	DB_INCR		0x02	/* increment block's reference count */
227355d6bb5Sswilcox #define	DB_DECR		0x04	/* decrement block's reference count */
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /*
230355d6bb5Sswilcox  * Cache data structures
2317c478bd9Sstevel@tonic-gate  */
232355d6bb5Sswilcox struct inoinfo {
233355d6bb5Sswilcox 	struct inoinfo	*i_nextlist;	/* next inode/acl cache entry */
234355d6bb5Sswilcox 	fsck_ino_t	i_number;	/* inode number of this entry */
235355d6bb5Sswilcox 	fsck_ino_t	i_parent;	/* inode number of parent */
236355d6bb5Sswilcox 	fsck_ino_t	i_dotdot;	/* inode number of .. */
237355d6bb5Sswilcox 	fsck_ino_t	i_extattr;	/* inode of hidden attr dir */
238355d6bb5Sswilcox 	offset_t	i_isize;	/* size of inode */
239355d6bb5Sswilcox 	size_t		i_blkssize;	/* size of block array in bytes */
240355d6bb5Sswilcox 	daddr32_t	i_blks[1];	/* actually longer */
2417c478bd9Sstevel@tonic-gate };
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate /*
244355d6bb5Sswilcox  * Inode cache
2457c478bd9Sstevel@tonic-gate  */
246355d6bb5Sswilcox struct inoinfo **inphead, **inpsort;
2477c478bd9Sstevel@tonic-gate int64_t numdirs, listmax, inplast;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate /*
250355d6bb5Sswilcox  * ACL cache
2517c478bd9Sstevel@tonic-gate  */
252355d6bb5Sswilcox struct inoinfo **aclphead, **aclpsort;
2537c478bd9Sstevel@tonic-gate int64_t numacls, aclmax, aclplast;
2547c478bd9Sstevel@tonic-gate 
255355d6bb5Sswilcox /*
256355d6bb5Sswilcox  * Tree of directories we haven't reconnected or cleared.  Any
257355d6bb5Sswilcox  * dir inode that linkup() fails on gets added, any that clri()
258355d6bb5Sswilcox  * succeeds on gets removed.  If there are any left at the end of
259355d6bb5Sswilcox  * pass four, then we have a user-forced corrupt filesystem, and
260355d6bb5Sswilcox  * need to set iscorrupt.
261355d6bb5Sswilcox  *
262355d6bb5Sswilcox  * Elements are fsck_ino_t instances (not pointers).
263355d6bb5Sswilcox  */
264355d6bb5Sswilcox void *limbo_dirs;
265355d6bb5Sswilcox 
266355d6bb5Sswilcox /*
267355d6bb5Sswilcox  * Number of directories we actually found in the filesystem,
268355d6bb5Sswilcox  * as opposed to how many the superblock claims there are.
269355d6bb5Sswilcox  */
270355d6bb5Sswilcox fsck_ino_t countdirs;
271355d6bb5Sswilcox 
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate  * shadowclients and shadowclientinfo are structures for keeping track of
2747c478bd9Sstevel@tonic-gate  * shadow inodes that exist, and which regular inodes use them (i.e. are
2757c478bd9Sstevel@tonic-gate  * their clients).
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate struct shadowclients {
279355d6bb5Sswilcox 	fsck_ino_t *client;	/* an array of inode numbers */
2807c478bd9Sstevel@tonic-gate 	int nclients; /* how many inodes in the array are in use (valid) */
2817c478bd9Sstevel@tonic-gate 	struct shadowclients *next; /* link to more client inode numbers */
2827c478bd9Sstevel@tonic-gate };
2837c478bd9Sstevel@tonic-gate struct shadowclientinfo {
284355d6bb5Sswilcox 	fsck_ino_t shadow;	/* the shadow inode that this info is for */
2857c478bd9Sstevel@tonic-gate 	int totalClients;	/* how many inodes total refer to this */
2867c478bd9Sstevel@tonic-gate 	struct shadowclients *clients; /* a linked list of wads of clients */
2877c478bd9Sstevel@tonic-gate 	struct shadowclientinfo *next; /* link to the next shadow inode */
2887c478bd9Sstevel@tonic-gate };
2897c478bd9Sstevel@tonic-gate /* global pointer to this shadow/client information */
290355d6bb5Sswilcox struct shadowclientinfo *shadowclientinfo;
291355d6bb5Sswilcox struct shadowclientinfo *attrclientinfo;
292355d6bb5Sswilcox 
293355d6bb5Sswilcox /*
294355d6bb5Sswilcox  * In ufs_inode.h ifdef _KERNEL, this is defined as `/@/'.  However,
295355d6bb5Sswilcox  * to avoid all sorts of potential confusion (you can't actually use
296355d6bb5Sswilcox  * `foo/@/bar' to get to an attribute), we use something that doesn't
297355d6bb5Sswilcox  * look quite so much like a simple pathname.
298355d6bb5Sswilcox  */
299355d6bb5Sswilcox #define	XATTR_DIR_NAME	" <xattr> "
300355d6bb5Sswilcox 
301355d6bb5Sswilcox /*
302355d6bb5Sswilcox  * granularity -- how many client inodes do we make space for at a time
303355d6bb5Sswilcox  * initialized in setup.c;
304355d6bb5Sswilcox  */
3057c478bd9Sstevel@tonic-gate extern int maxshadowclients;
3067c478bd9Sstevel@tonic-gate 
307355d6bb5Sswilcox /*
308355d6bb5Sswilcox  * Initialized global variables.
309355d6bb5Sswilcox  */
310355d6bb5Sswilcox extern caddr_t lfname;
311355d6bb5Sswilcox 
312355d6bb5Sswilcox /*
313355d6bb5Sswilcox  * Unitialized globals.
314355d6bb5Sswilcox  */
3157c478bd9Sstevel@tonic-gate char	*devname;		/* name of device being checked */
316355d6bb5Sswilcox size_t	dev_bsize;		/* computed value of DEV_BSIZE */
3177c478bd9Sstevel@tonic-gate int	secsize;		/* actual disk sector size */
3187c478bd9Sstevel@tonic-gate char	nflag;			/* assume a no response */
3197c478bd9Sstevel@tonic-gate char	yflag;			/* assume a yes response */
320355d6bb5Sswilcox daddr32_t	bflag;		/* location of alternate super block */
3217c478bd9Sstevel@tonic-gate int	debug;			/* output debugging info */
3227c478bd9Sstevel@tonic-gate int	rflag;			/* check raw file systems */
323355d6bb5Sswilcox int	roflag;			/* do normal checks but don't update disk */
3247c478bd9Sstevel@tonic-gate int	fflag;			/* check regardless of clean flag (force) */
325355d6bb5Sswilcox int	mflag;			/* sanity check only */
326355d6bb5Sswilcox int	verbose;		/* be chatty */
3277c478bd9Sstevel@tonic-gate char	preen;			/* just fix normal inconsistencies */
3287c478bd9Sstevel@tonic-gate char	mountedfs;		/* checking mounted device */
329355d6bb5Sswilcox int	exitstat;		/* exit status (see EX* defines below) */
3307c478bd9Sstevel@tonic-gate char	hotroot;		/* checking root device */
331355d6bb5Sswilcox char	rerun;			/* rerun fsck. Only used in non-preen mode */
332355d6bb5Sswilcox int	interrupted;		/* 1 => exit EXSIGNAL on exit */
3337c478bd9Sstevel@tonic-gate char	havesb;			/* superblock has been read */
3347c478bd9Sstevel@tonic-gate int	fsmodified;		/* 1 => write done to file system */
3357c478bd9Sstevel@tonic-gate int	fsreadfd;		/* file descriptor for reading file system */
3367c478bd9Sstevel@tonic-gate int	fswritefd;		/* file descriptor for writing file system */
3377c478bd9Sstevel@tonic-gate int	iscorrupt;		/* known to be corrupt/inconsistent */
338355d6bb5Sswilcox 				/* -1 means mark clean so user can mount+fix */
3397c478bd9Sstevel@tonic-gate int	isdirty;		/* 1 => write pending to file system */
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate int	islog;			/* logging file system */
3427c478bd9Sstevel@tonic-gate int	islogok;		/* log is okay */
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate int	errorlocked;		/* set => mounted fs has been error-locked */
3457c478bd9Sstevel@tonic-gate 				/* implies fflag "force check flag" */
3467c478bd9Sstevel@tonic-gate char	*elock_combuf;		/* error lock comment buffer */
3477c478bd9Sstevel@tonic-gate char	*elock_mountp;		/* mount point; used to unlock error-lock */
3487c478bd9Sstevel@tonic-gate int	pid;			/* fsck's process id (put in lockfs comment) */
3497c478bd9Sstevel@tonic-gate int	mountfd;		/* fd of mount point */
3507c478bd9Sstevel@tonic-gate struct lockfs	*lfp;		/* current lockfs status */
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate daddr32_t	maxfsblock;	/* number of blocks in the file system */
353355d6bb5Sswilcox uint_t	largefile_count;	/* global largefile counter */
354355d6bb5Sswilcox char	*mount_point;		/* if mounted, this is where */
3557c478bd9Sstevel@tonic-gate char	*blockmap;		/* ptr to primary blk allocation map */
356355d6bb5Sswilcox fsck_ino_t	maxino;		/* number of inodes in file system */
357355d6bb5Sswilcox fsck_ino_t	lastino;	/* last inode in use */
358355d6bb5Sswilcox ushort_t *statemap;		/* ptr to inode state table */
3597c478bd9Sstevel@tonic-gate short	*lncntp;		/* ptr to link count table */
3607c478bd9Sstevel@tonic-gate 
361355d6bb5Sswilcox fsck_ino_t	lfdir;		/* lost & found directory inode number */
362355d6bb5Sswilcox int		overflowed_lf;	/* tried to wrap lost & found's link count */
363355d6bb5Sswilcox int		reattached_dir;	/* reconnected at least one directory */
364355d6bb5Sswilcox int		broke_dir_link;	/* broke at least one directory hardlink */
3657c478bd9Sstevel@tonic-gate 
366355d6bb5Sswilcox daddr32_t	n_blks;		/* number of blocks in use */
367355d6bb5Sswilcox fsck_ino_t	n_files;	/* number of files in use */
3687c478bd9Sstevel@tonic-gate 
369355d6bb5Sswilcox #define	clearinode(dp)	{ \
370355d6bb5Sswilcox 	*(dp) = zino; \
371355d6bb5Sswilcox }
3727c478bd9Sstevel@tonic-gate struct	dinode zino;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate #define	testbmap(blkno)	isset(blockmap, blkno)
375355d6bb5Sswilcox #define	setbmap(blkno)	setbit(blockmap, blkno)
3767c478bd9Sstevel@tonic-gate #define	clrbmap(blkno)	clrbit(blockmap, blkno)
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate #define	STOP	0x01
3797c478bd9Sstevel@tonic-gate #define	SKIP	0x02
3807c478bd9Sstevel@tonic-gate #define	KEEPON	0x04
3817c478bd9Sstevel@tonic-gate #define	ALTERED	0x08
3827c478bd9Sstevel@tonic-gate #define	FOUND	0x10
3837c478bd9Sstevel@tonic-gate 
384355d6bb5Sswilcox /*
385355d6bb5Sswilcox  * Support relatively easy debugging of lncntp[] updates.  This can't
386355d6bb5Sswilcox  * be a function, because of the (_op) step.  Normally, we just do that.
387355d6bb5Sswilcox  */
388355d6bb5Sswilcox #define	TRACK_LNCNTP(_ino, _op) (_op)
389355d6bb5Sswilcox 
390355d6bb5Sswilcox /*
391355d6bb5Sswilcox  * See if the net link count for an inode has gone outside
392355d6bb5Sswilcox  * what can be represented on disk.  Returning text as NULL
393355d6bb5Sswilcox  * indicates no.
394355d6bb5Sswilcox  *
395355d6bb5Sswilcox  * Remember that link counts are effectively inverted, so
396355d6bb5Sswilcox  * underflow and overflow are reversed as well.
397355d6bb5Sswilcox  *
398355d6bb5Sswilcox  * This check should be done before modifying the actual link
399355d6bb5Sswilcox  * count.
400355d6bb5Sswilcox  */
401355d6bb5Sswilcox #define	LINK_RANGE(text, current, offset) { \
402355d6bb5Sswilcox 	int net = ((int)(current)) + ((int)(offset)); \
403355d6bb5Sswilcox 	text = NULL; \
404355d6bb5Sswilcox 	if (net > (MAXLINK)) \
405355d6bb5Sswilcox 		text = "UNDERFLOW"; \
406355d6bb5Sswilcox 	else if (net < -(MAXLINK)) \
407355d6bb5Sswilcox 		text = "OVERFLOW"; \
408355d6bb5Sswilcox }
4097c478bd9Sstevel@tonic-gate 
410355d6bb5Sswilcox /*
411355d6bb5Sswilcox  * If LINK_RANGE() indicated a problem, this is the boiler-plate
412355d6bb5Sswilcox  * for dealing with it.  Usage is:
413355d6bb5Sswilcox  *
414355d6bb5Sswilcox  *     LINK_RANGE(text, current, offset);
415355d6bb5Sswilcox  *     if (text != NULL) {
416355d6bb5Sswilcox  *         LINK_CLEAR(text, ino, mode, idp);
417355d6bb5Sswilcox  *         if (statemap[ino] == USTATE)
418355d6bb5Sswilcox  *             ...inode was cleared...
419355d6bb5Sswilcox  *     }
420355d6bb5Sswilcox  *
421355d6bb5Sswilcox  * Note that clri() will set iscorrupt if the user elects not to
422355d6bb5Sswilcox  * clear the problem inode, so the filesystem won't get reported
423355d6bb5Sswilcox  * as clean when it shouldn't be.
424355d6bb5Sswilcox  */
425355d6bb5Sswilcox #define	LINK_CLEAR(text, ino, mode, idp) { \
426355d6bb5Sswilcox 	pwarn("%s LINK COUNT %s", file_id((ino), (mode)), (text)); \
427355d6bb5Sswilcox 	pinode((ino)); \
428355d6bb5Sswilcox 	pfatal(""); \
429355d6bb5Sswilcox 	init_inodesc((idp)); \
430355d6bb5Sswilcox 	(idp)->id_type = ADDR; \
431355d6bb5Sswilcox 	(idp)->id_func = pass4check; \
432355d6bb5Sswilcox 	(idp)->id_number = ino; \
433355d6bb5Sswilcox 	(idp)->id_fix = DONTKNOW; \
434355d6bb5Sswilcox 	clri((idp), (text), CLRI_QUIET, CLRI_NOP_CORRUPT); \
435355d6bb5Sswilcox }
436355d6bb5Sswilcox 
437355d6bb5Sswilcox /*
438355d6bb5Sswilcox  * Used for checking link count under/overflow specifically on
439355d6bb5Sswilcox  * the lost+found directory.  If the user decides not to do the
440355d6bb5Sswilcox  * clri(), then flag that we've hit this problem and refuse to do
441355d6bb5Sswilcox  * the reconnect.
442355d6bb5Sswilcox  */
443355d6bb5Sswilcox #define	LFDIR_LINK_RANGE_RVAL(text, current, offset, idp, rval) { \
444355d6bb5Sswilcox 	LINK_RANGE(text, current, offset); \
445355d6bb5Sswilcox 	if (text != NULL) { \
446355d6bb5Sswilcox 		LINK_CLEAR(text, lfdir, IFDIR, idp); \
447355d6bb5Sswilcox 		if (statemap[lfdir] == USTATE) { \
448355d6bb5Sswilcox 			lfdir = 0; \
449355d6bb5Sswilcox 			return (rval); \
450355d6bb5Sswilcox 		} else { \
451355d6bb5Sswilcox 			overflowed_lf++; \
452355d6bb5Sswilcox 		} \
453355d6bb5Sswilcox 	} \
454355d6bb5Sswilcox }
455355d6bb5Sswilcox 
456355d6bb5Sswilcox #define	LFDIR_LINK_RANGE_NORVAL(text, current, offset, idp) { \
457355d6bb5Sswilcox 	LINK_RANGE(text, current, offset); \
458355d6bb5Sswilcox 	if (text != NULL) { \
459355d6bb5Sswilcox 		LINK_CLEAR(text, lfdir, IFDIR, idp); \
460355d6bb5Sswilcox 		if (statemap[lfdir] == USTATE) { \
461355d6bb5Sswilcox 			lfdir = 0; \
462355d6bb5Sswilcox 			return; \
463355d6bb5Sswilcox 		} else { \
464355d6bb5Sswilcox 			overflowed_lf++; \
465355d6bb5Sswilcox 		} \
466355d6bb5Sswilcox 	} \
467355d6bb5Sswilcox }
468355d6bb5Sswilcox 
469355d6bb5Sswilcox /*
470355d6bb5Sswilcox  * Values for mounted() and mountedfs.
471355d6bb5Sswilcox  */
472355d6bb5Sswilcox #define	M_NOMNT		0	/* filesystem is not mounted */
473355d6bb5Sswilcox #define	M_RO		1	/* filesystem is mounted read-only */
474355d6bb5Sswilcox #define	M_RW		2	/* filesystem is mounted read-write */
475355d6bb5Sswilcox 
476355d6bb5Sswilcox #define	EXOKAY		0	/* file system is unmounted and ok */
477355d6bb5Sswilcox #define	EXBADPARM	1	/* bad parameter(s) given */
478355d6bb5Sswilcox #define	EXUMNTCHK	32	/* fsck -m: unmounted, needs checking */
479355d6bb5Sswilcox #define	EXMOUNTED	33	/* file system already mounted, not magic, */
480355d6bb5Sswilcox 				/* or it is magic and mounted read/write */
481355d6bb5Sswilcox #define	EXNOSTAT	34	/* cannot stat device */
482355d6bb5Sswilcox #define	EXREBOOTNOW	35	/* modified root or something equally scary */
483355d6bb5Sswilcox #define	EXFNDERRS	36	/* uncorrectable errors, terminate normally */
484355d6bb5Sswilcox #define	EXSIGNAL	37	/* a signal was caught during processing */
485355d6bb5Sswilcox #define	EXERRFATAL	39	/* uncorrectable errors, exit immediately */
486355d6bb5Sswilcox #define	EXROOTOKAY	40	/* for root, same as 0 */
487355d6bb5Sswilcox 
488355d6bb5Sswilcox /*
489355d6bb5Sswilcox  * Values for clri()'s `verbose' and `corrupting' arguments (third
490