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