xref: /illumos-gate/usr/src/cmd/fs.d/udfs/fsck/setup.c (revision 8459c777fc1aaabb2f7dad05de1313aa169417cd)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved	*/
8 
9 /*
10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by the University of California, Berkeley and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #define	DKTYPENAMES
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <ustat.h>
34 #include <errno.h>
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/sysmacros.h>
38 #include <sys/mntent.h>
39 #include <sys/mnttab.h>
40 #include <sys/dkio.h>
41 #include <sys/filio.h>
42 #include <sys/isa_defs.h>	/* for ENDIAN defines */
43 #include <sys/int_const.h>
44 #include <sys/vnode.h>
45 #include <sys/stat.h>
46 #include <sys/file.h>
47 #include <sys/fcntl.h>
48 #include <string.h>
49 #include <sys/vfstab.h>
50 #include <sys/fs/udf_volume.h>
51 #include <sys/vtoc.h>
52 #include <locale.h>
53 
54 #include "fsck.h"
55 
56 extern void	errexit(char *, ...);
57 extern int32_t	mounted(char *);
58 extern void	pwarn(char *, ...);
59 extern void	pfatal(char *, ...);
60 extern void	printclean();
61 extern void	bufinit();
62 extern void	ckfini();
63 extern int32_t	bread(int32_t, char *, daddr_t, long);
64 extern int32_t	reply(char *);
65 
66 static int32_t	readvolseq(int32_t);
67 static uint32_t	get_last_block();
68 extern int32_t	verifytag(struct tag *, uint32_t, struct tag *, int);
69 extern char	*tagerrs[];
70 
71 #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
72 
73 extern int	mflag;
74 long fsbsize;
75 static char hotroot;	/* checking root device */
76 char *freemap;
77 char *busymap;
78 uint32_t part_start;
79 uint32_t lvintlen;
80 uint32_t lvintblock;
81 uint32_t rootblock;
82 uint32_t rootlen;
83 uint32_t part_bmp_bytes;
84 uint32_t part_bmp_sectors;
85 uint32_t part_bmp_loc;
86 int fsreadfd;
87 int fswritefd;
88 long secsize;
89 long numdirs, numfiles, listmax;
90 struct fileinfo *inphead, **inphash, *inpnext, *inplast;
91 struct space_bmap_desc *spacep;
92 static struct unall_desc *unallp;
93 static struct pri_vol_desc *pvolp;
94 static struct part_desc *partp;
95 static struct phdr_desc *pheadp;
96 static struct log_vol_desc *logvp;
97 struct lvid_iu *lviup;
98 static struct vdp_desc *volp;
99 static struct anch_vol_desc_ptr *avdp;
100 static struct iuvd_desc *iudp;
101 
102 char avdbuf[MAXBSIZE];		/* buffer for anchor volume descriptor */
103 char *main_vdbuf;		/* buffer for entire main volume sequence */
104 char *res_vdbuf;		/* buffer for reserved volume sequence */
105 int serialnum = -1;		/* set from primary volume descriptor */
106 
107 char *
108 setup(char *dev)
109 {
110 	dev_t rootdev;
111 	struct stat statb;
112 	static char devstr[MAXPATHLEN];
113 	char *raw, *rawname(), *unrawname();
114 	struct ustat ustatb;
115 
116 	if (stat("/", &statb) < 0)
117 		errexit(gettext("Can't stat root\n"));
118 	rootdev = statb.st_dev;
119 
120 	devname = devstr;
121 	(void) strncpy(devstr, dev, sizeof (devstr));
122 restat:
123 	if (stat(devstr, &statb) < 0) {
124 		(void) printf(gettext("Can't stat %s\n"), devstr);
125 		exitstat = 34;
126 		return (0);
127 	}
128 	/*
129 	 * A mount point is specified. But the mount point doesn't
130 	 * match entries in the /etc/vfstab.
131 	 * Search mnttab, because if the fs is error locked, it is
132 	 * allowed to be fsck'd while mounted.
133 	 */
134 	if ((statb.st_mode & S_IFMT) == S_IFDIR) {
135 		(void) printf(gettext("%s is not a block or "
136 			"character device\n"), dev);
137 		return (0);
138 	}
139 
140 	if ((statb.st_mode & S_IFMT) == S_IFBLK) {
141 		if (rootdev == statb.st_rdev)
142 			hotroot++;
143 		else if (ustat(statb.st_rdev, &ustatb) == 0) {
144 			(void) printf(gettext("%s is a mounted file system, "
145 				"ignored\n"), dev);
146 			exitstat = 33;
147 			return (0);
148 		}
149 	}
150 	if ((statb.st_mode & S_IFMT) == S_IFDIR) {
151 		FILE *vfstab;
152 		struct vfstab vfsbuf;
153 		/*
154 		 * Check vfstab for a mount point with this name
155 		 */
156 		if ((vfstab = fopen(VFSTAB, "r")) == NULL) {
157 			errexit(gettext("Can't open checklist file: %s\n"),
158 				VFSTAB);
159 		}
160 		while (getvfsent(vfstab, &vfsbuf) == 0) {
161 			if (strcmp(devstr, vfsbuf.vfs_mountp) == 0) {
162 				if (strcmp(vfsbuf.vfs_fstype,
163 				    MNTTYPE_UDFS) != 0) {
164 					/*
165 					 * found the entry but it is not a
166 					 * udfs filesystem, don't check it
167 					 */
168 					(void) fclose(vfstab);
169 					return (0);
170 				}
171 				(void) strcpy(devstr, vfsbuf.vfs_special);
172 				if (rflag) {
173 					raw = rawname(
174 					    unrawname(vfsbuf.vfs_special));
175 					(void) strcpy(devstr, raw);
176 				}
177 				goto restat;
178 			}
179 		}
180 		(void) fclose(vfstab);
181 
182 	} else if (((statb.st_mode & S_IFMT) != S_IFBLK) &&
183 	    ((statb.st_mode & S_IFMT) != S_IFCHR)) {
184 		if (preen)
185 			pwarn(gettext("file is not a block or "
186 				"character device.\n"));
187 		else if (reply(gettext("file is not a block or "
188 				"character device; OK"))
189 		    == 0)
190 			return (0);
191 		/*
192 		 * To fsck regular files (fs images)
193 		 * we need to clear the rflag since
194 		 * regular files don't have raw names.  --CW
195 		 */
196 		rflag = 0;
197 	}
198 
199 	if (mounted(devstr)) {
200 		if (rflag)
201 			mountedfs++;
202 		else {
203 			(void) printf(gettext("%s is mounted, fsck on BLOCK "
204 				"device ignored\n"), devstr);
205 			exit(33);
206 		}
207 		sync();	/* call sync, only when devstr's mounted */
208 	}
209 	if (rflag) {
210 		char blockname[MAXPATHLEN];
211 		/*
212 		 * For root device check, must check
213 		 * block devices.
214 		 */
215 		(void) strcpy(blockname, devstr);
216 		if (stat(unrawname(blockname), &statb) < 0) {
217 			(void) printf(gettext("Can't stat %s\n"), blockname);
218 			exitstat = 34;
219 			return (0);
220 		}
221 	}
222 	if (rootdev == statb.st_rdev)
223 		hotroot++;
224 	if ((fsreadfd = open(devstr, O_RDONLY)) < 0) {
225 		(void) printf(gettext("Can't open %s\n"), devstr);
226 		exitstat = 34;
227 		return (0);
228 	}
229 	if (preen == 0 || debug != 0)
230 		(void) printf("** %s", devstr);
231 
232 	if (nflag || (fswritefd = open(devstr, O_WRONLY)) < 0) {
233 		fswritefd = -1;
234 		if (preen && !debug)
235 			pfatal(gettext("(NO WRITE ACCESS)\n"));
236 		(void) printf(gettext(" (NO WRITE)"));
237 	}
238 	if (preen == 0)
239 		(void) printf("\n");
240 	if (debug && (hotroot || mountedfs)) {
241 		(void) printf("** %s", devstr);
242 		if (hotroot)
243 			(void) printf(" is root fs%s",
244 				mountedfs? " and": "");
245 		if (mountedfs)
246 			(void) printf(" is mounted");
247 
248 		(void) printf(".\n");
249 	}
250 	fsmodified = 0;
251 	if (readvolseq(1) == 0)
252 		return (0);
253 	if (fflag == 0 && preen &&
254 		lvintp->lvid_int_type == LVI_CLOSE) {
255 		iscorrupt = 0;
256 		printclean();
257 		return (0);
258 	}
259 	listmax = FEGROW;
260 	inphash = (struct fileinfo **)calloc(FEGROW,
261 			sizeof (struct fileinfo *));
262 	inphead = (struct fileinfo *)calloc(FEGROW + 1,
263 			sizeof (struct fileinfo));
264 	if (inphead == NULL || inphash == NULL) {
265 		(void) printf(gettext("cannot alloc %ld bytes for inphead\n"),
266 			listmax * sizeof (struct fileinfo));
267 		goto badsb;
268 	}
269 	inpnext = inphead;
270 	inplast = &inphead[listmax];
271 
272 	bufinit();
273 	return (devstr);
274 
275 badsb:
276 	ckfini();
277 	exitstat = 39;
278 	return (0);
279 }
280 
281 static int
282 check_pri_vol_desc(struct tag *tp)
283 {
284 	pvolp = (struct pri_vol_desc *)tp;
285 	return (0);
286 }
287 
288 static int
289 check_avdp(struct tag *tp)
290 {
291 	avdp = (struct anch_vol_desc_ptr *)tp;
292 	return (0);
293 }
294 
295 static int
296 check_vdp(struct tag *tp)
297 {
298 	volp = (struct vdp_desc *)tp;
299 	return (0);
300 }
301 
302 static int
303 check_iuvd(struct tag *tp)
304 {
305 	iudp = (struct iuvd_desc *)tp;
306 	return (0);
307 }
308 
309 static int
310 check_part_desc(struct tag *tp)
311 {
312 	partp = (struct part_desc *)tp;
313 	/* LINTED */
314 	pheadp = (struct phdr_desc *)&partp->pd_pc_use;
315 	part_start = partp->pd_part_start;
316 	part_len = partp->pd_part_length;
317 	if (debug)
318 		(void) printf("partition start %x len %x\n", part_start,
319 			part_len);
320 	return (0);
321 }
322 
323 static int
324 check_log_desc(struct tag *tp)
325 {
326 	logvp = (struct log_vol_desc *)tp;
327 	return (0);
328 }
329 
330 static int
331 check_unall_desc(struct tag *tp)
332 {
333 	unallp = (struct unall_desc *)tp;
334 	return (0);
335 }
336 
337 /* ARGSUSED */
338 static int
339 check_term_desc(struct tag *tp)
340 {
341 	return (0);
342 }
343 
344 static int
345 check_lvint(struct tag *tp)
346 {
347 	/* LINTED */
348 	lvintp = (struct log_vol_int_desc *)tp;
349 	return (0);
350 }
351 
352 void
353 dump16(char *cp, char *nl)
354 {
355 	int i;
356 	long *ptr;
357 
358 
359 	for (i = 0; i < 16; i += 4) {
360 		/* LINTED */
361 		ptr = (long *)(cp + i);
362 		(void) printf("%08lx ", *ptr);
363 	}
364 	(void) printf(nl);
365 }
366 
367 /*
368  * Read in the super block and its summary info.
369  */
370 /* ARGSUSED */
371 static int
372 readvolseq(int32_t listerr)
373 {
374 	struct tag *tp;
375 	long_ad_t *lap;
376 	struct anch_vol_desc_ptr *avp;
377 	uint8_t *cp, *end;
378 	daddr_t nextblock;
379 	int err;
380 	long	freelen;
381 	daddr_t avdp;
382 	struct file_set_desc *fileset;
383 	uint32_t filesetblock;
384 	uint32_t filesetlen;
385 
386 	if (debug)
387 		(void) printf("Disk partition size: %x\n", get_last_block());
388 
389 	/* LINTED */
390 	avp = (struct anch_vol_desc_ptr *)avdbuf;
391 	tp = &avp->avd_tag;
392 	for (fsbsize = 512; fsbsize <= MAXBSIZE; fsbsize <<= 1) {
393 		avdp = FIRSTAVDP * fsbsize / DEV_BSIZE;
394 		if (bread(fsreadfd, avdbuf, avdp, fsbsize) != 0)
395 			return (0);
396 		err = verifytag(tp, FIRSTAVDP, tp, UD_ANCH_VOL_DESC);
397 		if (debug)
398 			(void) printf("bsize %ld tp->tag %d, %s\n", fsbsize,
399 				tp->tag_id, tagerrs[err]);
400 		if (err == 0)
401 			break;
402 	}
403 	if (fsbsize > MAXBSIZE)
404 		errexit(gettext("Can't find anchor volume descriptor\n"));
405 	secsize = fsbsize;
406 	if (debug)
407 		(void) printf("fsbsize = %ld\n", fsbsize);
408 	main_vdbuf = malloc(avp->avd_main_vdse.ext_len);
409 	res_vdbuf = malloc(avp->avd_res_vdse.ext_len);
410 	if (main_vdbuf == NULL || res_vdbuf == NULL)
411 		errexit("cannot allocate space for volume sequences\n");
412 	if (debug)
413 		(void) printf("reading volume sequences "
414 			"(%d bytes at %x and %x)\n",
415 			avp->avd_main_vdse.ext_len, avp->avd_main_vdse.ext_loc,
416 			avp->avd_res_vdse.ext_loc);
417 	if (bread(fsreadfd, main_vdbuf, fsbtodb(avp->avd_main_vdse.ext_loc),
418 		avp->avd_main_vdse.ext_len) != 0)
419 		return (0);
420 	if (bread(fsreadfd, res_vdbuf, fsbtodb(avp->avd_res_vdse.ext_loc),
421 		avp->avd_res_vdse.ext_len) != 0)
422 		return (0);
423 	end = (uint8_t *)main_vdbuf + avp->avd_main_vdse.ext_len;
424 	nextblock = avp->avd_main_vdse.ext_loc;
425 	for (cp = (uint8_t *)main_vdbuf; cp < end; cp += fsbsize, nextblock++) {
426 		/* LINTED */
427 		tp = (struct tag *)cp;
428 		err = verifytag(tp, nextblock, tp, 0);
429 		if (debug) {
430 			dump16((char *)cp, "");
431 			(void) printf("blk %lx err %s tag %d\n", nextblock,
432 				tagerrs[err], tp->tag_id);
433 		}
434 		if (err == 0) {
435 			if (serialnum >= 0 && tp->tag_sno != serialnum) {
436 				(void) printf(gettext("serial number mismatch "
437 					"tag type %d, block %lx\n"), tp->tag_id,
438 					nextblock);
439 				continue;
440 			}
441 			switch (tp->tag_id) {
442 			case UD_PRI_VOL_DESC:
443 				serialnum = tp->tag_sno;
444 				if (debug) {
445 					(void) printf("serial number = %d\n",
446 						serialnum);
447 				}
448 				err = check_pri_vol_desc(tp);
449 				break;
450 			case UD_ANCH_VOL_DESC:
451 				err = check_avdp(tp);
452 				break;
453 			case UD_VOL_DESC_PTR:
454 				err = check_vdp(tp);
455 				break;
456 			case UD_IMPL_USE_DESC:
457 				err = check_iuvd(tp);
458 				break;
459 			case UD_PART_DESC:
460 				err = check_part_desc(tp);
461 				break;
462 			case UD_LOG_VOL_DESC:
463 				err = check_log_desc(tp);
464 				break;
465 			case UD_UNALL_SPA_DESC:
466 				err = check_unall_desc(tp);
467 				break;
468 			case UD_TERM_DESC:
469 				err = check_term_desc(tp);
470 				goto done;
471 				break;
472 			case UD_LOG_VOL_INT:
473 				err = check_lvint(tp);
474 				break;
475 			default:
476 				(void) printf(gettext("Invalid volume "
477 					"sequence tag %d\n"), tp->tag_id);
478 			}
479 		} else {
480 			(void) printf(gettext("Volume sequence tag error %s\n"),
481 				tagerrs[err]);
482 		}
483 	}
484 done:
485 	if (!partp || !logvp) {
486 		(void) printf(gettext("Missing partition header or"
487 			" logical volume descriptor\n"));
488 		return (0);
489 	}
490 
491 	/* Get the logical volume integrity descriptor */
492 	lvintblock = logvp->lvd_int_seq_ext.ext_loc;
493 	lvintlen = logvp->lvd_int_seq_ext.ext_len;
494 	lvintp = (struct log_vol_int_desc *)malloc(lvintlen);
495 	if (debug)
496 		(void) printf("Logvolint at %x for %d bytes\n", lvintblock,
497 			lvintlen);
498 	if (lvintp == NULL) {
499 		(void) printf(gettext("Can't allocate space for logical"
500 			" volume integrity sequence\n"));
501 		return (0);
502 	}
503 	if (bread(fsreadfd, (char *)lvintp,
504 			fsbtodb(lvintblock), lvintlen) != 0) {
505 		return (0);
506 	}
507 	err = verifytag(&lvintp->lvid_tag, lvintblock, &lvintp->lvid_tag,
508 		UD_LOG_VOL_INT);
509 	if (debug) {
510 		dump16((char *)lvintp, "\n");
511 	}
512 	if (err) {
513 		(void) printf(gettext("Log_vol_int tag error: %s, tag = %d\n"),
514 			tagerrs[err], lvintp->lvid_tag.tag_id);
515 		return (0);
516 	}
517 
518 	/* Get pointer to implementation use area */
519 	lviup = (struct lvid_iu *)&lvintp->lvid_fst[lvintp->lvid_npart*2];
520 	if (debug) {
521 		(void) printf("free space %d total %d ", lvintp->lvid_fst[0],
522 			lvintp->lvid_fst[1]);
523 	(void) printf(gettext("nfiles %d ndirs %d\n"), lviup->lvidiu_nfiles,
524 			lviup->lvidiu_ndirs);
525 	}
526 
527 	/* Set up free block map and read in the existing free space map */
528 	freelen = pheadp->phdr_usb.sad_ext_len;
529 	if (freelen == 0) {
530 		(void) printf(gettext("No partition free map\n"));
531 	}
532 	part_bmp_bytes = (part_len + NBBY - 1) / NBBY;
533 	busymap = calloc((unsigned)part_bmp_bytes, sizeof (char));
534 	if (busymap == NULL) {
535 		(void) printf(gettext("Can't allocate free block bitmap\n"));
536 		return (0);
537 	}
538 	if (freelen) {
539 		part_bmp_sectors =
540 			(part_bmp_bytes + SPACEMAP_OFF + secsize - 1) /
541 			secsize;
542 		part_bmp_loc = pheadp->phdr_usb.sad_ext_loc + part_start;
543 
544 		/* Mark the partition map blocks busy */
545 		markbusy(pheadp->phdr_usb.sad_ext_loc,
546 			part_bmp_sectors * secsize);
547 
548 		spacep = (struct space_bmap_desc *)
549 			malloc(secsize*part_bmp_sectors);
550 		if (spacep == NULL) {
551 			(void) printf(gettext("Can't allocate partition "
552 				"map\n"));
553 			return (0);
554 		}
555 		if (bread(fsreadfd, (char *)spacep, fsbtodb(part_bmp_loc),
556 			part_bmp_sectors * secsize) != 0)
557 			return (0);
558 		cp = (uint8_t *)spacep;
559 		err = verifytag(&spacep->sbd_tag, pheadp->phdr_usb.sad_ext_loc,
560 			&spacep->sbd_tag, UD_SPA_BMAP_DESC);
561 		if (debug) {
562 			dump16((char *)cp, "");
563 			(void) printf("blk %x err %s tag %d\n", part_bmp_loc,
564 				tagerrs[err], spacep->sbd_tag.tag_id);
565 		}
566 		freemap = (char *)cp + SPACEMAP_OFF;
567 		if (debug)
568 			(void) printf("err %s tag %x space bitmap at %x"
569 				" length %d nbits %d nbytes %d\n",
570 				tagerrs[err], spacep->sbd_tag.tag_id,
571 				part_bmp_loc, part_bmp_sectors,
572 				spacep->sbd_nbits, spacep->sbd_nbytes);
573 		if (err) {
574 			(void) printf(gettext("Space bitmap tag error, %s, "
575 				"tag = %d\n"),
576 				tagerrs[err], spacep->sbd_tag.tag_id);
577 			return (0);
578 		}
579 	}
580 
581 	/* Get the fileset descriptor */
582 	lap = (long_ad_t *)&logvp->lvd_lvcu;
583 	filesetblock = lap->lad_ext_loc;
584 	filesetlen = lap->lad_ext_len;
585 	markbusy(filesetblock, filesetlen);
586 	if (debug)
587 		(void) printf("Fileset descriptor at %x for %d bytes\n",
588 			filesetblock, filesetlen);
589 	if (!filesetlen) {
590 		(void) printf(gettext("No file set descriptor found\n"));
591 		return (0);
592 	}
593 	fileset = (struct file_set_desc *)malloc(filesetlen);
594 	if (fileset == NULL) {
595 		(void) printf(gettext("Unable to allocate fileset\n"));
596 		return (0);
597 	}
598 	if (bread(fsreadfd, (char *)fileset, fsbtodb(filesetblock + part_start),
599 		filesetlen) != 0) {
600 		return (0);
601 	}
602 	err = verifytag(&fileset->fsd_tag, filesetblock, &fileset->fsd_tag,
603 		UD_FILE_SET_DESC);
604 	if (err) {
605 		(void) printf(gettext("Fileset tag error, tag = %d, %s\n"),
606 			fileset->fsd_tag.tag_id, tagerrs[err]);
607 		return (0);
608 	}
609 
610 	/* Get the address of the root file entry */
611 	lap = (long_ad_t *)&fileset->fsd_root_icb;
612 	rootblock = lap->lad_ext_loc;
613 	rootlen = lap->lad_ext_len;
614 	if (debug)
615 		(void) printf("Root at %x for %d bytes\n", rootblock, rootlen);
616 
617 	return (1);
618 }
619 
620 uint32_t
621 get_last_block()
622 {
623 	struct vtoc vtoc;
624 	struct dk_cinfo dki_info;
625 
626 	if (ioctl(fsreadfd, DKIOCGVTOC, (intptr_t)&vtoc) != 0) {
627 		(void) fprintf(stderr, gettext("Unable to read VTOC\n"));
628 		return (0);
629 	}
630 
631 	if (vtoc.v_sanity != VTOC_SANE) {
632 		(void) fprintf(stderr, gettext("Vtoc.v_sanity != VTOC_SANE\n"));
633 		return (0);
634 	}
635 
636 	if (ioctl(fsreadfd, DKIOCINFO, (intptr_t)&dki_info) != 0) {
637 		(void) fprintf(stderr,
638 		    gettext("Could not get the slice information\n"));
639 		return (0);
640 	}
641 
642 	if (dki_info.dki_partition > V_NUMPAR) {
643 		(void) fprintf(stderr,
644 		    gettext("dki_info.dki_partition > V_NUMPAR\n"));
645 		return (0);
646 	}
647 
648 	return ((uint32_t)vtoc.v_part[dki_info.dki_partition].p_size);
649 }
650