xref: /minix3/minix/commands/fsck.mfs/fsck.c (revision d0055759dd8892194db7fce6acc5085d5c9aeaee)
1433d6423SLionel Sambuc /* Hacks for version 1.6 */
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #define INODES_PER_BLOCK V2_INODES_PER_BLOCK(block_size)
4433d6423SLionel Sambuc #define INODE_SIZE ((int) V2_INODE_SIZE)
5433d6423SLionel Sambuc #define WORDS_PER_BLOCK (block_size / (int) sizeof(bitchunk_t))
6433d6423SLionel Sambuc #define MAX_ZONES (V2_NR_DZONES+V2_INDIRECTS(block_size)+(long)V2_INDIRECTS(block_size)*V2_INDIRECTS(block_size))
7433d6423SLionel Sambuc #define NR_DZONE_NUM V2_NR_DZONES
8433d6423SLionel Sambuc #define NR_INDIRECTS V2_INDIRECTS(block_size)
9433d6423SLionel Sambuc #define NR_ZONE_NUMS V2_NR_TZONES
10433d6423SLionel Sambuc #define ZONE_NUM_SIZE V2_ZONE_NUM_SIZE
11433d6423SLionel Sambuc #define bit_nr bit_t
12433d6423SLionel Sambuc #define block_nr block_t
13433d6423SLionel Sambuc #define d_inode d2_inode
14433d6423SLionel Sambuc #define d_inum mfs_d_ino
15433d6423SLionel Sambuc #define dir_struct struct direct
16433d6423SLionel Sambuc #define i_mode d2_mode
17433d6423SLionel Sambuc #define i_nlinks d2_nlinks
18433d6423SLionel Sambuc #define i_size d2_size
19433d6423SLionel Sambuc #define i_zone d2_zone
20433d6423SLionel Sambuc #define zone_nr zone_t
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc /* fsck - file system checker		Author: Robbert van Renesse */
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc /* Modified by Norbert Schlenker
25433d6423SLionel Sambuc *   Removed vestiges of standalone/DOS versions:
26433d6423SLionel Sambuc *     - various unused variables and buffers removed
27433d6423SLionel Sambuc *     - now uses library functions rather than private internal routines
28433d6423SLionel Sambuc *     - bytewise structure copies replaced by structure assignment
29433d6423SLionel Sambuc *     - fixed one bug with 14 character file names
30433d6423SLionel Sambuc *     - other small tweaks for speed
31433d6423SLionel Sambuc *
32433d6423SLionel Sambuc * Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
33433d6423SLionel Sambuc *   Removed -m option, by which fsck could be told to make a file
34433d6423SLionel Sambuc *   system on a 360K floppy.  The code had limited utility, was buggy,
35433d6423SLionel Sambuc *   and failed due to a bug in the ACK C compiler.  Use mkfs instead!
36433d6423SLionel Sambuc */
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc #include <sys/types.h>
39433d6423SLionel Sambuc #include <ctype.h>
40433d6423SLionel Sambuc #include <errno.h>
41433d6423SLionel Sambuc #include <fcntl.h>
42433d6423SLionel Sambuc #include <limits.h>
43433d6423SLionel Sambuc #include <stdlib.h>
44433d6423SLionel Sambuc #include <string.h>
45433d6423SLionel Sambuc #include <unistd.h>
46433d6423SLionel Sambuc #include <minix/config.h>
47433d6423SLionel Sambuc #include <minix/const.h>
48433d6423SLionel Sambuc #include <minix/type.h>
49ccaeedb2SDavid van Moolenbroek #include <minix/ipc.h>
50433d6423SLionel Sambuc #include "mfs/const.h"
51433d6423SLionel Sambuc #include "mfs/inode.h"
52433d6423SLionel Sambuc #include "mfs/type.h"
53433d6423SLionel Sambuc #include "mfs/mfsdir.h"
54433d6423SLionel Sambuc #include <minix/fslib.h>
55433d6423SLionel Sambuc #include <stdio.h>
56433d6423SLionel Sambuc #include <sys/stat.h>
57433d6423SLionel Sambuc #include <dirent.h>
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc #include "exitvalues.h"
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc #undef N_DATA
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc unsigned int fs_version = 2, block_size = 0;
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc #define BITSHIFT	  5	/* = log2(#bits(int)) */
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc #define MAXPRINT	  80	/* max. number of error lines in chkmap */
68433d6423SLionel Sambuc #define CINDIR		128	/* number of indirect zno's read at a time */
69433d6423SLionel Sambuc #define CDIRECT		  1	/* number of dir entries read at a time */
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc /* Macros for handling bitmaps.  Now bit_t is long, these are bulky and the
72433d6423SLionel Sambuc  * type demotions produce a lot of lint.  The explicit demotion in POWEROFBIT
73433d6423SLionel Sambuc  * is for efficiency and assumes 2's complement ints.  Lint should be clever
74433d6423SLionel Sambuc  * enough not to warn about it since BITMASK is small, but isn't.  (It would
75433d6423SLionel Sambuc  * be easier to get right if bit_t was was unsigned (long) since then there
76433d6423SLionel Sambuc  * would be no danger from wierd sign representations.  Lint doesn't know
77433d6423SLionel Sambuc  * we only use non-negative bit numbers.) There will usually be an implicit
78433d6423SLionel Sambuc  * demotion when WORDOFBIT is used as an array index.  This should be safe
79433d6423SLionel Sambuc  * since memory for bitmaps will run out first.
80433d6423SLionel Sambuc  */
81433d6423SLionel Sambuc #define BITMASK		((1 << BITSHIFT) - 1)
82433d6423SLionel Sambuc #define WORDOFBIT(b)	((b) >> BITSHIFT)
83433d6423SLionel Sambuc #define POWEROFBIT(b)	(1 << ((int) (b) & BITMASK))
84433d6423SLionel Sambuc #define setbit(w, b)	(w[WORDOFBIT(b)] |= POWEROFBIT(b))
85433d6423SLionel Sambuc #define clrbit(w, b)	(w[WORDOFBIT(b)] &= ~POWEROFBIT(b))
86433d6423SLionel Sambuc #define bitset(w, b)	(w[WORDOFBIT(b)] & POWEROFBIT(b))
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc #define ZONE_CT 	360	/* default zones  (when making file system) */
89433d6423SLionel Sambuc #define INODE_CT	 95	/* default inodes (when making file system) */
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc #include "mfs/super.h"
92433d6423SLionel Sambuc static struct super_block sb;
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc #define STICKY_BIT	01000	/* not defined anywhere else */
95433d6423SLionel Sambuc 
96433d6423SLionel Sambuc /* Ztob gives the block address of a zone
97433d6423SLionel Sambuc  * btoa64 gives the byte address of a block
98433d6423SLionel Sambuc  */
99433d6423SLionel Sambuc #define ztob(z)		((block_nr) (z) << sb.s_log_zone_size)
100433d6423SLionel Sambuc #define btoa64(b)	((u64_t)(b) * block_size)
101433d6423SLionel Sambuc #define SCALE		((int) ztob(1))	/* # blocks in a zone */
102433d6423SLionel Sambuc #define FIRST		((zone_nr) sb.s_firstdatazone)	/* as the name says */
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc /* # blocks of each type */
105433d6423SLionel Sambuc #define N_IMAP		(sb.s_imap_blocks)
106433d6423SLionel Sambuc #define N_ZMAP		(sb.s_zmap_blocks)
107433d6423SLionel Sambuc #define N_ILIST		((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
108433d6423SLionel Sambuc #define N_DATA		(sb.s_zones - FIRST)
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc /* Block address of each type */
111433d6423SLionel Sambuc #define OFFSET_SUPER_BLOCK	SUPER_BLOCK_BYTES
112433d6423SLionel Sambuc #define BLK_IMAP	2
113433d6423SLionel Sambuc #define BLK_ZMAP	(BLK_IMAP  + N_IMAP)
114433d6423SLionel Sambuc #define BLK_ILIST	(BLK_ZMAP  + N_ZMAP)
115433d6423SLionel Sambuc #define BLK_FIRST	ztob(FIRST)
116433d6423SLionel Sambuc #define ZONE_SIZE	((int) ztob(block_size))
117433d6423SLionel Sambuc #define NLEVEL		(NR_ZONE_NUMS - NR_DZONE_NUM + 1)
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc /* Byte address of a zone */
120433d6423SLionel Sambuc #define INDCHUNK	((int) (CINDIR * ZONE_NUM_SIZE))
121433d6423SLionel Sambuc #define DIRCHUNK	((int) (CDIRECT * DIR_ENTRY_SIZE))
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc char *prog, *fsck_device;		/* program name (fsck), device name */
124433d6423SLionel Sambuc int firstcnterr;		/* is this the first inode ref cnt error? */
125433d6423SLionel Sambuc bitchunk_t *imap, *spec_imap;	/* inode bit maps */
126433d6423SLionel Sambuc bitchunk_t *zmap, *spec_zmap;	/* zone bit maps */
127433d6423SLionel Sambuc bitchunk_t *dirmap;		/* directory (inode) bit map */
128433d6423SLionel Sambuc char *rwbuf;			/* one block buffer cache */
129433d6423SLionel Sambuc block_nr thisblk;		/* block in buffer cache */
130433d6423SLionel Sambuc char *nullbuf;	/* null buffer */
131433d6423SLionel Sambuc nlink_t *count;			/* inode count */
132433d6423SLionel Sambuc int changed;			/* has the diskette been written to? */
133433d6423SLionel Sambuc struct stack {
134433d6423SLionel Sambuc   dir_struct *st_dir;
135433d6423SLionel Sambuc   struct stack *st_next;
136433d6423SLionel Sambuc   char st_presence;
137433d6423SLionel Sambuc } *ftop;
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc int dev;			/* file descriptor of the device */
140433d6423SLionel Sambuc 
141433d6423SLionel Sambuc #define DOT	1
142433d6423SLionel Sambuc #define DOTDOT	2
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc /* Counters for each type of inode/zone. */
145433d6423SLionel Sambuc int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
146433d6423SLionel Sambuc int nsock, npipe, nsyml, ztype[NLEVEL];
147433d6423SLionel Sambuc long nfreezone;
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc int repair, notrepaired = 0, automatic, listing, listsuper;	/* flags */
150433d6423SLionel Sambuc int preen = 0, markdirty = 0;
151433d6423SLionel Sambuc int firstlist;			/* has the listing header been printed? */
152433d6423SLionel Sambuc unsigned part_offset;		/* sector offset for this partition */
153433d6423SLionel Sambuc char answer[] = "Answer questions with y or n.  Then hit RETURN";
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc int main(int argc, char **argv);
156433d6423SLionel Sambuc void initvars(void);
157433d6423SLionel Sambuc void fatal(char *s);
158433d6423SLionel Sambuc int eoln(int c);
159433d6423SLionel Sambuc int yes(char *question);
160433d6423SLionel Sambuc int atoo(char *s);
161433d6423SLionel Sambuc int input(char *buf, int size);
162433d6423SLionel Sambuc char *alloc(unsigned nelem, unsigned elsize);
163433d6423SLionel Sambuc void printname(char *s);
164433d6423SLionel Sambuc void printrec(struct stack *sp);
165433d6423SLionel Sambuc void printpath(int mode, int nlcr);
166433d6423SLionel Sambuc void devopen(void);
167433d6423SLionel Sambuc void devclose(void);
168433d6423SLionel Sambuc void devio(block_nr bno, int dir);
169433d6423SLionel Sambuc void devread(long block, long offset, char *buf, int size);
170433d6423SLionel Sambuc void devwrite(long block, long offset, char *buf, int size);
171433d6423SLionel Sambuc void pr(char *fmt, int cnt, char *s, char *p);
172433d6423SLionel Sambuc void lpr(char *fmt, long cnt, char *s, char *p);
173433d6423SLionel Sambuc bit_nr getnumber(char *s);
174433d6423SLionel Sambuc char **getlist(char ***argv, char *type);
175433d6423SLionel Sambuc void lsuper(void);
176433d6423SLionel Sambuc #define SUPER_GET	0
177433d6423SLionel Sambuc #define SUPER_PUT	1
178433d6423SLionel Sambuc void rw_super(int mode);
179433d6423SLionel Sambuc void chksuper(void);
180433d6423SLionel Sambuc void lsi(char **clist);
181433d6423SLionel Sambuc bitchunk_t *allocbitmap(int nblk);
182433d6423SLionel Sambuc void loadbitmap(bitchunk_t *bitmap, block_nr bno, int nblk);
183433d6423SLionel Sambuc void dumpbitmap(bitchunk_t *bitmap, block_nr bno, int nblk);
184433d6423SLionel Sambuc void fillbitmap(bitchunk_t *bitmap, bit_nr lwb, bit_nr upb, char
185433d6423SLionel Sambuc 	**list);
186433d6423SLionel Sambuc void freebitmap(bitchunk_t *p);
187433d6423SLionel Sambuc void getbitmaps(void);
188433d6423SLionel Sambuc void putbitmaps(void);
189433d6423SLionel Sambuc void chkword(unsigned w1, unsigned w2, bit_nr bit, char *type, int *n,
190433d6423SLionel Sambuc 	int *report, bit_t);
191433d6423SLionel Sambuc void chkmap(bitchunk_t *cmap, bitchunk_t *dmap, bit_nr bit, block_nr
192433d6423SLionel Sambuc 	blkno, int nblk, char *type);
193433d6423SLionel Sambuc void chkilist(void);
194433d6423SLionel Sambuc void getcount(void);
195433d6423SLionel Sambuc void counterror(ino_t ino);
196433d6423SLionel Sambuc void chkcount(void);
197433d6423SLionel Sambuc void freecount(void);
198433d6423SLionel Sambuc void printperm(mode_t mode, int shift, int special, int overlay);
199433d6423SLionel Sambuc void list(ino_t ino, d_inode *ip);
200433d6423SLionel Sambuc int Remove(dir_struct *dp);
201433d6423SLionel Sambuc void make_printable_name(char *dst, char *src, int n);
202433d6423SLionel Sambuc int chkdots(ino_t ino, off_t pos, dir_struct *dp, ino_t exp);
203433d6423SLionel Sambuc int chkname(ino_t ino, dir_struct *dp);
204433d6423SLionel Sambuc int chkentry(ino_t ino, off_t pos, dir_struct *dp);
205433d6423SLionel Sambuc int chkdirzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno);
206433d6423SLionel Sambuc int chksymlinkzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno);
207433d6423SLionel Sambuc void errzone(char *mess, zone_nr zno, int level, off_t pos);
208433d6423SLionel Sambuc int markzone(zone_nr zno, int level, off_t pos);
209433d6423SLionel Sambuc int chkindzone(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int
210433d6423SLionel Sambuc 	level);
211433d6423SLionel Sambuc off_t jump(int level);
212433d6423SLionel Sambuc int zonechk(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level);
213433d6423SLionel Sambuc int chkzones(ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist, int
214433d6423SLionel Sambuc 	len, int level);
215433d6423SLionel Sambuc int chkfile(ino_t ino, d_inode *ip);
216433d6423SLionel Sambuc int chkdirectory(ino_t ino, d_inode *ip);
217433d6423SLionel Sambuc int chklink(ino_t ino, d_inode *ip);
218433d6423SLionel Sambuc int chkspecial(ino_t ino, d_inode *ip);
219433d6423SLionel Sambuc int chkmode(ino_t ino, d_inode *ip);
220433d6423SLionel Sambuc int chkinode(ino_t ino, d_inode *ip);
221433d6423SLionel Sambuc int descendtree(dir_struct *dp);
222433d6423SLionel Sambuc void chktree(void);
223433d6423SLionel Sambuc void printtotal(void);
224433d6423SLionel Sambuc void chkdev(char *f, char **clist, char **ilist, char **zlist);
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc /* Initialize the variables used by this program. */
initvars()227433d6423SLionel Sambuc void initvars()
228433d6423SLionel Sambuc {
229433d6423SLionel Sambuc   register int level;
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc   nregular = ndirectory = nblkspec = ncharspec =
232433d6423SLionel Sambuc   nbadinode = nsock = npipe = nsyml = 0;
233433d6423SLionel Sambuc   for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
234433d6423SLionel Sambuc   changed = 0;
235433d6423SLionel Sambuc   thisblk = NO_BLOCK;
236433d6423SLionel Sambuc   firstlist = 1;
237433d6423SLionel Sambuc   firstcnterr = 1;
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc /* Print the string `s' and exit. */
fatal(s)241433d6423SLionel Sambuc void fatal(s)
242433d6423SLionel Sambuc char *s;
243433d6423SLionel Sambuc {
244433d6423SLionel Sambuc   printf("%s\nfatal\n", s);
245433d6423SLionel Sambuc   exit(FSCK_EXIT_CHECK_FAILED);
246433d6423SLionel Sambuc }
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc /* Test for end of line. */
eoln(c)249433d6423SLionel Sambuc int eoln(c)
250433d6423SLionel Sambuc int c;
251433d6423SLionel Sambuc {
252433d6423SLionel Sambuc   return(c == EOF || c == '\n' || c == '\r');
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc 
255433d6423SLionel Sambuc /* Ask a question and get the answer unless automatic is set. */
yes(question)256433d6423SLionel Sambuc int yes(question)
257433d6423SLionel Sambuc char *question;
258433d6423SLionel Sambuc {
259433d6423SLionel Sambuc   register int c, answerchar;
260433d6423SLionel Sambuc   static int note = 0;
261433d6423SLionel Sambuc   int yes;
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc   if (!repair) {
264433d6423SLionel Sambuc 	printf("\n");
265433d6423SLionel Sambuc 	return(0);
266433d6423SLionel Sambuc   }
267433d6423SLionel Sambuc   printf("%s? ", question);
268433d6423SLionel Sambuc   if(!note) { printf("(y=yes, n=no, q=quit, A=for yes to all) "); note = 1; }
269433d6423SLionel Sambuc   if (automatic) {
270433d6423SLionel Sambuc 	printf("yes\n");
271433d6423SLionel Sambuc 	return(1);
272433d6423SLionel Sambuc   }
273433d6423SLionel Sambuc   fflush(stdout);
274433d6423SLionel Sambuc   if ((c = answerchar = getchar()) == 'q' || c == 'Q') exit(FSCK_EXIT_CHECK_FAILED);
275433d6423SLionel Sambuc   if(c == 'A') { automatic = 1; c = 'y'; }
276433d6423SLionel Sambuc   while (!eoln(c)) c = getchar();
277433d6423SLionel Sambuc   yes = !(answerchar == 'n' || answerchar == 'N');
278433d6423SLionel Sambuc   if(!yes) notrepaired = 1;
279433d6423SLionel Sambuc   return yes;
280433d6423SLionel Sambuc }
281433d6423SLionel Sambuc 
282433d6423SLionel Sambuc /* Convert string to integer.  Representation is octal. */
atoo(s)283433d6423SLionel Sambuc int atoo(s)
284433d6423SLionel Sambuc register char *s;
285433d6423SLionel Sambuc {
286433d6423SLionel Sambuc   register int n = 0;
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc   while ('0' <= *s && *s < '8') {
289433d6423SLionel Sambuc 	n <<= 3;
290433d6423SLionel Sambuc 	n += *s++ - '0';
291433d6423SLionel Sambuc   }
292433d6423SLionel Sambuc   return n;
293433d6423SLionel Sambuc }
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc /* If repairing the file system, print a prompt and get a string from user. */
input(buf,size)296433d6423SLionel Sambuc int input(buf, size)
297433d6423SLionel Sambuc char *buf;
298433d6423SLionel Sambuc int size;
299433d6423SLionel Sambuc {
300433d6423SLionel Sambuc   register char *p = buf;
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc   printf("\n");
303433d6423SLionel Sambuc   if (repair) {
304433d6423SLionel Sambuc 	printf("--> ");
305433d6423SLionel Sambuc 	fflush(stdout);
306433d6423SLionel Sambuc 	while (--size) {
307433d6423SLionel Sambuc 		*p = getchar();
308433d6423SLionel Sambuc 		if (eoln(*p)) {
309433d6423SLionel Sambuc 			*p = 0;
310433d6423SLionel Sambuc 			return(p > buf);
311433d6423SLionel Sambuc 		}
312433d6423SLionel Sambuc 		p++;
313433d6423SLionel Sambuc 	}
314433d6423SLionel Sambuc 	*p = 0;
315433d6423SLionel Sambuc 	while (!eoln(getchar()));
316433d6423SLionel Sambuc 	return(1);
317433d6423SLionel Sambuc   }
318433d6423SLionel Sambuc   return(0);
319433d6423SLionel Sambuc }
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc /* Allocate some memory and zero it. */
alloc(nelem,elsize)322433d6423SLionel Sambuc char *alloc(nelem, elsize)
323433d6423SLionel Sambuc unsigned nelem, elsize;
324433d6423SLionel Sambuc {
325433d6423SLionel Sambuc   char *p;
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc   if ((p = (char *)malloc((size_t)nelem * elsize)) == 0) {
328433d6423SLionel Sambuc   	fprintf(stderr, "Tried to allocate %dkB\n",
329433d6423SLionel Sambuc   		nelem*elsize/1024);
330433d6423SLionel Sambuc   	fatal("out of memory");
331433d6423SLionel Sambuc   }
332433d6423SLionel Sambuc   memset((void *) p, 0, (size_t)nelem * elsize);
333433d6423SLionel Sambuc   return(p);
334433d6423SLionel Sambuc }
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc /* Print the name in a directory entry. */
printname(s)337433d6423SLionel Sambuc void printname(s)
338433d6423SLionel Sambuc char *s;
339433d6423SLionel Sambuc {
340433d6423SLionel Sambuc   register int n = MFS_NAME_MAX;
341433d6423SLionel Sambuc   int c;
342433d6423SLionel Sambuc 
343433d6423SLionel Sambuc   do {
344433d6423SLionel Sambuc 	if ((c = *s) == 0) break;
345433d6423SLionel Sambuc 	if (!isprint(c)) c = '?';
346433d6423SLionel Sambuc 	putchar(c);
347433d6423SLionel Sambuc 	s++;
348433d6423SLionel Sambuc   } while (--n);
349433d6423SLionel Sambuc }
350433d6423SLionel Sambuc 
351433d6423SLionel Sambuc /* Print the pathname given by a linked list pointed to by `sp'.  The
352433d6423SLionel Sambuc  * names are in reverse order.
353433d6423SLionel Sambuc  */
printrec(struct stack * sp)354433d6423SLionel Sambuc void printrec(struct stack *sp)
355433d6423SLionel Sambuc {
356433d6423SLionel Sambuc   if (sp->st_next != 0) {
357433d6423SLionel Sambuc 	printrec(sp->st_next);
358433d6423SLionel Sambuc 	putchar('/');
359433d6423SLionel Sambuc 	printname(sp->st_dir->mfs_d_name);
360433d6423SLionel Sambuc   }
361433d6423SLionel Sambuc }
362433d6423SLionel Sambuc 
363433d6423SLionel Sambuc /* Print the current pathname.  */
printpath(mode,nlcr)364433d6423SLionel Sambuc void printpath(mode, nlcr)
365433d6423SLionel Sambuc int mode;
366433d6423SLionel Sambuc int nlcr;
367433d6423SLionel Sambuc {
368433d6423SLionel Sambuc   if (ftop->st_next == 0)
369433d6423SLionel Sambuc 	putchar('/');
370433d6423SLionel Sambuc   else
371433d6423SLionel Sambuc 	printrec(ftop);
372433d6423SLionel Sambuc   switch (mode) {
373433d6423SLionel Sambuc       case 1:
374433d6423SLionel Sambuc 	printf(" (ino = %u, ", ftop->st_dir->d_inum);
375433d6423SLionel Sambuc 	break;
376433d6423SLionel Sambuc       case 2:
377433d6423SLionel Sambuc 	printf(" (ino = %u)", ftop->st_dir->d_inum);
378433d6423SLionel Sambuc 	break;
379433d6423SLionel Sambuc   }
380433d6423SLionel Sambuc   if (nlcr) printf("\n");
381433d6423SLionel Sambuc }
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc /* Open the device.  */
devopen()384433d6423SLionel Sambuc void devopen()
385433d6423SLionel Sambuc {
386433d6423SLionel Sambuc   if ((dev = open(fsck_device,
387433d6423SLionel Sambuc     (repair || markdirty) ? O_RDWR : O_RDONLY)) < 0) {
388433d6423SLionel Sambuc 	perror(fsck_device);
389433d6423SLionel Sambuc 	fatal("couldn't open device to fsck");
390433d6423SLionel Sambuc   }
391433d6423SLionel Sambuc }
392433d6423SLionel Sambuc 
393433d6423SLionel Sambuc /* Close the device. */
devclose()394433d6423SLionel Sambuc void devclose()
395433d6423SLionel Sambuc {
396433d6423SLionel Sambuc   if (close(dev) != 0) {
397433d6423SLionel Sambuc 	perror("close");
398433d6423SLionel Sambuc 	fatal("");
399433d6423SLionel Sambuc   }
400433d6423SLionel Sambuc }
401433d6423SLionel Sambuc 
402433d6423SLionel Sambuc /* Read or write a block. */
devio(bno,dir)403433d6423SLionel Sambuc void devio(bno, dir)
404433d6423SLionel Sambuc block_nr bno;
405433d6423SLionel Sambuc int dir;
406433d6423SLionel Sambuc {
407433d6423SLionel Sambuc   off_t r;
408433d6423SLionel Sambuc 
409433d6423SLionel Sambuc   if(!block_size) fatal("devio() with unknown block size");
410433d6423SLionel Sambuc   if (dir == READING && bno == thisblk) return;
411433d6423SLionel Sambuc   thisblk = bno;
412433d6423SLionel Sambuc 
413433d6423SLionel Sambuc #if 0
414433d6423SLionel Sambuc printf("%s at block %5d\n", dir == READING ? "reading " : "writing", bno);
415433d6423SLionel Sambuc #endif
416433d6423SLionel Sambuc   r= lseek(dev, btoa64(bno), SEEK_SET);
417433d6423SLionel Sambuc   if (r == (off_t)-1)
418433d6423SLionel Sambuc 	fatal("lseek failed");
419433d6423SLionel Sambuc   if (dir == READING) {
420433d6423SLionel Sambuc 	if (read(dev, rwbuf, block_size) == block_size)
421433d6423SLionel Sambuc 		return;
422433d6423SLionel Sambuc   } else {
423433d6423SLionel Sambuc 	if (write(dev, rwbuf, block_size) == block_size)
424433d6423SLionel Sambuc 		return;
425433d6423SLionel Sambuc   }
426433d6423SLionel Sambuc 
427433d6423SLionel Sambuc   printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
428433d6423SLionel Sambuc          dir == READING ? "read" : "write", (long) bno, errno);
429433d6423SLionel Sambuc   if (dir == READING) {
430433d6423SLionel Sambuc 	printf("Continuing with a zero-filled block.\n");
431433d6423SLionel Sambuc 	memset(rwbuf, 0, block_size);
432433d6423SLionel Sambuc 	return;
433433d6423SLionel Sambuc   }
434433d6423SLionel Sambuc   fatal("");
435433d6423SLionel Sambuc }
436433d6423SLionel Sambuc 
437433d6423SLionel Sambuc /* Read `size' bytes from the disk starting at block 'block' and
438433d6423SLionel Sambuc  * byte `offset'.
439433d6423SLionel Sambuc  */
devread(block,offset,buf,size)440433d6423SLionel Sambuc void devread(block, offset, buf, size)
441433d6423SLionel Sambuc long block;
442433d6423SLionel Sambuc long offset;
443433d6423SLionel Sambuc char *buf;
444433d6423SLionel Sambuc int size;
445433d6423SLionel Sambuc {
446433d6423SLionel Sambuc   if(!block_size) fatal("devread() with unknown block size");
447433d6423SLionel Sambuc   if (offset >= block_size)
448433d6423SLionel Sambuc   {
449433d6423SLionel Sambuc 	block += offset/block_size;
450433d6423SLionel Sambuc 	offset %= block_size;
451433d6423SLionel Sambuc   }
452433d6423SLionel Sambuc   devio(block, READING);
453433d6423SLionel Sambuc   memmove(buf, &rwbuf[offset], size);
454433d6423SLionel Sambuc }
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc /* Write `size' bytes to the disk starting at block 'block' and
457433d6423SLionel Sambuc  * byte `offset'.
458433d6423SLionel Sambuc  */
devwrite(block,offset,buf,size)459433d6423SLionel Sambuc void devwrite(block, offset, buf, size)
460433d6423SLionel Sambuc long block;
461433d6423SLionel Sambuc long offset;
462433d6423SLionel Sambuc char *buf;
463433d6423SLionel Sambuc int size;
464433d6423SLionel Sambuc {
465433d6423SLionel Sambuc   if(!block_size) fatal("devwrite() with unknown block size");
466433d6423SLionel Sambuc   if (!repair) fatal("internal error (devwrite)");
467433d6423SLionel Sambuc   if (offset >= block_size)
468433d6423SLionel Sambuc   {
469433d6423SLionel Sambuc 	block += offset/block_size;
470433d6423SLionel Sambuc 	offset %= block_size;
471433d6423SLionel Sambuc   }
472433d6423SLionel Sambuc   if (size != block_size) devio(block, READING);
473433d6423SLionel Sambuc   memmove(&rwbuf[offset], buf, size);
474433d6423SLionel Sambuc   devio(block, WRITING);
475433d6423SLionel Sambuc   changed = 1;
476433d6423SLionel Sambuc }
477433d6423SLionel Sambuc 
478433d6423SLionel Sambuc /* Print a string with either a singular or a plural pronoun. */
pr(fmt,cnt,s,p)479433d6423SLionel Sambuc void pr(fmt, cnt, s, p)
480433d6423SLionel Sambuc char *fmt, *s, *p;
481433d6423SLionel Sambuc int cnt;
482433d6423SLionel Sambuc {
483433d6423SLionel Sambuc   printf(fmt, cnt, cnt == 1 ? s : p);
484433d6423SLionel Sambuc }
485433d6423SLionel Sambuc 
486433d6423SLionel Sambuc /* Same as above, but with a long argument */
lpr(fmt,cnt,s,p)487433d6423SLionel Sambuc void lpr(fmt, cnt, s, p)
488433d6423SLionel Sambuc char *fmt, *s, *p;
489433d6423SLionel Sambuc long cnt;
490433d6423SLionel Sambuc {
491433d6423SLionel Sambuc   printf(fmt, cnt, cnt == 1 ? s : p);
492433d6423SLionel Sambuc }
493433d6423SLionel Sambuc 
494433d6423SLionel Sambuc /* Convert string to number. */
getnumber(s)495433d6423SLionel Sambuc bit_nr getnumber(s)
496433d6423SLionel Sambuc register char *s;
497433d6423SLionel Sambuc {
498433d6423SLionel Sambuc   register bit_nr n = 0;
499433d6423SLionel Sambuc 
500433d6423SLionel Sambuc   if (s == NULL)
501433d6423SLionel Sambuc 	return NO_BIT;
502433d6423SLionel Sambuc   while (isdigit(*s))
503433d6423SLionel Sambuc 	n = (n << 1) + (n << 3) + *s++ - '0';
504433d6423SLionel Sambuc   return (*s == '\0') ? n : NO_BIT;
505433d6423SLionel Sambuc }
506433d6423SLionel Sambuc 
507433d6423SLionel Sambuc /* See if the list pointed to by `argv' contains numbers. */
getlist(argv,type)508433d6423SLionel Sambuc char **getlist(argv, type)
509433d6423SLionel Sambuc char ***argv, *type;
510433d6423SLionel Sambuc {
511433d6423SLionel Sambuc   register char **list = *argv;
512433d6423SLionel Sambuc   register int empty = 1;
513433d6423SLionel Sambuc 
514433d6423SLionel Sambuc   while (getnumber(**argv) != NO_BIT) {
515433d6423SLionel Sambuc 	(*argv)++;
516433d6423SLionel Sambuc 	empty = 0;
517433d6423SLionel Sambuc   }
518433d6423SLionel Sambuc   if (empty) {
519433d6423SLionel Sambuc 	printf("warning: no %s numbers given\n", type);
520433d6423SLionel Sambuc 	return(NULL);
521433d6423SLionel Sambuc   }
522433d6423SLionel Sambuc   return(list);
523433d6423SLionel Sambuc }
524433d6423SLionel Sambuc 
525433d6423SLionel Sambuc /* Make a listing of the super block.  If `repair' is set, ask the user
526433d6423SLionel Sambuc  * for changes.
527433d6423SLionel Sambuc  */
lsuper()528433d6423SLionel Sambuc void lsuper()
529433d6423SLionel Sambuc {
530433d6423SLionel Sambuc   char buf[80];
531433d6423SLionel Sambuc 
532433d6423SLionel Sambuc   do {
533433d6423SLionel Sambuc 	/* Most of the following atol's enrage lint, for good reason. */
534433d6423SLionel Sambuc 	printf("ninodes       = %u", sb.s_ninodes);
535433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_ninodes = atol(buf);
536433d6423SLionel Sambuc 	printf("nzones        = %d", sb.s_zones);
537433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_zones = atol(buf);
538433d6423SLionel Sambuc 	printf("imap_blocks   = %u", sb.s_imap_blocks);
539433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_imap_blocks = atol(buf);
540433d6423SLionel Sambuc 	printf("zmap_blocks   = %u", sb.s_zmap_blocks);
541433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_zmap_blocks = atol(buf);
542433d6423SLionel Sambuc 	printf("firstdatazone = %u", sb.s_firstdatazone_old);
543433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_firstdatazone_old = atol(buf);
544433d6423SLionel Sambuc 	printf("log_zone_size = %u", sb.s_log_zone_size);
545433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_log_zone_size = atol(buf);
546433d6423SLionel Sambuc 	printf("maxsize       = %d", sb.s_max_size);
547433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_max_size = atol(buf);
548433d6423SLionel Sambuc 	printf("block size    = %d", sb.s_block_size);
549433d6423SLionel Sambuc 	if (input(buf, 80)) sb.s_block_size = atol(buf);
550433d6423SLionel Sambuc 	if (yes("ok now")) {
551433d6423SLionel Sambuc 		devwrite(0, OFFSET_SUPER_BLOCK, (char *) &sb, sizeof(sb));
552433d6423SLionel Sambuc 		return;
553433d6423SLionel Sambuc 	}
554433d6423SLionel Sambuc 	printf("flags         = ");
555433d6423SLionel Sambuc 	if(sb.s_flags & MFSFLAG_CLEAN) printf("CLEAN "); else printf("DIRTY ");
556433d6423SLionel Sambuc 	printf("\n");
557433d6423SLionel Sambuc   } while (yes("Do you want to try again"));
558433d6423SLionel Sambuc   if (repair) exit(FSCK_EXIT_OK);
559433d6423SLionel Sambuc }
560433d6423SLionel Sambuc 
561433d6423SLionel Sambuc /* Get the super block from either disk or user.  Do some initial checks. */
rw_super(int put)562433d6423SLionel Sambuc void rw_super(int put)
563433d6423SLionel Sambuc {
564433d6423SLionel Sambuc   if(lseek(dev, OFFSET_SUPER_BLOCK, SEEK_SET) < 0) {
565433d6423SLionel Sambuc   	perror("lseek");
566433d6423SLionel Sambuc   	fatal("couldn't seek to super block.");
567433d6423SLionel Sambuc   }
568433d6423SLionel Sambuc   if(put == SUPER_PUT)  {
569433d6423SLionel Sambuc     if(write(dev, &sb, sizeof(sb)) != sizeof(sb)) {
570433d6423SLionel Sambuc   	fatal("couldn't write super block.");
571433d6423SLionel Sambuc     }
572433d6423SLionel Sambuc     return;
573433d6423SLionel Sambuc   }
574433d6423SLionel Sambuc   if(read(dev, &sb, sizeof(sb)) != sizeof(sb)) {
575433d6423SLionel Sambuc   	fatal("couldn't read super block.");
576433d6423SLionel Sambuc   }
577433d6423SLionel Sambuc   if (listsuper) lsuper();
578433d6423SLionel Sambuc   if (sb.s_magic == SUPER_MAGIC) fatal("Cannot handle V1 file systems");
579433d6423SLionel Sambuc   if (sb.s_magic == SUPER_V2) {
580433d6423SLionel Sambuc   	fs_version = 2;
581433d6423SLionel Sambuc   	block_size = /* STATIC_BLOCK_SIZE */ 8192;
582433d6423SLionel Sambuc   } else if(sb.s_magic == SUPER_V3) {
583433d6423SLionel Sambuc   	fs_version = 3;
584433d6423SLionel Sambuc   	block_size = sb.s_block_size;
585433d6423SLionel Sambuc   } else {
586433d6423SLionel Sambuc   	fatal("bad magic number in super block");
587433d6423SLionel Sambuc   }
588433d6423SLionel Sambuc   if (sb.s_ninodes <= 0) fatal("no inodes");
589433d6423SLionel Sambuc   if (sb.s_zones <= 0) fatal("no zones");
590433d6423SLionel Sambuc   if (sb.s_imap_blocks <= 0) fatal("no imap");
591433d6423SLionel Sambuc   if (sb.s_zmap_blocks <= 0) fatal("no zmap");
592433d6423SLionel Sambuc   if (sb.s_firstdatazone != 0 && sb.s_firstdatazone <= 4)
593433d6423SLionel Sambuc 	fatal("first data zone too small");
594433d6423SLionel Sambuc   if (sb.s_log_zone_size < 0) fatal("zone size < block size");
595433d6423SLionel Sambuc   if (sb.s_max_size <= 0) {
596433d6423SLionel Sambuc 	printf("warning: invalid max file size %d\n", sb.s_max_size);
597433d6423SLionel Sambuc   	sb.s_max_size = LONG_MAX;
598433d6423SLionel Sambuc   }
599433d6423SLionel Sambuc }
600433d6423SLionel Sambuc 
601433d6423SLionel Sambuc /* Check the super block for reasonable contents. */
chksuper()602433d6423SLionel Sambuc void chksuper()
603433d6423SLionel Sambuc {
604433d6423SLionel Sambuc   register int n;
605433d6423SLionel Sambuc   register off_t maxsize;
606433d6423SLionel Sambuc 
607433d6423SLionel Sambuc   n = bitmapsize((bit_t) sb.s_ninodes + 1, block_size);
608433d6423SLionel Sambuc   if (sb.s_magic != SUPER_V2 && sb.s_magic != SUPER_V3)
609433d6423SLionel Sambuc   	fatal("bad magic number in super block");
610433d6423SLionel Sambuc   if (sb.s_imap_blocks < n) {
611433d6423SLionel Sambuc   	printf("need %d bocks for inode bitmap; only have %d\n",
612433d6423SLionel Sambuc   		n, sb.s_imap_blocks);
613433d6423SLionel Sambuc   	fatal("too few imap blocks");
614433d6423SLionel Sambuc   }
615433d6423SLionel Sambuc   if (sb.s_imap_blocks != n) {
616433d6423SLionel Sambuc 	pr("warning: expected %d imap_block%s", n, "", "s");
617433d6423SLionel Sambuc 	printf(" instead of %d\n", sb.s_imap_blocks);
618433d6423SLionel Sambuc   }
619433d6423SLionel Sambuc   n = bitmapsize((bit_t) sb.s_zones, block_size);
620433d6423SLionel Sambuc   if (sb.s_zmap_blocks < n) fatal("too few zmap blocks");
621433d6423SLionel Sambuc   if (sb.s_zmap_blocks != n) {
622433d6423SLionel Sambuc 	pr("warning: expected %d zmap_block%s", n, "", "s");
623433d6423SLionel Sambuc 	printf(" instead of %d\n", sb.s_zmap_blocks);
624433d6423SLionel Sambuc   }
625433d6423SLionel Sambuc   if (sb.s_log_zone_size >= 8 * sizeof(block_nr))
626433d6423SLionel Sambuc 	fatal("log_zone_size too large");
627433d6423SLionel Sambuc   if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n",
628433d6423SLionel Sambuc 	       sb.s_log_zone_size);
629433d6423SLionel Sambuc   sb.s_firstdatazone = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size;
630433d6423SLionel Sambuc   if (sb.s_firstdatazone_old != 0) {
631433d6423SLionel Sambuc 	if (sb.s_firstdatazone_old >= sb.s_zones)
632433d6423SLionel Sambuc 		fatal("first data zone too large");
633433d6423SLionel Sambuc 	if (sb.s_firstdatazone_old < sb.s_firstdatazone)
634433d6423SLionel Sambuc 		fatal("first data zone too small");
635433d6423SLionel Sambuc 	if (sb.s_firstdatazone_old != sb.s_firstdatazone) {
636433d6423SLionel Sambuc 		printf("warning: expected first data zone to be %u ",
637433d6423SLionel Sambuc 			sb.s_firstdatazone);
638433d6423SLionel Sambuc 		printf("instead of %u\n", sb.s_firstdatazone_old);
639433d6423SLionel Sambuc 		sb.s_firstdatazone = sb.s_firstdatazone_old;
640433d6423SLionel Sambuc 	}
641433d6423SLionel Sambuc   }
642433d6423SLionel Sambuc   maxsize = MAX_FILE_POS;
643433d6423SLionel Sambuc   if (((maxsize - 1) >> sb.s_log_zone_size) / block_size >= MAX_ZONES)
644433d6423SLionel Sambuc 	maxsize = ((long) MAX_ZONES * block_size) << sb.s_log_zone_size;
645433d6423SLionel Sambuc   if(maxsize <= 0)
646433d6423SLionel Sambuc 	maxsize = LONG_MAX;
647433d6423SLionel Sambuc   if (sb.s_max_size != maxsize) {
648*d0055759SDavid van Moolenbroek 	printf("warning: expected max size to be %lld ", maxsize);
649433d6423SLionel Sambuc 	printf("instead of %d\n", sb.s_max_size);
650433d6423SLionel Sambuc   }
651433d6423SLionel Sambuc 
652433d6423SLionel Sambuc   if(sb.s_flags & MFSFLAG_MANDATORY_MASK) {
653433d6423SLionel Sambuc   	fatal("unsupported feature bits - newer fsck needed");
654433d6423SLionel Sambuc   }
655433d6423SLionel Sambuc }
656433d6423SLionel Sambuc 
inoblock(int inn)657433d6423SLionel Sambuc int inoblock(int inn)
658433d6423SLionel Sambuc {
659433d6423SLionel Sambuc   return (int)(((u64_t)(inn - 1) * INODE_SIZE) / block_size) + BLK_ILIST;
660433d6423SLionel Sambuc }
661433d6423SLionel Sambuc 
inooff(int inn)662433d6423SLionel Sambuc int inooff(int inn)
663433d6423SLionel Sambuc {
664433d6423SLionel Sambuc   return (int)(((u64_t)(inn - 1) * INODE_SIZE) % block_size);
665433d6423SLionel Sambuc }
666433d6423SLionel Sambuc 
667433d6423SLionel Sambuc /* Make a listing of the inodes given by `clist'.  If `repair' is set, ask
668433d6423SLionel Sambuc  * the user for changes.
669433d6423SLionel Sambuc  */
lsi(clist)670433d6423SLionel Sambuc void lsi(clist)
671433d6423SLionel Sambuc char **clist;
672433d6423SLionel Sambuc {
673433d6423SLionel Sambuc   register bit_nr bit;
674433d6423SLionel Sambuc   register ino_t ino;
675433d6423SLionel Sambuc   d_inode inode, *ip = &inode;
676433d6423SLionel Sambuc   char buf[80];
677433d6423SLionel Sambuc 
678433d6423SLionel Sambuc   if (clist == 0) return;
679433d6423SLionel Sambuc   while ((bit = getnumber(*clist++)) != NO_BIT) {
680433d6423SLionel Sambuc 	setbit(spec_imap, bit);
681433d6423SLionel Sambuc 	ino = bit;
682433d6423SLionel Sambuc 	do {
683433d6423SLionel Sambuc 		devread(inoblock(ino), inooff(ino), (char *) ip, INODE_SIZE);
684*d0055759SDavid van Moolenbroek 		printf("inode %llu:\n", ino);
685433d6423SLionel Sambuc 		printf("    mode   = %6o", ip->i_mode);
686433d6423SLionel Sambuc 		if (input(buf, 80)) ip->i_mode = atoo(buf);
687433d6423SLionel Sambuc 		printf("    nlinks = %6u", ip->i_nlinks);
688433d6423SLionel Sambuc 		if (input(buf, 80)) ip->i_nlinks = atol(buf);
689433d6423SLionel Sambuc 		printf("    size   = %6d", ip->i_size);
690433d6423SLionel Sambuc 		if (input(buf, 80)) ip->i_size = atol(buf);
691433d6423SLionel Sambuc 		if (yes("Write this back")) {
692433d6423SLionel Sambuc 			devwrite(inoblock(ino), inooff(ino), (char *) ip,
693433d6423SLionel Sambuc 				INODE_SIZE);
694433d6423SLionel Sambuc 			break;
695433d6423SLionel Sambuc 		}
696433d6423SLionel Sambuc 	} while (yes("Do you want to change it again"));
697433d6423SLionel Sambuc   }
698433d6423SLionel Sambuc }
699433d6423SLionel Sambuc 
700433d6423SLionel Sambuc /* Allocate `nblk' blocks worth of bitmap. */
allocbitmap(nblk)701433d6423SLionel Sambuc bitchunk_t *allocbitmap(nblk)
702433d6423SLionel Sambuc int nblk;
703433d6423SLionel Sambuc {
704433d6423SLionel Sambuc   register bitchunk_t *bitmap;
705433d6423SLionel Sambuc 
706433d6423SLionel Sambuc   bitmap = (bitchunk_t *) alloc((unsigned) nblk, block_size);
707433d6423SLionel Sambuc   *bitmap |= 1;
708433d6423SLionel Sambuc   return(bitmap);
709433d6423SLionel Sambuc }
710433d6423SLionel Sambuc 
711433d6423SLionel Sambuc /* Load the bitmap starting at block `bno' from disk. */
loadbitmap(bitmap,bno,nblk)712433d6423SLionel Sambuc void loadbitmap(bitmap, bno, nblk)
713433d6423SLionel Sambuc bitchunk_t *bitmap;
714433d6423SLionel Sambuc block_nr bno;
715433d6423SLionel Sambuc int nblk;
716433d6423SLionel Sambuc {
717433d6423SLionel Sambuc   register int i;
718433d6423SLionel Sambuc   register bitchunk_t *p;
719433d6423SLionel Sambuc 
720433d6423SLionel Sambuc   p = bitmap;
721433d6423SLionel Sambuc   for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
722433d6423SLionel Sambuc 	devread(bno, 0, (char *) p, block_size);
723433d6423SLionel Sambuc   *bitmap |= 1;
724433d6423SLionel Sambuc }
725433d6423SLionel Sambuc 
726433d6423SLionel Sambuc /* Write the bitmap starting at block `bno' to disk. */
dumpbitmap(bitmap,bno,nblk)727433d6423SLionel Sambuc void dumpbitmap(bitmap, bno, nblk)
728433d6423SLionel Sambuc bitchunk_t *bitmap;
729433d6423SLionel Sambuc block_nr bno;
730433d6423SLionel Sambuc int nblk;
731433d6423SLionel Sambuc {
732433d6423SLionel Sambuc   register int i;
733433d6423SLionel Sambuc   register bitchunk_t *p = bitmap;
734433d6423SLionel Sambuc 
735433d6423SLionel Sambuc   for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
736433d6423SLionel Sambuc 	devwrite(bno, 0, (char *) p, block_size);
737433d6423SLionel Sambuc }
738433d6423SLionel Sambuc 
739433d6423SLionel Sambuc /* Set the bits given by `list' in the bitmap. */
fillbitmap(bitmap,lwb,upb,list)740433d6423SLionel Sambuc void fillbitmap(bitmap, lwb, upb, list)
741433d6423SLionel Sambuc bitchunk_t *bitmap;
742433d6423SLionel Sambuc bit_nr lwb, upb;
743433d6423SLionel Sambuc char **list;
744433d6423SLionel Sambuc {
745433d6423SLionel Sambuc   register bit_nr bit;
746433d6423SLionel Sambuc 
747433d6423SLionel Sambuc   if (list == 0) return;
748433d6423SLionel Sambuc   while ((bit = getnumber(*list++)) != NO_BIT)
749433d6423SLionel Sambuc 	if (bit < lwb || bit >= upb) {
750433d6423SLionel Sambuc 		if (bitmap == spec_imap)
751433d6423SLionel Sambuc 			printf("inode number %d ", bit);
752433d6423SLionel Sambuc 		else
753433d6423SLionel Sambuc 			printf("zone number %d ", bit);
754433d6423SLionel Sambuc 		printf("out of range (ignored)\n");
755433d6423SLionel Sambuc 	} else
756433d6423SLionel Sambuc 		setbit(bitmap, bit - lwb + 1);
757433d6423SLionel Sambuc }
758433d6423SLionel Sambuc 
759433d6423SLionel Sambuc /* Deallocate the bitmap `p'. */
freebitmap(p)760433d6423SLionel Sambuc void freebitmap(p)
761433d6423SLionel Sambuc bitchunk_t *p;
762433d6423SLionel Sambuc {
763433d6423SLionel Sambuc   free((char *) p);
764433d6423SLionel Sambuc }
765433d6423SLionel Sambuc 
766433d6423SLionel Sambuc /* Get all the bitmaps used by this program. */
getbitmaps()767433d6423SLionel Sambuc void getbitmaps()
768433d6423SLionel Sambuc {
769433d6423SLionel Sambuc   imap = allocbitmap(N_IMAP);
770433d6423SLionel Sambuc   zmap = allocbitmap(N_ZMAP);
771433d6423SLionel Sambuc   spec_imap = allocbitmap(N_IMAP);
772433d6423SLionel Sambuc   spec_zmap = allocbitmap(N_ZMAP);
773433d6423SLionel Sambuc   dirmap = allocbitmap(N_IMAP);
774433d6423SLionel Sambuc }
775433d6423SLionel Sambuc 
776433d6423SLionel Sambuc /* Release all the space taken by the bitmaps. */
putbitmaps()777433d6423SLionel Sambuc void putbitmaps()
778433d6423SLionel Sambuc {
779433d6423SLionel Sambuc   freebitmap(imap);
780433d6423SLionel Sambuc   freebitmap(zmap);
781433d6423SLionel Sambuc   freebitmap(spec_imap);
782433d6423SLionel Sambuc   freebitmap(spec_zmap);
783433d6423SLionel Sambuc   freebitmap(dirmap);
784433d6423SLionel Sambuc }
785433d6423SLionel Sambuc 
786433d6423SLionel Sambuc /* `w1' and `w2' are differing words from two bitmaps that should be
787433d6423SLionel Sambuc  * identical.  Print what's the matter with them.
788433d6423SLionel Sambuc  */
chkword(w1,w2,bit,type,n,report,phys)789433d6423SLionel Sambuc void chkword(w1, w2, bit, type, n, report, phys)
790433d6423SLionel Sambuc unsigned w1, w2;
791433d6423SLionel Sambuc char *type;
792433d6423SLionel Sambuc bit_nr bit;
793433d6423SLionel Sambuc int *n, *report;
794433d6423SLionel Sambuc bit_nr phys;
795433d6423SLionel Sambuc {
796433d6423SLionel Sambuc   for (; (w1 | w2); w1 >>= 1, w2 >>= 1, bit++, phys++)
797433d6423SLionel Sambuc 	if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report &&
798433d6423SLionel Sambuc 	    (!repair || automatic || yes("stop this listing")))
799433d6423SLionel Sambuc 		*report = 0;
800433d6423SLionel Sambuc 	else {
801*d0055759SDavid van Moolenbroek 	    if (*report) {
802433d6423SLionel Sambuc 		if ((w1 & 1) && !(w2 & 1))
803433d6423SLionel Sambuc 			printf("%s %d is missing\n", type, bit);
804433d6423SLionel Sambuc 		else if (!(w1 & 1) && (w2 & 1))
805433d6423SLionel Sambuc 			printf("%s %d is not free\n", type, bit);
806433d6423SLionel Sambuc 	    }
807433d6423SLionel Sambuc 	}
808*d0055759SDavid van Moolenbroek }
809433d6423SLionel Sambuc 
810433d6423SLionel Sambuc /* Check if the given (correct) bitmap is identical with the one that is
811433d6423SLionel Sambuc  * on the disk.  If not, ask if the disk should be repaired.
812433d6423SLionel Sambuc  */
chkmap(cmap,dmap,bit,blkno,nblk,type)813433d6423SLionel Sambuc void chkmap(cmap, dmap, bit, blkno, nblk, type)
814433d6423SLionel Sambuc bitchunk_t *cmap, *dmap;
815433d6423SLionel Sambuc bit_nr bit;
816433d6423SLionel Sambuc block_nr blkno;
817433d6423SLionel Sambuc int nblk;
818433d6423SLionel Sambuc char *type;
819433d6423SLionel Sambuc {
820433d6423SLionel Sambuc   register bitchunk_t *p = dmap, *q = cmap;
821433d6423SLionel Sambuc   int report = 1, nerr = 0;
822433d6423SLionel Sambuc   int w = nblk * WORDS_PER_BLOCK;
823433d6423SLionel Sambuc   bit_nr phys = 0;
824433d6423SLionel Sambuc 
825433d6423SLionel Sambuc   printf("Checking %s map. ", type);
826433d6423SLionel Sambuc   if(!preen) printf("\n");
827433d6423SLionel Sambuc   fflush(stdout);
828433d6423SLionel Sambuc   loadbitmap(dmap, blkno, nblk);
829433d6423SLionel Sambuc   do {
830433d6423SLionel Sambuc 	if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report, phys);
831433d6423SLionel Sambuc 	p++;
832433d6423SLionel Sambuc 	q++;
833433d6423SLionel Sambuc 	bit += 8 * sizeof(bitchunk_t);
834433d6423SLionel Sambuc 	phys += 8 * sizeof(bitchunk_t);
835433d6423SLionel Sambuc   } while (--w > 0);
836433d6423SLionel Sambuc 
837433d6423SLionel Sambuc   if ((!repair || automatic) && !report) printf("etc. ");
838433d6423SLionel Sambuc   if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
839433d6423SLionel Sambuc   if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
840433d6423SLionel Sambuc   if (nerr > 0) printf("\n");
841433d6423SLionel Sambuc }
842433d6423SLionel Sambuc 
843433d6423SLionel Sambuc /* See if the inodes that aren't allocated are cleared. */
chkilist()844433d6423SLionel Sambuc void chkilist()
845433d6423SLionel Sambuc {
846433d6423SLionel Sambuc   register ino_t ino = 1;
847433d6423SLionel Sambuc   mode_t mode;
848433d6423SLionel Sambuc 
849433d6423SLionel Sambuc   printf("Checking inode list. ");
850433d6423SLionel Sambuc   if(!preen) printf("\n");
851433d6423SLionel Sambuc   fflush(stdout);
852433d6423SLionel Sambuc   do
853433d6423SLionel Sambuc 	if (!bitset(imap, (bit_nr) ino)) {
854433d6423SLionel Sambuc 		devread(inoblock(ino), inooff(ino), (char *) &mode,
855433d6423SLionel Sambuc 			sizeof(mode));
856433d6423SLionel Sambuc 		if (mode != I_NOT_ALLOC) {
857*d0055759SDavid van Moolenbroek 			printf("mode inode %llu not cleared", ino);
858433d6423SLionel Sambuc 			if (yes(". clear")) devwrite(inoblock(ino),
859433d6423SLionel Sambuc 				inooff(ino), nullbuf, INODE_SIZE);
860433d6423SLionel Sambuc 		}
861433d6423SLionel Sambuc 	}
862433d6423SLionel Sambuc   while (++ino <= sb.s_ninodes && ino != 0);
863433d6423SLionel Sambuc   if(!preen) printf("\n");
864433d6423SLionel Sambuc }
865433d6423SLionel Sambuc 
866433d6423SLionel Sambuc /* Allocate an array to maintain the inode reference counts in. */
getcount()867433d6423SLionel Sambuc void getcount()
868433d6423SLionel Sambuc {
869433d6423SLionel Sambuc   count = (nlink_t *) alloc((unsigned) (sb.s_ninodes + 1), sizeof(nlink_t));
870433d6423SLionel Sambuc }
871433d6423SLionel Sambuc 
872433d6423SLionel Sambuc /* The reference count for inode `ino' is wrong.  Ask if it should be adjusted. */
counterror(ino_t ino)873433d6423SLionel Sambuc void counterror(ino_t ino)
874433d6423SLionel Sambuc {
875433d6423SLionel Sambuc   d_inode inode;
876433d6423SLionel Sambuc 
877433d6423SLionel Sambuc   if (firstcnterr) {
878433d6423SLionel Sambuc 	printf("INODE NLINK COUNT\n");
879433d6423SLionel Sambuc 	firstcnterr = 0;
880433d6423SLionel Sambuc   }
881433d6423SLionel Sambuc   devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
882433d6423SLionel Sambuc   count[ino] += inode.i_nlinks;	/* it was already subtracted; add it back */
883*d0055759SDavid van Moolenbroek   printf("%5llu %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
884433d6423SLionel Sambuc   if (yes(" adjust")) {
885433d6423SLionel Sambuc 	if ((inode.i_nlinks = count[ino]) == 0) {
886433d6423SLionel Sambuc 		fatal("internal error (counterror)");
887433d6423SLionel Sambuc 		inode.i_mode = I_NOT_ALLOC;
888433d6423SLionel Sambuc 		clrbit(imap, (bit_nr) ino);
889433d6423SLionel Sambuc 	}
890433d6423SLionel Sambuc 	devwrite(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
891433d6423SLionel Sambuc   }
892433d6423SLionel Sambuc }
893433d6423SLionel Sambuc 
894433d6423SLionel Sambuc /* Check if the reference count of the inodes are correct.  The array `count'
895433d6423SLionel Sambuc  * is maintained as follows:  an entry indexed by the inode number is
896433d6423SLionel Sambuc  * incremented each time a link is found; when the inode is read the link
897433d6423SLionel Sambuc  * count in there is substracted from the corresponding entry in `count'.
898433d6423SLionel Sambuc  * Thus, when the whole file system has been traversed, all the entries
899433d6423SLionel Sambuc  * should be zero.
900433d6423SLionel Sambuc  */
chkcount()901433d6423SLionel Sambuc void chkcount()
902433d6423SLionel Sambuc {
903433d6423SLionel Sambuc   register ino_t ino;
904433d6423SLionel Sambuc 
905433d6423SLionel Sambuc   for (ino = 1; ino <= sb.s_ninodes && ino != 0; ino++)
906433d6423SLionel Sambuc 	if (count[ino] != 0) counterror(ino);
907433d6423SLionel Sambuc   if (!firstcnterr) printf("\n");
908433d6423SLionel Sambuc }
909433d6423SLionel Sambuc 
910433d6423SLionel Sambuc /* Deallocate the `count' array. */
freecount()911433d6423SLionel Sambuc void freecount()
912433d6423SLionel Sambuc {
913433d6423SLionel Sambuc   free((char *) count);
914433d6423SLionel Sambuc }
915433d6423SLionel Sambuc 
916433d6423SLionel Sambuc /* Print the inode permission bits given by mode and shift. */
printperm(mode_t mode,int shift,int special,int overlay)917433d6423SLionel Sambuc void printperm(mode_t mode, int shift, int special, int overlay)
918433d6423SLionel Sambuc {
919433d6423SLionel Sambuc   if (mode >> shift & R_BIT)
920433d6423SLionel Sambuc 	putchar('r');
921433d6423SLionel Sambuc   else
922433d6423SLionel Sambuc 	putchar('-');
923433d6423SLionel Sambuc   if (mode >> shift & W_BIT)
924433d6423SLionel Sambuc 	putchar('w');
925433d6423SLionel Sambuc   else
926433d6423SLionel Sambuc 	putchar('-');
927433d6423SLionel Sambuc   if (mode & special)
928433d6423SLionel Sambuc 	putchar(overlay);
929433d6423SLionel Sambuc   else
930433d6423SLionel Sambuc 	if (mode >> shift & X_BIT)
931433d6423SLionel Sambuc 		putchar('x');
932433d6423SLionel Sambuc 	else
933433d6423SLionel Sambuc 		putchar('-');
934433d6423SLionel Sambuc }
935433d6423SLionel Sambuc 
936433d6423SLionel Sambuc /* List the given inode. */
list(ino_t ino,d_inode * ip)937433d6423SLionel Sambuc void list(ino_t ino, d_inode *ip)
938433d6423SLionel Sambuc {
939433d6423SLionel Sambuc   if (firstlist) {
940433d6423SLionel Sambuc 	firstlist = 0;
941433d6423SLionel Sambuc 	printf(" inode permission link   size name\n");
942433d6423SLionel Sambuc   }
943*d0055759SDavid van Moolenbroek   printf("%6llu ", ino);
944433d6423SLionel Sambuc   switch (ip->i_mode & I_TYPE) {
945433d6423SLionel Sambuc       case I_REGULAR:		putchar('-');	break;
946433d6423SLionel Sambuc       case I_DIRECTORY:		putchar('d');	break;
947433d6423SLionel Sambuc       case I_CHAR_SPECIAL:	putchar('c');	break;
948433d6423SLionel Sambuc       case I_BLOCK_SPECIAL:	putchar('b');	break;
949433d6423SLionel Sambuc       case I_NAMED_PIPE:	putchar('p');	break;
950433d6423SLionel Sambuc       case I_UNIX_SOCKET:	putchar('s');	break;
951433d6423SLionel Sambuc #ifdef I_SYMBOLIC_LINK
952433d6423SLionel Sambuc       case I_SYMBOLIC_LINK:	putchar('l');	break;
953433d6423SLionel Sambuc #endif
954433d6423SLionel Sambuc       default:			putchar('?');
955433d6423SLionel Sambuc }
956433d6423SLionel Sambuc   printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
957433d6423SLionel Sambuc   printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
958433d6423SLionel Sambuc   printperm(ip->i_mode, 0, STICKY_BIT, 't');
959433d6423SLionel Sambuc   printf(" %3u ", ip->i_nlinks);
960433d6423SLionel Sambuc   switch (ip->i_mode & I_TYPE) {
961433d6423SLionel Sambuc       case I_CHAR_SPECIAL:
962433d6423SLionel Sambuc       case I_BLOCK_SPECIAL:
963433d6423SLionel Sambuc 	printf("  %2x,%2x ", major(ip->i_zone[0]), minor(ip->i_zone[0]));
964433d6423SLionel Sambuc 	break;
965433d6423SLionel Sambuc       default:	printf("%7d ", ip->i_size);
966433d6423SLionel Sambuc   }
967433d6423SLionel Sambuc   printpath(0, 1);
968433d6423SLionel Sambuc }
969433d6423SLionel Sambuc 
970433d6423SLionel Sambuc /* Remove an entry from a directory if ok with the user.
971433d6423SLionel Sambuc  * Don't name the function remove() - that is owned by ANSI, and chaos results
972433d6423SLionel Sambuc  * when it is a macro.
973433d6423SLionel Sambuc  */
Remove(dir_struct * dp)974433d6423SLionel Sambuc int Remove(dir_struct *dp)
975433d6423SLionel Sambuc {
976433d6423SLionel Sambuc   setbit(spec_imap, (bit_nr) dp->d_inum);
977433d6423SLionel Sambuc   if (yes(". remove entry")) {
978433d6423SLionel Sambuc 	count[dp->d_inum]--;
979433d6423SLionel Sambuc 	memset((void *) dp, 0, sizeof(dir_struct));
980433d6423SLionel Sambuc 	return(1);
981433d6423SLionel Sambuc   }
982433d6423SLionel Sambuc   return(0);
983433d6423SLionel Sambuc }
984433d6423SLionel Sambuc 
985433d6423SLionel Sambuc /* Convert string so that embedded control characters are printable. */
make_printable_name(dst,src,n)986433d6423SLionel Sambuc void make_printable_name(dst, src, n)
987433d6423SLionel Sambuc register char *dst;
988433d6423SLionel Sambuc register char *src;
989433d6423SLionel Sambuc register int n;
990433d6423SLionel Sambuc {
991433d6423SLionel Sambuc   register int c;
992433d6423SLionel Sambuc 
993433d6423SLionel Sambuc   while (--n >= 0 && (c = *src++) != '\0') {
994433d6423SLionel Sambuc 	if (isprint(c) && c != '\\')
995433d6423SLionel Sambuc 		*dst++ = c;
996433d6423SLionel Sambuc 	else {
997433d6423SLionel Sambuc 		*dst++ = '\\';
998433d6423SLionel Sambuc 		switch (c) {
999433d6423SLionel Sambuc 		      case '\\':
1000433d6423SLionel Sambuc 			*dst++ = '\\'; break;
1001433d6423SLionel Sambuc 		      case '\b':
1002433d6423SLionel Sambuc 			*dst++ = 'b'; break;
1003433d6423SLionel Sambuc 		      case '\f':
1004433d6423SLionel Sambuc 			*dst++ = 'f'; break;
1005433d6423SLionel Sambuc 		      case '\n':
1006433d6423SLionel Sambuc 			*dst++ = 'n'; break;
1007433d6423SLionel Sambuc 		      case '\r':
1008433d6423SLionel Sambuc 			*dst++ = 'r'; break;
1009433d6423SLionel Sambuc 		      case '\t':
1010433d6423SLionel Sambuc 			*dst++ = 't'; break;
1011433d6423SLionel Sambuc 		      default:
1012433d6423SLionel Sambuc 			*dst++ = '0' + ((c >> 6) & 03);
1013433d6423SLionel Sambuc 			*dst++ = '0' + ((c >> 3) & 07);
1014433d6423SLionel Sambuc 			*dst++ = '0' + (c & 07);
1015433d6423SLionel Sambuc 		}
1016433d6423SLionel Sambuc 	}
1017433d6423SLionel Sambuc   }
1018433d6423SLionel Sambuc   *dst = '\0';
1019433d6423SLionel Sambuc }
1020433d6423SLionel Sambuc 
1021433d6423SLionel Sambuc /* See if the `.' or `..' entry is as expected. */
chkdots(ino_t ino,off_t pos,dir_struct * dp,ino_t exp)1022433d6423SLionel Sambuc int chkdots(ino_t ino, off_t pos, dir_struct *dp, ino_t exp)
1023433d6423SLionel Sambuc {
1024433d6423SLionel Sambuc   char printable_name[4 * MFS_NAME_MAX + 1];
1025433d6423SLionel Sambuc 
1026433d6423SLionel Sambuc   if (dp->d_inum != exp) {
1027*d0055759SDavid van Moolenbroek 	make_printable_name(printable_name, dp->mfs_d_name,
1028*d0055759SDavid van Moolenbroek 	    sizeof(dp->mfs_d_name));
1029433d6423SLionel Sambuc 	printf("bad %s in ", printable_name);
1030433d6423SLionel Sambuc 	printpath(1, 0);
1031433d6423SLionel Sambuc 	printf("%s is linked to %u ", printable_name, dp->d_inum);
1032*d0055759SDavid van Moolenbroek 	printf("instead of %llu)", exp);
1033433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) ino);
1034433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) dp->d_inum);
1035433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) exp);
1036433d6423SLionel Sambuc 	if (yes(". repair")) {
1037433d6423SLionel Sambuc 		count[dp->d_inum]--;
1038433d6423SLionel Sambuc 		dp->d_inum = exp;
1039433d6423SLionel Sambuc 		count[exp]++;
1040433d6423SLionel Sambuc 		return(0);
1041433d6423SLionel Sambuc 	}
1042433d6423SLionel Sambuc   } else if (pos != (dp->mfs_d_name[1] ? DIR_ENTRY_SIZE : 0)) {
1043*d0055759SDavid van Moolenbroek 	make_printable_name(printable_name, dp->mfs_d_name,
1044*d0055759SDavid van Moolenbroek 	    sizeof(dp->mfs_d_name));
1045*d0055759SDavid van Moolenbroek 	printf("warning: %s has offset %lld in ", printable_name, pos);
1046433d6423SLionel Sambuc 	printpath(1, 0);
1047433d6423SLionel Sambuc 	printf("%s is linked to %u)\n", printable_name, dp->d_inum);
1048433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) ino);
1049433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) dp->d_inum);
1050433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) exp);
1051433d6423SLionel Sambuc   }
1052433d6423SLionel Sambuc   return(1);
1053433d6423SLionel Sambuc }
1054433d6423SLionel Sambuc 
1055433d6423SLionel Sambuc /* Check the name in a directory entry. */
chkname(ino_t ino,dir_struct * dp)1056433d6423SLionel Sambuc int chkname(ino_t ino, dir_struct *dp)
1057433d6423SLionel Sambuc {
1058433d6423SLionel Sambuc   register int n = MFS_NAME_MAX + 1;
1059433d6423SLionel Sambuc   register char *p = dp->mfs_d_name;
1060433d6423SLionel Sambuc 
1061433d6423SLionel Sambuc   if (*p == '\0') {
1062433d6423SLionel Sambuc 	printf("null name found in ");
1063433d6423SLionel Sambuc 	printpath(0, 0);
1064433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) ino);
1065433d6423SLionel Sambuc 	if (Remove(dp)) return(0);
1066433d6423SLionel Sambuc   }
1067433d6423SLionel Sambuc   while (*p != '\0' && --n != 0)
1068433d6423SLionel Sambuc 	if (*p++ == '/') {
1069433d6423SLionel Sambuc 		printf("found a '/' in entry of directory ");
1070433d6423SLionel Sambuc 		printpath(1, 0);
1071433d6423SLionel Sambuc 		setbit(spec_imap, (bit_nr) ino);
1072433d6423SLionel Sambuc 		printf("entry = '");
1073433d6423SLionel Sambuc 		printname(dp->mfs_d_name);
1074433d6423SLionel Sambuc 		printf("')");
1075433d6423SLionel Sambuc 		if (Remove(dp)) return(0);
1076433d6423SLionel Sambuc 		break;
1077433d6423SLionel Sambuc 	}
1078433d6423SLionel Sambuc   return(1);
1079433d6423SLionel Sambuc }
1080433d6423SLionel Sambuc 
1081433d6423SLionel Sambuc /* Check a directory entry.  Here the routine `descendtree' is called
1082433d6423SLionel Sambuc  * recursively to check the file or directory pointed to by the entry.
1083433d6423SLionel Sambuc  */
chkentry(ino_t ino,off_t pos,dir_struct * dp)1084433d6423SLionel Sambuc int chkentry(ino_t ino, off_t pos, dir_struct *dp)
1085433d6423SLionel Sambuc {
1086433d6423SLionel Sambuc   if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
1087433d6423SLionel Sambuc 	printf("bad inode found in directory ");
1088433d6423SLionel Sambuc 	printpath(1, 0);
1089433d6423SLionel Sambuc 	printf("ino found = %u, ", dp->d_inum);
1090433d6423SLionel Sambuc 	printf("name = '");
1091433d6423SLionel Sambuc 	printname(dp->mfs_d_name);
1092433d6423SLionel Sambuc 	printf("')");
1093433d6423SLionel Sambuc 	if (yes(". remove entry")) {
1094433d6423SLionel Sambuc 		memset((void *) dp, 0, sizeof(dir_struct));
1095433d6423SLionel Sambuc 		return(0);
1096433d6423SLionel Sambuc 	}
1097433d6423SLionel Sambuc 	return(1);
1098433d6423SLionel Sambuc   }
1099433d6423SLionel Sambuc   if ((unsigned) count[dp->d_inum] == SHRT_MAX) {
1100433d6423SLionel Sambuc 	printf("too many links to ino %u\n", dp->d_inum);
1101433d6423SLionel Sambuc 	printf("discovered at entry '");
1102433d6423SLionel Sambuc 	printname(dp->mfs_d_name);
1103433d6423SLionel Sambuc 	printf("' in directory ");
1104433d6423SLionel Sambuc 	printpath(0, 1);
1105433d6423SLionel Sambuc 	if (Remove(dp)) return(0);
1106433d6423SLionel Sambuc   }
1107433d6423SLionel Sambuc   count[dp->d_inum]++;
1108433d6423SLionel Sambuc   if (strcmp(dp->mfs_d_name, ".") == 0) {
1109433d6423SLionel Sambuc 	ftop->st_presence |= DOT;
1110433d6423SLionel Sambuc 	return(chkdots(ino, pos, dp, ino));
1111433d6423SLionel Sambuc   }
1112433d6423SLionel Sambuc   if (strcmp(dp->mfs_d_name, "..") == 0) {
1113433d6423SLionel Sambuc 	ftop->st_presence |= DOTDOT;
1114433d6423SLionel Sambuc 	return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
1115433d6423SLionel Sambuc 			ftop->st_next->st_dir->d_inum));
1116433d6423SLionel Sambuc   }
1117433d6423SLionel Sambuc   if (!chkname(ino, dp)) return(0);
1118433d6423SLionel Sambuc   if (bitset(dirmap, (bit_nr) dp->d_inum)) {
1119433d6423SLionel Sambuc 	printf("link to directory discovered in ");
1120433d6423SLionel Sambuc 	printpath(1, 0);
1121433d6423SLionel Sambuc 	printf("name = '");
1122433d6423SLionel Sambuc 	printname(dp->mfs_d_name);
1123433d6423SLionel Sambuc 	printf("', dir ino = %u)", dp->d_inum);
1124433d6423SLionel Sambuc 	return !Remove(dp);
1125433d6423SLionel Sambuc   }
1126433d6423SLionel Sambuc   return(descendtree(dp));
1127433d6423SLionel Sambuc }
1128433d6423SLionel Sambuc 
1129433d6423SLionel Sambuc /* Check a zone of a directory by checking all the entries in the zone.
1130433d6423SLionel Sambuc  * The zone is split up into chunks to not allocate too much stack.
1131433d6423SLionel Sambuc  */
chkdirzone(ino_t ino,d_inode * ip,off_t pos,zone_nr zno)1132433d6423SLionel Sambuc int chkdirzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1133433d6423SLionel Sambuc {
1134433d6423SLionel Sambuc   dir_struct dirblk[CDIRECT];
1135433d6423SLionel Sambuc   register dir_struct *dp;
1136433d6423SLionel Sambuc   register int n, dirty;
1137433d6423SLionel Sambuc   long block= ztob(zno);
1138433d6423SLionel Sambuc   register long offset = 0;
1139433d6423SLionel Sambuc   register off_t size = 0;
1140433d6423SLionel Sambuc   n = SCALE * (NR_DIR_ENTRIES(block_size) / CDIRECT);
1141433d6423SLionel Sambuc 
1142433d6423SLionel Sambuc   do {
1143433d6423SLionel Sambuc 	devread(block, offset, (char *) dirblk, DIRCHUNK);
1144433d6423SLionel Sambuc 	dirty = 0;
1145433d6423SLionel Sambuc 	for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
1146433d6423SLionel Sambuc 		if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))
1147433d6423SLionel Sambuc 			dirty = 1;
1148433d6423SLionel Sambuc 		pos += DIR_ENTRY_SIZE;
1149433d6423SLionel Sambuc 		if (dp->d_inum != NO_ENTRY) size = pos;
1150433d6423SLionel Sambuc 	}
1151433d6423SLionel Sambuc 	if (dirty) devwrite(block, offset, (char *) dirblk, DIRCHUNK);
1152433d6423SLionel Sambuc 	offset += DIRCHUNK;
1153433d6423SLionel Sambuc 	n--;
1154433d6423SLionel Sambuc   } while (n > 0);
1155433d6423SLionel Sambuc 
1156433d6423SLionel Sambuc   if (size > ip->i_size) {
1157433d6423SLionel Sambuc 	printf("size not updated of directory ");
1158433d6423SLionel Sambuc 	printpath(2, 0);
1159433d6423SLionel Sambuc 	if (yes(". extend")) {
1160433d6423SLionel Sambuc 		setbit(spec_imap, (bit_nr) ino);
1161433d6423SLionel Sambuc 		ip->i_size = size;
1162433d6423SLionel Sambuc 		devwrite(inoblock(ino), inooff(ino), (char *) ip, INODE_SIZE);
1163433d6423SLionel Sambuc 	}
1164433d6423SLionel Sambuc   }
1165433d6423SLionel Sambuc   return(1);
1166433d6423SLionel Sambuc }
1167433d6423SLionel Sambuc 
1168433d6423SLionel Sambuc 
chksymlinkzone(ino_t ino,d_inode * ip,off_t pos,zone_nr zno)1169433d6423SLionel Sambuc int chksymlinkzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1170433d6423SLionel Sambuc {
1171433d6423SLionel Sambuc 	long block;
1172433d6423SLionel Sambuc 	size_t len;
1173433d6423SLionel Sambuc 	char target[PATH_MAX+1];
1174433d6423SLionel Sambuc 
1175433d6423SLionel Sambuc 	if (ip->i_size > PATH_MAX)
1176433d6423SLionel Sambuc 		fatal("chksymlinkzone: fsck program inconsistency\n");
1177433d6423SLionel Sambuc 	block= ztob(zno);
1178433d6423SLionel Sambuc 	devread(block, 0, target, ip->i_size);
1179433d6423SLionel Sambuc 	target[ip->i_size]= '\0';
1180433d6423SLionel Sambuc 	len= strlen(target);
1181433d6423SLionel Sambuc 	if (len != ip->i_size)
1182433d6423SLionel Sambuc 	{
1183433d6423SLionel Sambuc 		printf("bad size in symbolic link (%d instead of %d) ",
1184433d6423SLionel Sambuc 			ip->i_size, len);
1185433d6423SLionel Sambuc 		printpath(2, 0);
1186433d6423SLionel Sambuc 		if (yes(". update")) {
1187433d6423SLionel Sambuc 			setbit(spec_imap, (bit_nr) ino);
1188433d6423SLionel Sambuc 			ip->i_size = len;
1189433d6423SLionel Sambuc 			devwrite(inoblock(ino), inooff(ino),
1190433d6423SLionel Sambuc 				(char *) ip, INODE_SIZE);
1191433d6423SLionel Sambuc 		}
1192433d6423SLionel Sambuc 	}
1193433d6423SLionel Sambuc 	return 1;
1194433d6423SLionel Sambuc }
1195433d6423SLionel Sambuc 
1196433d6423SLionel Sambuc /* There is something wrong with the given zone.  Print some details. */
errzone(mess,zno,level,pos)1197433d6423SLionel Sambuc void errzone(mess, zno, level, pos)
1198433d6423SLionel Sambuc char *mess;
1199433d6423SLionel Sambuc zone_nr zno;
1200433d6423SLionel Sambuc int level;
1201433d6423SLionel Sambuc off_t pos;
1202433d6423SLionel Sambuc {
1203433d6423SLionel Sambuc   printf("%s zone in ", mess);
1204433d6423SLionel Sambuc   printpath(1, 0);
1205433d6423SLionel Sambuc   printf("zno = %d, type = ", zno);
1206433d6423SLionel Sambuc   switch (level) {
1207433d6423SLionel Sambuc       case 0:	printf("DATA");	break;
1208433d6423SLionel Sambuc       case 1:	printf("SINGLE INDIRECT");	break;
1209433d6423SLionel Sambuc       case 2:	printf("DOUBLE INDIRECT");	break;
1210433d6423SLionel Sambuc       default:	printf("VERY INDIRECT");
1211433d6423SLionel Sambuc   }
1212*d0055759SDavid van Moolenbroek   printf(", pos = %lld)\n", pos);
1213433d6423SLionel Sambuc }
1214433d6423SLionel Sambuc 
1215433d6423SLionel Sambuc /* Found the given zone in the given inode.  Check it, and if ok, mark it
1216433d6423SLionel Sambuc  * in the zone bitmap.
1217433d6423SLionel Sambuc  */
markzone(zno,level,pos)1218433d6423SLionel Sambuc int markzone(zno, level, pos)
1219433d6423SLionel Sambuc zone_nr zno;
1220433d6423SLionel Sambuc int level;
1221433d6423SLionel Sambuc off_t pos;
1222433d6423SLionel Sambuc {
1223433d6423SLionel Sambuc   register bit_nr bit = (bit_nr) zno - FIRST + 1;
1224433d6423SLionel Sambuc 
1225433d6423SLionel Sambuc   ztype[level]++;
1226433d6423SLionel Sambuc   if (zno < FIRST || zno >= sb.s_zones) {
1227433d6423SLionel Sambuc 	errzone("out-of-range", zno, level, pos);
1228433d6423SLionel Sambuc 	return(0);
1229433d6423SLionel Sambuc   }
1230433d6423SLionel Sambuc   if (bitset(zmap, bit)) {
1231433d6423SLionel Sambuc 	setbit(spec_zmap, bit);
1232433d6423SLionel Sambuc 	errzone("duplicate", zno, level, pos);
1233433d6423SLionel Sambuc 	return(0);
1234433d6423SLionel Sambuc   }
1235433d6423SLionel Sambuc   nfreezone--;
1236433d6423SLionel Sambuc   if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
1237433d6423SLionel Sambuc   setbit(zmap, bit);
1238433d6423SLionel Sambuc   return(1);
1239433d6423SLionel Sambuc }
1240433d6423SLionel Sambuc 
1241433d6423SLionel Sambuc /* Check an indirect zone by checking all of its entries.
1242433d6423SLionel Sambuc  * The zone is split up into chunks to not allocate too much stack.
1243433d6423SLionel Sambuc  */
chkindzone(ino_t ino,d_inode * ip,off_t * pos,zone_nr zno,int level)1244433d6423SLionel Sambuc int chkindzone(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1245433d6423SLionel Sambuc {
1246433d6423SLionel Sambuc   zone_nr indirect[CINDIR];
1247433d6423SLionel Sambuc   register int n = NR_INDIRECTS / CINDIR;
1248433d6423SLionel Sambuc   long block= ztob(zno);
1249433d6423SLionel Sambuc   register long offset = 0;
1250433d6423SLionel Sambuc 
1251433d6423SLionel Sambuc   do {
1252433d6423SLionel Sambuc 	devread(block, offset, (char *) indirect, INDCHUNK);
1253433d6423SLionel Sambuc 	if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
1254433d6423SLionel Sambuc 	offset += INDCHUNK;
1255433d6423SLionel Sambuc   } while (--n && *pos < ip->i_size);
1256433d6423SLionel Sambuc   return(1);
1257433d6423SLionel Sambuc }
1258433d6423SLionel Sambuc 
1259433d6423SLionel Sambuc /* Return the size of a gap in the file, represented by a null zone number
1260433d6423SLionel Sambuc  * at some level of indirection.
1261433d6423SLionel Sambuc  */
jump(level)1262433d6423SLionel Sambuc off_t jump(level)
1263433d6423SLionel Sambuc int level;
1264433d6423SLionel Sambuc {
1265433d6423SLionel Sambuc   off_t power = ZONE_SIZE;
1266433d6423SLionel Sambuc 
1267433d6423SLionel Sambuc   if (level != 0) do
1268433d6423SLionel Sambuc 		power *= NR_INDIRECTS;
1269433d6423SLionel Sambuc 	while (--level);
1270433d6423SLionel Sambuc   return(power);
1271433d6423SLionel Sambuc }
1272433d6423SLionel Sambuc 
1273433d6423SLionel Sambuc /* Check a zone, which may be either a normal data zone, a directory zone,
1274433d6423SLionel Sambuc  * or an indirect zone.
1275433d6423SLionel Sambuc  */
zonechk(ino_t ino,d_inode * ip,off_t * pos,zone_nr zno,int level)1276433d6423SLionel Sambuc int zonechk(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1277433d6423SLionel Sambuc {
1278433d6423SLionel Sambuc   if (level == 0) {
1279433d6423SLionel Sambuc 	if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
1280433d6423SLionel Sambuc 	    !chkdirzone(ino, ip, *pos, zno))
1281433d6423SLionel Sambuc 		return(0);
1282433d6423SLionel Sambuc 	if ((ip->i_mode & I_TYPE) == I_SYMBOLIC_LINK &&
1283433d6423SLionel Sambuc 	    !chksymlinkzone(ino, ip, *pos, zno))
1284433d6423SLionel Sambuc 		return(0);
1285433d6423SLionel Sambuc 	*pos += ZONE_SIZE;
1286433d6423SLionel Sambuc 	return(1);
1287433d6423SLionel Sambuc   } else
1288433d6423SLionel Sambuc 	return chkindzone(ino, ip, pos, zno, level);
1289433d6423SLionel Sambuc }
1290433d6423SLionel Sambuc 
1291433d6423SLionel Sambuc /* Check a list of zones given by `zlist'. */
chkzones(ino_t ino,d_inode * ip,off_t * pos,zone_nr * zlist,int len,int level)1292433d6423SLionel Sambuc int chkzones(ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist,
1293433d6423SLionel Sambuc  int len, int level)
1294433d6423SLionel Sambuc {
1295433d6423SLionel Sambuc   register int ok = 1, i;
1296433d6423SLionel Sambuc 
1297433d6423SLionel Sambuc   /* The check on the position in the next loop is commented out, since FS
1298433d6423SLionel Sambuc    * now requires valid zone numbers in each level that is necessary and FS
1299433d6423SLionel Sambuc    * always deleted all the zones in the double indirect block.
1300433d6423SLionel Sambuc    */
1301433d6423SLionel Sambuc   for (i = 0; i < len /* && *pos < ip->i_size */ ; i++)
1302433d6423SLionel Sambuc 	if (zlist[i] == NO_ZONE)
1303433d6423SLionel Sambuc 		*pos += jump(level);
1304433d6423SLionel Sambuc 	else if (!markzone(zlist[i], level, *pos)) {
1305433d6423SLionel Sambuc 		*pos += jump(level);
1306433d6423SLionel Sambuc 		ok = 0;
1307433d6423SLionel Sambuc 	} else if (!zonechk(ino, ip, pos, zlist[i], level))
1308433d6423SLionel Sambuc 		ok = 0;
1309433d6423SLionel Sambuc   return(ok);
1310433d6423SLionel Sambuc }
1311433d6423SLionel Sambuc 
1312433d6423SLionel Sambuc /* Check a file or a directory. */
chkfile(ino_t ino,d_inode * ip)1313433d6423SLionel Sambuc int chkfile(ino_t ino, d_inode *ip)
1314433d6423SLionel Sambuc {
1315433d6423SLionel Sambuc   register int ok, i, level;
1316433d6423SLionel Sambuc   off_t pos = 0;
1317433d6423SLionel Sambuc 
1318433d6423SLionel Sambuc   ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0);
1319433d6423SLionel Sambuc   for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
1320433d6423SLionel Sambuc 	ok &= chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level);
1321433d6423SLionel Sambuc   return(ok);
1322433d6423SLionel Sambuc }
1323433d6423SLionel Sambuc 
1324433d6423SLionel Sambuc /* Check a directory by checking the contents.  Check if . and .. are present. */
chkdirectory(ino_t ino,d_inode * ip)1325433d6423SLionel Sambuc int chkdirectory(ino_t ino, d_inode *ip)
1326433d6423SLionel Sambuc {
1327433d6423SLionel Sambuc   register int ok;
1328433d6423SLionel Sambuc 
1329433d6423SLionel Sambuc   setbit(dirmap, (bit_nr) ino);
1330433d6423SLionel Sambuc   ok = chkfile(ino, ip);
1331433d6423SLionel Sambuc   if (!(ftop->st_presence & DOT)) {
1332433d6423SLionel Sambuc 	printf(". missing in ");
1333433d6423SLionel Sambuc 	printpath(2, 1);
1334433d6423SLionel Sambuc 	ok = 0;
1335433d6423SLionel Sambuc   }
1336433d6423SLionel Sambuc   if (!(ftop->st_presence & DOTDOT)) {
1337433d6423SLionel Sambuc 	printf(".. missing in ");
1338433d6423SLionel Sambuc 	printpath(2, 1);
1339433d6423SLionel Sambuc 	ok = 0;
1340433d6423SLionel Sambuc   }
1341433d6423SLionel Sambuc   return(ok);
1342433d6423SLionel Sambuc }
1343433d6423SLionel Sambuc 
1344433d6423SLionel Sambuc #ifdef I_SYMBOLIC_LINK
1345433d6423SLionel Sambuc 
1346433d6423SLionel Sambuc /* Check the validity of a symbolic link. */
chklink(ino_t ino,d_inode * ip)1347433d6423SLionel Sambuc int chklink(ino_t ino, d_inode *ip)
1348433d6423SLionel Sambuc {
1349433d6423SLionel Sambuc   int ok;
1350433d6423SLionel Sambuc 
1351433d6423SLionel Sambuc   ok = chkfile(ino, ip);
1352433d6423SLionel Sambuc   if (ip->i_size <= 0 || ip->i_size > block_size) {
1353433d6423SLionel Sambuc 	if (ip->i_size == 0)
1354433d6423SLionel Sambuc 		printf("empty symbolic link ");
1355433d6423SLionel Sambuc 	else
1356433d6423SLionel Sambuc 		printf("symbolic link too large (size %d) ", ip->i_size);
1357433d6423SLionel Sambuc 	printpath(2, 1);
1358433d6423SLionel Sambuc 	ok = 0;
1359433d6423SLionel Sambuc   }
1360433d6423SLionel Sambuc   return(ok);
1361433d6423SLionel Sambuc }
1362433d6423SLionel Sambuc 
1363433d6423SLionel Sambuc #endif
1364433d6423SLionel Sambuc 
1365433d6423SLionel Sambuc /* Check the validity of a special file. */
chkspecial(ino_t ino,d_inode * ip)1366433d6423SLionel Sambuc int chkspecial(ino_t ino, d_inode *ip)
1367433d6423SLionel Sambuc {
1368433d6423SLionel Sambuc   int i, ok;
1369433d6423SLionel Sambuc 
1370433d6423SLionel Sambuc   ok = 1;
1371433d6423SLionel Sambuc   if ((dev_t) ip->i_zone[0] == NO_DEV) {
1372433d6423SLionel Sambuc 	printf("illegal device number %d for special file ", ip->i_zone[0]);
1373433d6423SLionel Sambuc 	printpath(2, 1);
1374433d6423SLionel Sambuc 	ok = 0;
1375433d6423SLionel Sambuc   }
1376433d6423SLionel Sambuc 
1377433d6423SLionel Sambuc   /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
1378433d6423SLionel Sambuc    * they are nonzero, since this should not happen.
1379433d6423SLionel Sambuc    */
1380433d6423SLionel Sambuc   for (i = 1; i < NR_ZONE_NUMS; i++)
1381433d6423SLionel Sambuc 	if (ip->i_zone[i] != NO_ZONE) {
1382433d6423SLionel Sambuc 		printf("nonzero zone number %d for special file ",
1383433d6423SLionel Sambuc 		       ip->i_zone[i]);
1384433d6423SLionel Sambuc 		printpath(2, 1);
1385433d6423SLionel Sambuc 		ok = 0;
1386433d6423SLionel Sambuc 	}
1387433d6423SLionel Sambuc   return(ok);
1388433d6423SLionel Sambuc }
1389433d6423SLionel Sambuc 
1390433d6423SLionel Sambuc /* Check the mode and contents of an inode. */
chkmode(ino_t ino,d_inode * ip)1391433d6423SLionel Sambuc int chkmode(ino_t ino, d_inode *ip)
1392433d6423SLionel Sambuc {
1393433d6423SLionel Sambuc   switch (ip->i_mode & I_TYPE) {
1394433d6423SLionel Sambuc       case I_REGULAR:
1395433d6423SLionel Sambuc 	nregular++;
1396433d6423SLionel Sambuc 	return chkfile(ino, ip);
1397433d6423SLionel Sambuc       case I_DIRECTORY:
1398433d6423SLionel Sambuc 	ndirectory++;
1399433d6423SLionel Sambuc 	return chkdirectory(ino, ip);
1400433d6423SLionel Sambuc       case I_BLOCK_SPECIAL:
1401433d6423SLionel Sambuc 	nblkspec++;
1402433d6423SLionel Sambuc 	return chkspecial(ino, ip);
1403433d6423SLionel Sambuc       case I_CHAR_SPECIAL:
1404433d6423SLionel Sambuc 	ncharspec++;
1405433d6423SLionel Sambuc 	return chkspecial(ino, ip);
1406433d6423SLionel Sambuc       case I_NAMED_PIPE:
1407433d6423SLionel Sambuc 	npipe++;
1408433d6423SLionel Sambuc 	return chkfile(ino, ip);
1409433d6423SLionel Sambuc       case I_UNIX_SOCKET:
1410433d6423SLionel Sambuc 	nsock++;
1411433d6423SLionel Sambuc 	return chkfile(ino, ip);
1412433d6423SLionel Sambuc #ifdef I_SYMBOLIC_LINK
1413433d6423SLionel Sambuc       case I_SYMBOLIC_LINK:
1414433d6423SLionel Sambuc 	nsyml++;
1415433d6423SLionel Sambuc 	return chklink(ino, ip);
1416433d6423SLionel Sambuc #endif
1417433d6423SLionel Sambuc       default:
1418433d6423SLionel Sambuc 	nbadinode++;
1419433d6423SLionel Sambuc 	printf("bad mode of ");
1420433d6423SLionel Sambuc 	printpath(1, 0);
1421433d6423SLionel Sambuc 	printf("mode = %o)", ip->i_mode);
1422433d6423SLionel Sambuc 	return(0);
1423433d6423SLionel Sambuc   }
1424433d6423SLionel Sambuc }
1425433d6423SLionel Sambuc 
1426433d6423SLionel Sambuc /* Check an inode. */
chkinode(ino_t ino,d_inode * ip)1427433d6423SLionel Sambuc int chkinode(ino_t ino, d_inode *ip)
1428433d6423SLionel Sambuc {
1429433d6423SLionel Sambuc   if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
1430433d6423SLionel Sambuc 	printf("root inode is not a directory ");
1431*d0055759SDavid van Moolenbroek 	printf("(ino = %llu, mode = %o)\n", ino, ip->i_mode);
1432433d6423SLionel Sambuc 	fatal("");
1433433d6423SLionel Sambuc   }
1434433d6423SLionel Sambuc   if (ip->i_nlinks == 0) {
1435433d6423SLionel Sambuc 	printf("link count zero of ");
1436433d6423SLionel Sambuc 	printpath(2, 0);
1437433d6423SLionel Sambuc 	return(0);
1438433d6423SLionel Sambuc   }
1439433d6423SLionel Sambuc   nfreeinode--;
1440433d6423SLionel Sambuc   setbit(imap, (bit_nr) ino);
1441433d6423SLionel Sambuc   if ((unsigned) ip->i_nlinks > SHRT_MAX) {
1442433d6423SLionel Sambuc 	printf("link count too big in ");
1443433d6423SLionel Sambuc 	printpath(1, 0);
1444433d6423SLionel Sambuc 	printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
1445433d6423SLionel Sambuc 	count[ino] -= SHRT_MAX;
1446433d6423SLionel Sambuc 	setbit(spec_imap, (bit_nr) ino);
1447433d6423SLionel Sambuc   } else {
1448433d6423SLionel Sambuc 	count[ino] -= (unsigned) ip->i_nlinks;
1449433d6423SLionel Sambuc   }
1450433d6423SLionel Sambuc   return chkmode(ino, ip);
1451433d6423SLionel Sambuc }
1452433d6423SLionel Sambuc 
1453433d6423SLionel Sambuc /* Check the directory entry pointed to by dp, by checking the inode. */
descendtree(dp)1454433d6423SLionel Sambuc int descendtree(dp)
1455433d6423SLionel Sambuc dir_struct *dp;
1456433d6423SLionel Sambuc {
1457433d6423SLionel Sambuc   d_inode inode;
1458433d6423SLionel Sambuc   register ino_t ino = dp->d_inum;
1459433d6423SLionel Sambuc   register int visited;
1460433d6423SLionel Sambuc   struct stack stk;
1461433d6423SLionel Sambuc 
1462433d6423SLionel Sambuc   stk.st_dir = dp;
1463433d6423SLionel Sambuc   stk.st_next = ftop;
1464433d6423SLionel Sambuc   ftop = &stk;
1465433d6423SLionel Sambuc   if (bitset(spec_imap, (bit_nr) ino)) {
1466*d0055759SDavid van Moolenbroek 	printf("found inode %llu: ", ino);
1467433d6423SLionel Sambuc 	printpath(0, 1);
1468433d6423SLionel Sambuc   }
1469433d6423SLionel Sambuc   visited = bitset(imap, (bit_nr) ino);
1470433d6423SLionel Sambuc   if (!visited || listing) {
1471433d6423SLionel Sambuc 	devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
1472433d6423SLionel Sambuc 	if (listing) list(ino, &inode);
1473433d6423SLionel Sambuc 	if (!visited && !chkinode(ino, &inode)) {
1474433d6423SLionel Sambuc 		setbit(spec_imap, (bit_nr) ino);
1475433d6423SLionel Sambuc 		if (yes("remove")) {
1476433d6423SLionel Sambuc 			count[ino] += inode.i_nlinks - 1;
1477433d6423SLionel Sambuc 			clrbit(imap, (bit_nr) ino);
1478433d6423SLionel Sambuc 			devwrite(inoblock(ino), inooff(ino),
1479433d6423SLionel Sambuc 				nullbuf, INODE_SIZE);
1480433d6423SLionel Sambuc 			memset((void *) dp, 0, sizeof(dir_struct));
1481433d6423SLionel Sambuc 			ftop = ftop->st_next;
1482433d6423SLionel Sambuc 			return(0);
1483433d6423SLionel Sambuc 		}
1484433d6423SLionel Sambuc 	}
1485433d6423SLionel Sambuc   }
1486433d6423SLionel Sambuc   ftop = ftop->st_next;
1487433d6423SLionel Sambuc   return(1);
1488433d6423SLionel Sambuc }
1489433d6423SLionel Sambuc 
1490433d6423SLionel Sambuc /* Check the file system tree. */
chktree()1491433d6423SLionel Sambuc void chktree()
1492433d6423SLionel Sambuc {
1493433d6423SLionel Sambuc   dir_struct dir;
1494433d6423SLionel Sambuc 
1495433d6423SLionel Sambuc   nfreeinode = sb.s_ninodes;
1496433d6423SLionel Sambuc   nfreezone = N_DATA;
1497433d6423SLionel Sambuc   dir.d_inum = ROOT_INODE;
1498433d6423SLionel Sambuc   dir.mfs_d_name[0] = 0;
1499433d6423SLionel Sambuc   if (!descendtree(&dir)) fatal("bad root inode");
1500433d6423SLionel Sambuc   putchar('\n');
1501433d6423SLionel Sambuc }
1502433d6423SLionel Sambuc 
1503433d6423SLionel Sambuc /* Print the totals of all the objects found. */
printtotal()1504433d6423SLionel Sambuc void printtotal()
1505433d6423SLionel Sambuc {
1506433d6423SLionel Sambuc   if(preen) {
1507433d6423SLionel Sambuc   	printf("%d files, %d directories, %d free inodes, %ld free zones\n",
1508433d6423SLionel Sambuc 	  	nregular, ndirectory, nfreeinode, nfreezone);
1509433d6423SLionel Sambuc 	return;
1510433d6423SLionel Sambuc   }
1511433d6423SLionel Sambuc 
1512433d6423SLionel Sambuc   printf("blocksize = %5d        ", block_size);
1513433d6423SLionel Sambuc   printf("zonesize  = %5d\n", ZONE_SIZE);
1514433d6423SLionel Sambuc   printf("\n");
1515433d6423SLionel Sambuc   pr("%8u    Regular file%s\n", nregular, "", "s");
1516433d6423SLionel Sambuc   pr("%8u    Director%s\n", ndirectory, "y", "ies");
1517433d6423SLionel Sambuc   pr("%8u    Block special file%s\n", nblkspec, "", "s");
1518433d6423SLionel Sambuc   pr("%8u    Character special file%s\n", ncharspec, "", "s");
1519433d6423SLionel Sambuc   if (nbadinode != 0) pr("%6u    Bad inode%s\n", nbadinode, "", "s");
1520433d6423SLionel Sambuc   pr("%8u    Free inode%s\n", nfreeinode, "", "s");
1521433d6423SLionel Sambuc   pr("%8u    Named pipe%s\n", npipe, "", "s");
1522433d6423SLionel Sambuc   pr("%8u    Unix socket%s\n", nsock, "", "s");
1523433d6423SLionel Sambuc   pr("%8u    Symbolic link%s\n", nsyml, "", "s");
1524433d6423SLionel Sambuc /* Don't print some fields.
1525433d6423SLionel Sambuc   printf("\n");
1526433d6423SLionel Sambuc   pr("%8u    Data zone%s\n",		  ztype[0],	 "",   "s");
1527433d6423SLionel Sambuc   pr("%8u    Single indirect zone%s\n",	  ztype[1],	 "",   "s");
1528433d6423SLionel Sambuc   pr("%8u    Double indirect zone%s\n",	  ztype[2],	 "",   "s");
1529433d6423SLionel Sambuc */
1530433d6423SLionel Sambuc   lpr("%8ld    Free zone%s\n", nfreezone, "", "s");
1531433d6423SLionel Sambuc }
1532433d6423SLionel Sambuc 
1533433d6423SLionel Sambuc /* Check the device which name is given by `f'.  The inodes listed by `clist'
1534433d6423SLionel Sambuc  * should be listed separately, and the inodes listed by `ilist' and the zones
1535433d6423SLionel Sambuc  * listed by `zlist' should be watched for while checking the file system.
1536433d6423SLionel Sambuc  */
1537433d6423SLionel Sambuc 
chkdev(f,clist,ilist,zlist)1538433d6423SLionel Sambuc void chkdev(f, clist, ilist, zlist)
1539433d6423SLionel Sambuc char *f, **clist, **ilist, **zlist;
1540433d6423SLionel Sambuc {
1541433d6423SLionel Sambuc   if (automatic) repair = 1;
1542433d6423SLionel Sambuc   fsck_device = f;
1543433d6423SLionel Sambuc   initvars();
1544433d6423SLionel Sambuc 
1545433d6423SLionel Sambuc   devopen();
1546433d6423SLionel Sambuc 
1547433d6423SLionel Sambuc   rw_super(SUPER_GET);
1548433d6423SLionel Sambuc 
1549433d6423SLionel Sambuc   if(block_size < SUPER_BLOCK_BYTES)
1550433d6423SLionel Sambuc   	fatal("funny block size");
1551433d6423SLionel Sambuc 
1552433d6423SLionel Sambuc   if(!(rwbuf = malloc(block_size))) fatal("couldn't allocate fs buf (1)");
1553433d6423SLionel Sambuc   if(!(nullbuf = malloc(block_size))) fatal("couldn't allocate fs buf (2)");
1554433d6423SLionel Sambuc   memset(nullbuf, 0, block_size);
1555433d6423SLionel Sambuc 
1556433d6423SLionel Sambuc   chksuper();
1557433d6423SLionel Sambuc 
1558433d6423SLionel Sambuc   if(markdirty) {
1559433d6423SLionel Sambuc   	if(sb.s_flags & MFSFLAG_CLEAN) {
1560433d6423SLionel Sambuc 	  	sb.s_flags &= ~MFSFLAG_CLEAN;
1561433d6423SLionel Sambuc   		rw_super(SUPER_PUT);
1562433d6423SLionel Sambuc   		printf("\n----- FILE SYSTEM MARKED DIRTY -----\n\n");
1563433d6423SLionel Sambuc 	} else {
1564433d6423SLionel Sambuc   		printf("Filesystem is already dirty.\n");
1565433d6423SLionel Sambuc 	}
1566433d6423SLionel Sambuc   }
1567433d6423SLionel Sambuc 
1568433d6423SLionel Sambuc   /* If preening, skip fsck if clean flag is on. */
1569433d6423SLionel Sambuc   if(preen) {
1570433d6423SLionel Sambuc   	if(sb.s_flags & MFSFLAG_CLEAN) {
1571433d6423SLionel Sambuc 	  	printf("%s: clean\n", f);
1572433d6423SLionel Sambuc 		return;
1573433d6423SLionel Sambuc 	}
1574433d6423SLionel Sambuc 	printf("%s: dirty, performing fsck\n", f);
1575433d6423SLionel Sambuc   }
1576433d6423SLionel Sambuc 
1577433d6423SLionel Sambuc   lsi(clist);
1578433d6423SLionel Sambuc 
1579433d6423SLionel Sambuc   getbitmaps();
1580433d6423SLionel Sambuc 
1581433d6423SLionel Sambuc   fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
1582433d6423SLionel Sambuc   fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_zones, zlist);
1583433d6423SLionel Sambuc 
1584433d6423SLionel Sambuc   getcount();
1585433d6423SLionel Sambuc   chktree();
1586433d6423SLionel Sambuc   chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, "zone");
1587433d6423SLionel Sambuc   chkcount();
1588433d6423SLionel Sambuc   chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
1589433d6423SLionel Sambuc   chkilist();
1590433d6423SLionel Sambuc   if(preen) printf("\n");
1591433d6423SLionel Sambuc   printtotal();
1592433d6423SLionel Sambuc 
1593433d6423SLionel Sambuc   putbitmaps();
1594433d6423SLionel Sambuc   freecount();
1595433d6423SLionel Sambuc 
1596433d6423SLionel Sambuc   if (changed) printf("\n----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
1597433d6423SLionel Sambuc 
1598433d6423SLionel Sambuc   /* If we were told to repair the FS, and the user never stopped us from
1599433d6423SLionel Sambuc    * doing it, and the FS wasn't marked clean, we can mark the FS as clean.
1600433d6423SLionel Sambuc    * If we were stopped from repairing, tell user about it.
1601433d6423SLionel Sambuc    */
1602433d6423SLionel Sambuc   if(repair && !(sb.s_flags & MFSFLAG_CLEAN)) {
1603433d6423SLionel Sambuc   	if(notrepaired) {
1604433d6423SLionel Sambuc   		printf("\n----- FILE SYSTEM STILL DIRTY -----\n\n");
1605433d6423SLionel Sambuc 	} else {
1606433d6423SLionel Sambuc 		sync();	/* update FS on disk before clean flag */
1607433d6423SLionel Sambuc 	  	sb.s_flags |= MFSFLAG_CLEAN;
1608433d6423SLionel Sambuc   		rw_super(SUPER_PUT);
1609433d6423SLionel Sambuc   		printf("\n----- FILE SYSTEM MARKED CLEAN -----\n\n");
1610433d6423SLionel Sambuc 	}
1611433d6423SLionel Sambuc   }
1612433d6423SLionel Sambuc 
1613433d6423SLionel Sambuc   devclose();
1614433d6423SLionel Sambuc }
1615433d6423SLionel Sambuc 
main(argc,argv)1616433d6423SLionel Sambuc int main(argc, argv)
1617433d6423SLionel Sambuc int argc;
1618433d6423SLionel Sambuc char **argv;
1619433d6423SLionel Sambuc {
1620433d6423SLionel Sambuc   register char **clist = 0, **ilist = 0, **zlist = 0;
1621433d6423SLionel Sambuc   int badflag = 0;
1622433d6423SLionel Sambuc 
1623433d6423SLionel Sambuc   register int devgiven = 0;
1624433d6423SLionel Sambuc   register char *arg;
1625433d6423SLionel Sambuc 
1626433d6423SLionel Sambuc   if ((1 << BITSHIFT) != 8 * sizeof(bitchunk_t)) {
1627433d6423SLionel Sambuc 	printf("Fsck was compiled with the wrong BITSHIFT!\n");
1628433d6423SLionel Sambuc 	exit(FSCK_EXIT_CHECK_FAILED);
1629433d6423SLionel Sambuc   }
1630433d6423SLionel Sambuc 
1631433d6423SLionel Sambuc   sync();
1632433d6423SLionel Sambuc   prog = *argv++;
1633433d6423SLionel Sambuc   while ((arg = *argv++) != 0)
1634433d6423SLionel Sambuc 	if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
1635433d6423SLionel Sambuc 		    case 'd':	markdirty = 1;	break;
1636433d6423SLionel Sambuc 		    case 'p':	preen = repair = automatic = 1; break;
1637433d6423SLionel Sambuc 	            case 'y':
1638433d6423SLionel Sambuc 		    case 'a':	automatic ^= 1;	break;
1639433d6423SLionel Sambuc 		    case 'c':
1640433d6423SLionel Sambuc 			clist = getlist(&argv, "inode");
1641433d6423SLionel Sambuc 			break;
1642433d6423SLionel Sambuc 		    case 'i':
1643433d6423SLionel Sambuc 			ilist = getlist(&argv, "inode");
1644433d6423SLionel Sambuc 			break;
1645433d6423SLionel Sambuc 		    case 'z':
1646433d6423SLionel Sambuc 			zlist = getlist(&argv, "zone");
1647433d6423SLionel Sambuc 			break;
1648433d6423SLionel Sambuc 		    case 'r':	repair ^= 1;	break;
1649433d6423SLionel Sambuc 		    case 'l':	listing ^= 1;	break;
1650433d6423SLionel Sambuc 		    case 's':	listsuper ^= 1;	break;
1651433d6423SLionel Sambuc 		    case 'f':	break;
1652433d6423SLionel Sambuc 		    default:
1653433d6423SLionel Sambuc 			printf("%s: unknown flag '%s'\n", prog, arg);
1654433d6423SLionel Sambuc 			badflag = 1;
1655433d6423SLionel Sambuc 		}
1656433d6423SLionel Sambuc 	else {
1657433d6423SLionel Sambuc 		chkdev(arg, clist, ilist, zlist);
1658433d6423SLionel Sambuc 		clist = 0;
1659433d6423SLionel Sambuc 		ilist = 0;
1660433d6423SLionel Sambuc 		zlist = 0;
1661433d6423SLionel Sambuc 		devgiven = 1;
1662433d6423SLionel Sambuc 	}
1663433d6423SLionel Sambuc   if (!devgiven || badflag) {
1664433d6423SLionel Sambuc 	printf("Usage: fsck [-dyfpacilrsz] file\n");
1665433d6423SLionel Sambuc 	exit(FSCK_EXIT_USAGE);
1666433d6423SLionel Sambuc   }
1667433d6423SLionel Sambuc   return(0);
1668433d6423SLionel Sambuc }
1669433d6423SLionel Sambuc 
panic(char * fmt,...)1670433d6423SLionel Sambuc void panic(char *fmt, ...)
1671433d6423SLionel Sambuc {
1672433d6423SLionel Sambuc 	fprintf(stderr, "%s\n", fmt);
1673433d6423SLionel Sambuc 	exit(1);
1674433d6423SLionel Sambuc }
1675433d6423SLionel Sambuc 
1676