1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
27/*	  All Rights Reserved  	*/
28
29/*
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
32 */
33
34/*
35 * make file system for udfs (UDF - ISO13346)
36 *
37 * usage:
38 *
39 *    mkfs [-F FSType] [-V] [-m] [options]
40 *	[-o specific_options]  special size
41 *
42 *  where specific_options are:
43 *	N - no create
44 *	label - volume label
45 *	psize - physical block size
46 */
47
48#include	<stdio.h>
49#include	<strings.h>
50#include	<string.h>
51#include	<stdlib.h>
52#include	<unistd.h>
53#include	<time.h>
54#include	<locale.h>
55#include	<fcntl.h>
56#include	<errno.h>
57#include	<limits.h>
58#include	<sys/mnttab.h>
59#include	<sys/param.h>
60#include	<sys/types.h>
61#include	<sys/sysmacros.h>
62#include	<sys/vnode.h>
63#include	<sys/mntent.h>
64#include	<sys/filio.h>
65#include	<sys/stat.h>
66#include	<ustat.h>
67#include 	<sys/isa_defs.h>	/* for ENDIAN defines */
68#include	<sys/dkio.h>
69#include	<sys/fdio.h>
70#include	<sys/vtoc.h>
71#include	<sys/fs/udf_volume.h>
72
73extern char	*getfullrawname(char *);
74extern char	*getfullblkname(char *);
75extern struct tm *localtime_r(const time_t *, struct tm *);
76extern void	maketag(struct tag *, struct tag *);
77extern int	verifytag(struct tag *, uint32_t, struct tag *, int);
78extern void	setcharspec(struct charspec *, int32_t, uint8_t *);
79
80
81#define	UMASK		0755
82#define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
83#define	MB		(1024*1024)
84
85/*
86 * Forward declarations
87 */
88static void rdfs(daddr_t bno, int size, char *bf);
89static void wtfs(daddr_t bno, int size, char *bf);
90static void dump_fscmd(char *fsys, int fsi);
91static int32_t number(long big, char *param);
92static void usage();
93static int match(char *s);
94static int readvolseq();
95static uint32_t get_last_block();
96
97/*
98 * variables set up by front end.
99 */
100static int	Nflag = 0;		/* run mkfs without writing */
101					/* file system */
102static int	mflag = 0;		/* return the command line used */
103					/* to create this FS */
104static int	fssize;			/* file system size */
105static uint32_t	disk_size;		/* partition size from VTOC */
106static uint32_t unused;			/* unused sectors in partition */
107static int	sectorsize = 2048;	/* bytes/sector default */
108					/* If nothing specified */
109
110static char	*fsys;
111static int	fsi;
112static int	fso;
113
114#define	BIG	LONG_MAX
115static	uint32_t	number_flags = 0;
116
117static char	*string;
118
119static void	setstamp(tstamp_t *);
120static void	setextad(extent_ad_t *, uint32_t, uint32_t);
121static void	setdstring(dstring_t *, char *, int32_t);
122static void	wtvolseq(tag_t *, daddr_t, daddr_t);
123static void	volseqinit();
124static void	setstamp(tstamp_t *);
125static uint32_t	get_bsize();
126
127
128#define	VOLRECSTART	(32 * 1024)
129
130#define	VOLSEQSTART	128
131#define	VOLSEQLEN	16
132#define	INTSEQSTART	192
133#define	INTSEQLEN	8192
134#define	FIRSTAVDP	256
135#define	AVDPLEN		1
136
137
138#define	FILESETLEN	2
139
140#define	SPACEMAP_OFF	24
141#define	MAXID		16
142
143static time_t mkfstime;
144static struct tm res;
145static long tzone;
146static char vsibuf[128];
147
148static regid_t sunmicro = { 0, "*SUN SOLARIS UDF", 4, 2 };
149static regid_t lvinfo = { 0, "*UDF LV Info", 0x50, 0x1, 4, 2 };
150static regid_t partid = { 0, "+NSR02", 0 };
151static regid_t udf_compliant = { 0, "*OSTA UDF Compliant", 0x50, 0x1, 0 };
152static uint8_t osta_unicode[] = "OSTA Compressed Unicode";
153
154static int bdevismounted;
155static int ismounted;
156static int directory;
157static char buf[MAXBSIZE];
158static char buf2[MAXBSIZE];
159static char lvid[MAXBSIZE];
160
161uint32_t ecma_version = 2;
162
163static int serialnum = 1;	/* Tag serial number */
164static char udfs_label[128] = "*NoLabel*";
165static int acctype = PART_ACC_OW;
166static uint32_t part_start;
167static uint32_t part_len;
168static uint32_t part_bmp_bytes;
169static uint32_t part_bmp_sectors;
170static int32_t part_unalloc = -1;
171static uint32_t filesetblock;
172
173/* Set by readvolseq for -m option */
174static uint32_t oldfssize;
175static char *oldlabel;
176
177int
178main(int32_t argc, int8_t *argv[])
179{
180	long i;
181	FILE *mnttab;
182	struct mnttab mntp;
183	char *special, *raw_special;
184	struct stat statarea;
185	struct ustat ustatarea;
186	int32_t	c;
187	uint32_t temp_secsz;
188	int isfs;
189
190	(void) setlocale(LC_ALL, "");
191
192#if !defined(TEXT_DOMAIN)
193#define	TEXT_DOMAIN "SYS_TEST"
194#endif
195	(void) textdomain(TEXT_DOMAIN);
196
197	while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) {
198		switch (c) {
199
200			case 'F':
201				string = optarg;
202				if (strcmp(string, "udfs") != 0) {
203					usage();
204				}
205				break;
206
207			case 'V':
208				{
209					char	*opt_text;
210					int	opt_count;
211
212					(void) fprintf(stdout,
213					gettext("mkfs -F udfs "));
214					for (opt_count = 1; opt_count < argc;
215							opt_count++) {
216						opt_text = argv[opt_count];
217						if (opt_text) {
218							(void) fprintf(stdout,
219							" %s ", opt_text);
220						}
221					}
222					(void) fprintf(stdout, "\n");
223				}
224				break;
225
226			case 'm':
227				/*
228				 * return command line used
229				 * to create this FS
230				 */
231				mflag++;
232				break;
233
234			case 'o':
235				/*
236				 * udfs specific options.
237				 */
238				string = optarg;
239				while (*string != '\0') {
240					if (match("N")) {
241						Nflag++;
242					} else if (match("psize=")) {
243						number_flags = 0;
244						sectorsize = number(BIG,
245							"psize");
246					} else if (match("label=")) {
247						for (i = 0; i < 31; i++) {
248							if (*string == '\0') {
249								break;
250							}
251							udfs_label[i] =
252								*string++;
253						}
254						udfs_label[i] = '\0';
255					} else if (*string == '\0') {
256						break;
257					} else {
258						(void) fprintf(stdout,
259							gettext("illegal "
260							"option: %s\n"),
261							string);
262						usage();
263					}
264					if (*string == ',') {
265						string++;
266					}
267					if (*string == ' ') {
268						string++;
269					}
270				}
271				break;
272
273			case '?':
274				usage();
275				break;
276		}
277	}
278
279	(void) time(&mkfstime);
280	if (optind > (argc - 1)) {
281		usage();
282	}
283
284	argc -= optind;
285	argv = &argv[optind];
286	fsys = argv[0];
287	raw_special = getfullrawname(fsys);
288	fsi = open(raw_special, 0);
289	if (fsi < 0) {
290		(void) fprintf(stdout,
291			gettext("%s: cannot open\n"), fsys);
292		exit(32);
293	}
294	fso = fsi;
295
296	if ((temp_secsz = get_bsize()) != 0) {
297		sectorsize = temp_secsz;
298	}
299
300	/* Get old file system information */
301	isfs = readvolseq();
302
303	if (mflag) {
304		/*
305		 * Figure out the block size and
306		 * file system size and print the information
307		 */
308		if (isfs)
309			dump_fscmd(fsys, fsi);
310		else
311			(void) printf(gettext(
312				"[not currently a valid file system]\n"));
313		exit(0);
314	}
315
316	/*
317	 * Get the disk size from the drive or VTOC for the N and N-256
318	 * AVDPs and to make sure we don't want to create a file system
319	 * bigger than the partition.
320	 */
321	disk_size = get_last_block();
322
323	if (argc < 2 && disk_size == 0 || argc < 1) {
324		usage();
325	}
326
327	if (argc < 2) {
328		(void) printf(gettext("No size specified, entire partition "
329			"of %u sectors used\n"), disk_size);
330		fssize = disk_size;
331	} else {
332		string = argv[1];
333		number_flags = 0;
334		fssize = number(BIG, "size");
335	}
336
337	if (fssize < 0) {
338		(void) fprintf(stderr,
339			gettext("Negative number of sectors(%d) not allowed\n"),
340			fssize);
341		exit(32);
342	}
343
344	if (fssize < (512 * sectorsize / DEV_BSIZE)) {
345		(void) fprintf(stdout,
346			gettext("size should be at least %d sectors\n"),
347			(512 * sectorsize / DEV_BSIZE));
348		exit(32);
349	}
350
351	if (disk_size != 0) {
352		if (fssize > disk_size) {
353			(void) fprintf(stderr, gettext("Invalid size: %d "
354				"larger than the partition size\n"), fssize);
355			exit(32);
356		} else if (fssize < disk_size) {
357			unused = disk_size - fssize;
358			(void) printf(
359			    gettext("File system size %d smaller than "
360				"partition, %u sectors unused\n"),
361				fssize, unused);
362		}
363	} else {
364		/* Use passed-in size */
365		disk_size = fssize;
366	}
367
368	if (!Nflag) {
369		special = getfullblkname(fsys);
370
371		/*
372		 * If we found the block device name,
373		 * then check the mount table.
374		 * if mounted, write lock the file system
375		 *
376		 */
377		if ((special != NULL) && (*special != '\0')) {
378			mnttab = fopen(MNTTAB, "r");
379			while ((getmntent(mnttab, &mntp)) == NULL) {
380				if (strcmp(special, mntp.mnt_special) == 0) {
381					(void) fprintf(stdout,
382						gettext("%s is mounted,"
383						" can't mkfs\n"), special);
384					exit(32);
385				}
386			}
387			(void) fclose(mnttab);
388		}
389		if ((bdevismounted) && (ismounted == 0)) {
390			(void) fprintf(stdout,
391				gettext("can't check mount point; "));
392			(void) fprintf(stdout,
393				gettext("%s is mounted but not in mnttab(4)\n"),
394				special);
395			exit(32);
396		}
397		if (directory) {
398			if (ismounted == 0) {
399				(void) fprintf(stdout,
400					gettext("%s is not mounted\n"),
401					special);
402				exit(32);
403			}
404		}
405		fso = creat(fsys, 0666);
406		if (fso < 0) {
407			(void) fprintf(stdout,
408				gettext("%s: cannot create\n"), fsys);
409			exit(32);
410		}
411		if (stat(fsys, &statarea) < 0) {
412			(void) fprintf(stderr,
413				gettext("%s: %s: cannot stat\n"),
414				argv[0], fsys);
415			exit(32);
416		}
417		if (ustat(statarea.st_rdev, &ustatarea) >= 0) {
418			(void) fprintf(stderr,
419				gettext("%s is mounted, can't mkfs\n"), fsys);
420			exit(32);
421		}
422	} else {
423		/*
424		 * For the -N case, a file descriptor is needed for the llseek()
425		 * in wtfs(). See the comment in wtfs() for more information.
426		 *
427		 * Get a file descriptor that's read-only so that this code
428		 * doesn't accidentally write to the file.
429		 */
430		fso = open(fsys, O_RDONLY);
431		if (fso < 0) {
432			(void) fprintf(stderr, gettext("%s: cannot open\n"),
433				fsys);
434			exit(32);
435		}
436	}
437
438
439	/*
440	 * Validate the given file system size.
441	 * Verify that its last block can actually be accessed.
442	 */
443	fssize = fssize / (sectorsize / DEV_BSIZE);
444	if (fssize <= 0) {
445		(void) fprintf(stdout,
446			gettext("preposterous size %d. sectors\n"), fssize);
447		exit(32);
448	}
449	fssize --;
450
451	/*
452	 * verify device size
453	 */
454	rdfs(fssize - 1, sectorsize, buf);
455
456	if ((sectorsize < DEV_BSIZE) ||
457		(sectorsize > MAXBSIZE)) {
458		(void) fprintf(stdout,
459			gettext("sector size must be"
460			" between 512, 8192 bytes\n"));
461	}
462	if (!POWEROF2(sectorsize)) {
463		(void) fprintf(stdout,
464			gettext("sector size must be a power of 2, not %d\n"),
465			sectorsize);
466		exit(32);
467	}
468	if (Nflag) {
469		exit(0);
470	}
471
472	(void) printf(gettext("Creating file system with sector size of "
473		"%d bytes\n"), sectorsize);
474
475	/*
476	 * Set up time stamp values
477	 */
478	mkfstime = time(0);
479	(void) localtime_r(&mkfstime, &res);
480	if (res.tm_isdst > 0) {
481		tzone = altzone / 60;
482	} else if (res.tm_isdst == 0) {
483		tzone = tzone / 60;
484	} else {
485		tzone = 2047;	/* Unknown */
486	}
487
488	/*
489	 * Initialize the volume recognition sequence, the volume descriptor
490	 * sequences and the anchor pointer.
491	 */
492	volseqinit();
493
494	(void) fsync(fso);
495	(void) close(fsi);
496	(void) close(fso);
497
498	return (0);
499}
500
501static void
502setstamp(tstamp_t *tp)
503{
504	tp->ts_usec = 0;
505	tp->ts_husec = 0;
506	tp->ts_csec = 0;
507
508	tp->ts_sec = res.tm_sec;
509	tp->ts_min = res.tm_min;
510	tp->ts_hour = res.tm_hour;
511	tp->ts_day = res.tm_mday;
512	tp->ts_month = res.tm_mon + 1;
513	tp->ts_year = 1900 + res.tm_year;
514
515	tp->ts_tzone = 0x1000 + (-tzone & 0xFFF);
516}
517
518static void
519setextad(extent_ad_t *eap, uint32_t len, uint32_t loc)
520{
521	eap->ext_len = len;
522	eap->ext_loc = loc;
523}
524
525static void
526setdstring(dstring_t *dp, char *cp, int len)
527{
528	int32_t length;
529
530	bzero(dp, len);
531	length = strlen(cp);
532	if (length > len - 3) {
533		length = len - 3;
534	}
535	dp[len - 1] = length + 1;
536	*dp++ = 8;
537	(void) strncpy(dp, cp, len-2);
538}
539
540static void
541wtvolseq(tag_t *tp, daddr_t blk1, daddr_t blk2)
542{
543	static uint32_t vdsn = 0;
544
545	tp->tag_loc = blk1;
546	switch (tp->tag_id) {
547	case UD_PRI_VOL_DESC :
548		((struct pri_vol_desc *)tp)->pvd_vdsn = vdsn++;
549		break;
550	case UD_VOL_DESC_PTR :
551		((struct vol_desc_ptr *)tp)->vdp_vdsn = vdsn++;
552		break;
553	case UD_IMPL_USE_DESC :
554		((struct iuvd_desc *)tp)->iuvd_vdsn = vdsn++;
555		break;
556	case UD_PART_DESC :
557		((struct part_desc *)tp)->pd_vdsn = vdsn++;
558		break;
559	case UD_LOG_VOL_DESC :
560		((struct log_vol_desc *)tp)->lvd_vdsn = vdsn++;
561		break;
562	case UD_UNALL_SPA_DESC :
563		((struct unall_spc_desc *)tp)->ua_vdsn = vdsn++;
564		break;
565	}
566
567	bzero(buf2, sectorsize);
568	/* LINTED */
569	maketag(tp, (struct tag *)buf2);
570
571	/*
572	 * Write at Main Volume Descriptor Sequence
573	 */
574	wtfs(blk1, sectorsize, buf2);
575
576	tp->tag_loc = blk2;
577	switch (tp->tag_id) {
578	case UD_PRI_VOL_DESC :
579		((struct pri_vol_desc *)tp)->pvd_vdsn = vdsn++;
580		break;
581	case UD_VOL_DESC_PTR :
582		((struct vol_desc_ptr *)tp)->vdp_vdsn = vdsn++;
583		break;
584	case UD_IMPL_USE_DESC :
585		((struct iuvd_desc *)tp)->iuvd_vdsn = vdsn++;
586		break;
587	case UD_PART_DESC :
588		((struct part_desc *)tp)->pd_vdsn = vdsn++;
589		break;
590	case UD_LOG_VOL_DESC :
591		((struct log_vol_desc *)tp)->lvd_vdsn = vdsn++;
592		break;
593	case UD_UNALL_SPA_DESC :
594		((struct unall_spc_desc *)tp)->ua_vdsn = vdsn++;
595		break;
596	}
597	maketag(tp, tp);
598	/*
599	 * Write at Reserve Volume Descriptor Sequence
600	 */
601	wtfs(blk2, sectorsize, buf);
602}
603
604static void
605volseqinit()
606{
607	struct tag *tp;
608	struct nsr_desc *nsp;
609	struct pri_vol_desc *pvdp;
610	struct iuvd_desc *iudp;
611	struct part_desc *pp;
612	struct phdr_desc *php;
613	struct log_vol_desc *lvp;
614	long_ad_t *lap;
615	struct pmap_typ1 *pmp;
616	struct unall_spc_desc *uap;
617	struct log_vol_int_desc *lvip;
618	struct term_desc *tdp;
619	struct anch_vol_desc_ptr *avp;
620	struct lvid_iu *lviup;
621	struct file_set_desc *fsp;
622	struct file_entry *fp;
623	struct icb_tag *icb;
624	struct short_ad *sap;
625	struct file_id *fip;
626	struct space_bmap_desc *sbp;
627	uint8_t *cp;
628	daddr_t nextblock, endblock;
629	int32_t volseq_sectors, nextlogblock, rootfelen, i;
630	uint32_t mvds_loc, rvds_loc;
631
632	bzero(buf, MAXBSIZE);
633
634	/*
635	 * Starting from MAXBSIZE, clear out till 256 sectors.
636	 */
637	for (i = MAXBSIZE / sectorsize; i < FIRSTAVDP; i++) {
638		wtfs(i, sectorsize, buf);
639	}
640
641	/* Zero out the avdp at N - 257 */
642	wtfs(fssize - 256, sectorsize, buf);
643
644	/*
645	 * Leave 1st 32K for O.S.
646	 */
647	nextblock = VOLRECSTART / sectorsize;
648
649	/*
650	 * Write BEA01/NSR02/TEA01 sequence.
651	 * Each one must be 2K bytes in length.
652	 */
653	nsp = (struct nsr_desc *)buf;
654	nsp->nsr_str_type = 0;
655	nsp->nsr_ver = 1;
656	(void) strncpy((int8_t *)nsp->nsr_id, "BEA01", 5);
657
658	nsp = (struct nsr_desc *)&buf[2048];
659	nsp->nsr_str_type = 0;
660	nsp->nsr_ver = 1;
661	(void) strncpy((int8_t *)nsp->nsr_id, "NSR02", 5);
662
663	nsp = (struct nsr_desc *)&buf[4096];
664	nsp->nsr_str_type = 0;
665	nsp->nsr_ver = 1;
666	(void) strncpy((int8_t *)nsp->nsr_id, "TEA01", 5);
667
668	wtfs(nextblock, 8192, buf);
669	bzero(buf, MAXBSIZE);
670
671	/*
672	 * Minimum length of volume sequences
673	 */
674	volseq_sectors = 16;
675
676	/*
677	 * Round up to next 32K boundary for
678	 * volume descriptor sequences
679	 */
680	nextblock = VOLSEQSTART;
681	bzero(buf, sectorsize);
682	mvds_loc = VOLSEQSTART;
683	rvds_loc = mvds_loc + volseq_sectors;
684
685	/*
686	 * Primary Volume Descriptor
687	 */
688	/* LINTED */
689	pvdp = (struct pri_vol_desc *)buf;
690	tp = &pvdp->pvd_tag;
691	tp->tag_id =  UD_PRI_VOL_DESC;
692	tp->tag_desc_ver = ecma_version;
693	tp->tag_sno = serialnum;
694	tp->tag_crc_len = sizeof (struct pri_vol_desc) -
695			sizeof (struct tag);
696	pvdp->pvd_vdsn = 0;
697	pvdp->pvd_pvdn = 0;
698	setdstring(pvdp->pvd_vol_id, udfs_label, 32);
699	pvdp->pvd_vsn = 1;
700	pvdp->pvd_mvsn = 1;
701	pvdp->pvd_il = 2;		/* Single-volume */
702	pvdp->pvd_mil = 3;		/* Multi-volume */
703	pvdp->pvd_csl = 1;		/* CS0 */
704	pvdp->pvd_mcsl = 1;		/* CS0 */
705	(void) sprintf(vsibuf, "%08X", SWAP_32((uint32_t)mkfstime));
706	setdstring(pvdp->pvd_vsi, vsibuf, 128);
707	(void) strncpy(pvdp->pvd_vsi + 17, udfs_label, 128 - 17);
708	setcharspec(&pvdp->pvd_desc_cs, 0, osta_unicode);
709	setcharspec(&pvdp->pvd_exp_cs, 0, osta_unicode);
710	setextad(&pvdp->pvd_vol_abs, 0, 0);
711	setextad(&pvdp->pvd_vcn, 0, 0);
712	bzero(&pvdp->pvd_appl_id, sizeof (regid_t));
713	setstamp(&pvdp->pvd_time);
714	bcopy(&sunmicro, &pvdp->pvd_ii, sizeof (regid_t));
715	pvdp->pvd_flags = 0;
716	wtvolseq(tp, nextblock, nextblock + volseq_sectors);
717	nextblock++;
718
719	/*
720	 * Implementation Use Descriptor
721	 */
722	bzero(buf, sectorsize);
723	/* LINTED */
724	iudp = (struct iuvd_desc *)buf;
725	tp = &iudp->iuvd_tag;
726	tp->tag_id =  UD_IMPL_USE_DESC;
727	tp->tag_desc_ver = ecma_version;
728	tp->tag_sno = serialnum;
729	tp->tag_crc_len = sizeof (struct iuvd_desc) -
730			sizeof (struct tag);
731	iudp->iuvd_vdsn = 0;
732	bcopy(&lvinfo, &iudp->iuvd_ii, sizeof (regid_t));
733	setcharspec(&iudp->iuvd_cset, 0, osta_unicode);
734	setdstring(iudp->iuvd_lvi, udfs_label, 128);
735
736	setdstring(iudp->iuvd_ifo1, "", 36);
737	setdstring(iudp->iuvd_ifo2, "", 36);
738	setdstring(iudp->iuvd_ifo3, "", 36);
739
740
741	/*
742	 * info1,2,3 = user specified
743	 */
744	bcopy(&sunmicro, &iudp->iuvd_iid, sizeof (regid_t));
745	wtvolseq(tp, nextblock, nextblock + volseq_sectors);
746	nextblock++;
747
748	/*
749	 * Partition Descriptor
750	 */
751	bzero(buf, sectorsize);
752	/* LINTED */
753	pp = (struct part_desc *)buf;
754	tp = &pp->pd_tag;
755	tp->tag_id =  UD_PART_DESC;
756	tp->tag_desc_ver = ecma_version;
757	tp->tag_sno = serialnum;
758	tp->tag_crc_len = sizeof (struct part_desc) -
759			sizeof (struct tag);
760	pp->pd_vdsn = 0;
761	pp->pd_pflags = 1;			/* Allocated */
762	pp->pd_pnum = 0;
763	bcopy(&partid, &pp->pd_pcontents, sizeof (regid_t));
764
765	part_start = FIRSTAVDP + AVDPLEN;
766	part_len = fssize - part_start;
767	part_bmp_bytes = (part_len + NBBY - 1) / NBBY;
768	part_bmp_sectors = (part_bmp_bytes + SPACEMAP_OFF + sectorsize - 1) /
769		sectorsize;
770
771	pp->pd_part_start = part_start;
772	pp->pd_part_length = part_len;
773
774	pp->pd_acc_type = acctype;
775	nextlogblock = 0;
776
777	/*
778	 * Do the partition header
779	 */
780	/* LINTED */
781	php = (struct phdr_desc *)&pp->pd_pc_use;
782
783	/*
784	 * Set up unallocated space bitmap
785	 */
786	if (acctype == PART_ACC_RW || acctype == PART_ACC_OW) {
787		php->phdr_usb.sad_ext_len =
788			(part_bmp_bytes + SPACEMAP_OFF + sectorsize - 1) &
789				(~(sectorsize - 1));
790		php->phdr_usb.sad_ext_loc = nextlogblock;
791		part_unalloc = nextlogblock;
792		nextlogblock += part_bmp_sectors;
793	}
794
795	bcopy(&sunmicro, &pp->pd_ii, sizeof (regid_t));
796	wtvolseq(tp, nextblock, nextblock + volseq_sectors);
797	nextblock++;
798
799	/*
800	 * Logical Volume Descriptor
801	 */
802	bzero(buf, sectorsize);
803	/* LINTED */
804	lvp = (struct log_vol_desc *)buf;
805	tp = &lvp->lvd_tag;
806	tp->tag_id =  UD_LOG_VOL_DESC;
807	tp->tag_desc_ver = ecma_version;
808	tp->tag_sno = serialnum;
809	tp->tag_crc_len = sizeof (struct log_vol_desc) -
810			sizeof (struct tag);
811	lvp->lvd_vdsn = 0;
812	setcharspec(&lvp->lvd_desc_cs, 0, osta_unicode);
813	setdstring(lvp->lvd_lvid, udfs_label, 128);
814	lvp->lvd_log_bsize = sectorsize;
815	bcopy(&udf_compliant, &lvp->lvd_dom_id, sizeof (regid_t));
816	lap = (long_ad_t *)&lvp->lvd_lvcu;
817	lap->lad_ext_len = FILESETLEN * sectorsize;
818	filesetblock = nextlogblock;
819	lap->lad_ext_loc = nextlogblock;
820	lap->lad_ext_prn = 0;
821	lvp->lvd_mtbl_len = 6;
822	lvp->lvd_num_pmaps = 1;
823	bcopy(&sunmicro, &lvp->lvd_ii, sizeof (regid_t));
824	/* LINTED */
825	pmp = (struct pmap_typ1 *)&lvp->lvd_pmaps;
826	pmp->map1_type = 1;
827	pmp->map1_length = 6;
828	pmp->map1_vsn = SWAP_16(1);
829	pmp->map1_pn  = 0;
830	tp->tag_crc_len = (char *)(pmp + 1) - buf - sizeof (struct tag);
831	setextad(&lvp->lvd_int_seq_ext, INTSEQLEN, INTSEQSTART);
832	wtvolseq(tp, nextblock, nextblock + volseq_sectors);
833	nextblock++;
834
835	/*
836	 * Unallocated Space Descriptor
837	 */
838	bzero(buf, sectorsize);
839	/* LINTED */
840	uap = (struct unall_spc_desc *)buf;
841	tp = &uap->ua_tag;
842	tp->tag_id =  UD_UNALL_SPA_DESC;
843	tp->tag_desc_ver = ecma_version;
844	tp->tag_sno = serialnum;
845	uap->ua_vdsn = 0;
846	uap->ua_nad = 0;
847	tp->tag_crc_len = (char *)uap->ua_al_dsc - buf - sizeof (struct tag);
848	wtvolseq(tp, nextblock, nextblock + volseq_sectors);
849	nextblock++;
850
851	/*
852	 * Terminating Descriptor
853	 */
854	bzero(buf, sectorsize);
855	/* LINTED */
856	tdp = (struct term_desc *)buf;
857	tp = &tdp->td_tag;
858	tp->tag_id =  UD_TERM_DESC;
859	tp->tag_desc_ver = ecma_version;
860	tp->tag_sno = serialnum;
861	tp->tag_crc_len = sizeof (struct term_desc) -
862			sizeof (struct tag);
863	tp->tag_loc = nextblock;
864	wtvolseq(tp, nextblock, nextblock + volseq_sectors);
865	nextblock++;
866
867	/*
868	 * Do the anchor volume descriptor
869	 */
870	if (nextblock > FIRSTAVDP) {
871		(void) fprintf(stdout,
872			gettext("Volume integrity sequence"
873			" descriptors too long\n"));
874		exit(32);
875	}
876
877	nextblock = FIRSTAVDP;
878	bzero(buf, sectorsize);
879	/* LINTED */
880	avp = (struct anch_vol_desc_ptr *)buf;
881	tp = &avp->avd_tag;
882	tp->tag_id =  UD_ANCH_VOL_DESC;
883	tp->tag_desc_ver = ecma_version;
884	tp->tag_sno = serialnum;
885	tp->tag_crc_len = sizeof (struct anch_vol_desc_ptr) -
886			sizeof (struct tag);
887	tp->tag_loc = nextblock;
888	setextad(&avp->avd_main_vdse,
889			volseq_sectors * sectorsize, mvds_loc);
890	setextad(&avp->avd_res_vdse,
891			volseq_sectors * sectorsize, rvds_loc);
892	bzero(buf2, sectorsize);
893	/* LINTED */
894	maketag(tp, (struct tag *)buf2);
895	wtfs(nextblock, sectorsize, buf2);
896	nextblock++;
897
898	tp->tag_loc = fssize;
899	/* LINTED */
900	maketag(tp, (struct tag *)buf2);
901	wtfs(fssize, sectorsize, buf2);
902
903	/*
904	 * File Set Descriptor
905	 */
906	bzero(buf, sectorsize);
907	/* LINTED */
908	fsp = (struct file_set_desc *)&buf;
909	tp = &fsp->fsd_tag;
910	tp->tag_id =  UD_FILE_SET_DESC;
911	tp->tag_desc_ver = ecma_version;
912	tp->tag_sno = serialnum;
913	tp->tag_crc_len = sizeof (struct file_set_desc) -
914			sizeof (struct tag);
915	tp->tag_loc = nextlogblock;
916	setstamp(&fsp->fsd_time);
917	fsp->fsd_ilevel = 3;
918	fsp->fsd_mi_level = 3;
919	fsp->fsd_cs_list = 1;
920	fsp->fsd_mcs_list = 1;
921	fsp->fsd_fs_no = 0;
922	fsp->fsd_fsd_no = 0;
923	setcharspec(&fsp->fsd_lvidcs, 0, osta_unicode);
924	setdstring(fsp->fsd_lvid, udfs_label, 128);
925	setcharspec(&fsp->fsd_fscs, 0, osta_unicode);
926	setdstring(fsp->fsd_fsi, udfs_label, 32);
927	setdstring(fsp->fsd_cfi, "", 32);
928	setdstring(fsp->fsd_afi, "", 32);
929	lap = (long_ad_t *)&fsp->fsd_root_icb;
930	lap->lad_ext_len = sectorsize;
931	lap->lad_ext_loc = filesetblock + FILESETLEN;
932	lap->lad_ext_prn = 0;
933	bcopy(&udf_compliant, &fsp->fsd_did, sizeof (regid_t));
934	maketag(tp, tp);
935	wtfs(nextlogblock + part_start, sectorsize, (char *)tp);
936	nextlogblock++;
937
938	/*
939	 * Terminating Descriptor
940	 */
941	bzero(buf, sectorsize);
942	/* LINTED */
943	tdp = (struct term_desc *)buf;
944	tp = &tdp->td_tag;
945	tp->tag_id =  UD_TERM_DESC;
946	tp->tag_desc_ver = ecma_version;
947	tp->tag_sno = serialnum;
948	tp->tag_crc_len = sizeof (struct term_desc) -
949			sizeof (struct tag);
950	tp->tag_loc = nextlogblock;
951	maketag(tp, tp);
952	wtfs(nextlogblock + part_start, sectorsize, (char *)tp);
953	nextlogblock++;
954
955	if (nextlogblock > filesetblock + FILESETLEN) {
956		(void) fprintf(stdout,
957			gettext("File set descriptor too long\n"));
958		exit(32);
959	}
960	nextlogblock = filesetblock + FILESETLEN;
961
962	/*
963	 * Root File Entry
964	 */
965	bzero(buf, sectorsize);
966	/* LINTED */
967	fp = (struct file_entry *)&buf;
968	tp = &fp->fe_tag;
969	tp->tag_id =  UD_FILE_ENTRY;
970	tp->tag_desc_ver = ecma_version;
971	tp->tag_sno = serialnum;
972	tp->tag_loc = nextlogblock;
973	icb = &fp->fe_icb_tag;
974	icb->itag_prnde = 0;
975	icb->itag_strategy = STRAT_TYPE4;
976	icb->itag_param = 0; /* what does this mean? */
977	icb->itag_max_ent = 1;
978	icb->itag_ftype = FTYPE_DIRECTORY;
979	icb->itag_lb_loc = 0;
980	icb->itag_lb_prn = 0;
981	icb->itag_flags = ICB_FLAG_ARCHIVE;
982	fp->fe_uid = getuid();
983	fp->fe_gid = getgid();
984	fp->fe_perms = (0x1f << 10) | (0x5 << 5) | 0x5;
985	fp->fe_lcount = 1;
986	fp->fe_rec_for = 0;
987	fp->fe_rec_dis = 0;
988	fp->fe_rec_len = 0;
989	fp->fe_info_len = sizeof (struct file_id);
990	fp->fe_lbr = 1;
991	setstamp(&fp->fe_acc_time);
992	setstamp(&fp->fe_mod_time);
993	setstamp(&fp->fe_attr_time);
994	fp->fe_ckpoint = 1;
995	bcopy(&sunmicro, &fp->fe_impl_id, sizeof (regid_t));
996	fp->fe_uniq_id = 0;
997	fp->fe_len_ear = 0;
998	fp->fe_len_adesc = sizeof (short_ad_t);
999
1000	/* LINTED */
1001	sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear);
1002	sap->sad_ext_len = sizeof (struct file_id);
1003	sap->sad_ext_loc = nextlogblock + 1;
1004	rootfelen = (char *)(sap + 1) - buf;
1005	tp->tag_crc_len = rootfelen - sizeof (struct tag);
1006	maketag(tp, tp);
1007	wtfs(nextlogblock + part_start, sectorsize, (char *)tp);
1008	nextlogblock++;
1009
1010	/*
1011	 * Root Directory
1012	 */
1013	bzero(buf, sectorsize);
1014	/* LINTED */
1015	fip = (struct file_id *)&buf;
1016	tp = &fip->fid_tag;
1017	tp->tag_id =  UD_FILE_ID_DESC;
1018	tp->tag_desc_ver = ecma_version;
1019	tp->tag_sno = serialnum;
1020	tp->tag_crc_len = sizeof (struct file_id) -
1021			sizeof (struct tag);
1022	tp->tag_loc = nextlogblock;
1023	fip->fid_ver = 1;
1024	fip->fid_flags = FID_DIR | FID_PARENT;
1025	fip->fid_idlen = 0;
1026	fip->fid_iulen = 0;
1027	fip->fid_icb.lad_ext_len = sectorsize; /* rootfelen; */
1028	fip->fid_icb.lad_ext_loc = nextlogblock - 1;
1029	fip->fid_icb.lad_ext_prn = 0;
1030	maketag(tp, tp);
1031	wtfs(nextlogblock + part_start, sectorsize, (char *)tp);
1032	nextlogblock++;
1033
1034	/*
1035	 * Now do the space bitmaps
1036	 */
1037	if (part_unalloc >= 0) {
1038		int size = sectorsize * part_bmp_sectors;
1039
1040		sbp = (struct space_bmap_desc *)malloc(size);
1041		if (!sbp) {
1042			(void) fprintf(stdout,
1043				gettext("Can't allocate bitmap space\n"));
1044			exit(32);
1045		}
1046		bzero((char *)sbp, sectorsize * part_bmp_sectors);
1047		tp = &sbp->sbd_tag;
1048		tp->tag_id =  UD_SPA_BMAP_DESC;
1049		tp->tag_desc_ver = ecma_version;
1050		tp->tag_sno = serialnum;
1051		tp->tag_crc_len = 0;	/* Don't do CRCs on bitmaps */
1052		tp->tag_loc = part_unalloc;
1053		sbp->sbd_nbits = part_len;
1054		sbp->sbd_nbytes = part_bmp_bytes;
1055		maketag(tp, tp);
1056		if (part_unalloc >= 0) {
1057			int32_t i;
1058
1059			cp = (uint8_t *)sbp + SPACEMAP_OFF;
1060			i = nextlogblock / NBBY;
1061			cp[i++] = (0xff << (nextlogblock % NBBY)) & 0xff;
1062			while (i < part_bmp_bytes)
1063				cp[i++] = 0xff;
1064			if (part_len % NBBY)
1065				cp[--i] = (unsigned)0xff >>
1066					(NBBY - part_len % NBBY);
1067
1068			wtfs(part_unalloc + part_start, size, (char *)tp);
1069		}
1070		free((char *)sbp);
1071	}
1072
1073	/*
1074	 * Volume Integrity Descriptor
1075	 */
1076	nextblock = INTSEQSTART;
1077	endblock = nextblock + INTSEQLEN / sectorsize;
1078	/* LINTED */
1079	lvip = (struct log_vol_int_desc *)&lvid;
1080	tp = &lvip->lvid_tag;
1081	tp->tag_id =  UD_LOG_VOL_INT;
1082	tp->tag_desc_ver = ecma_version;
1083	tp->tag_sno = serialnum;
1084	tp->tag_loc = nextblock;
1085	setstamp(&lvip->lvid_tstamp);
1086	lvip->lvid_int_type = LOG_VOL_CLOSE_INT;
1087	setextad(&lvip->lvid_nie, 0, 0);
1088	lvip->lvid_npart = 1;
1089	lvip->lvid_liu = 0x2e;
1090	lvip->lvid_uniqid = MAXID + 1;
1091	lvip->lvid_fst[0] = part_len - nextlogblock;	/* Free space */
1092	lvip->lvid_fst[1] = part_len;			/* Size */
1093	lviup = (struct lvid_iu *)&lvip->lvid_fst[2];
1094	bcopy(&sunmicro, &lviup->lvidiu_regid, sizeof (regid_t));
1095	lviup->lvidiu_nfiles = 0;
1096	lviup->lvidiu_ndirs = 1;
1097	lviup->lvidiu_mread = 0x102;
1098	lviup->lvidiu_mwrite = 0x102;
1099	lviup->lvidiu_maxwr = 0x150;
1100	tp->tag_crc_len = sizeof (struct log_vol_int_desc) + lvip->lvid_liu -
1101		sizeof (struct tag);
1102	maketag(tp, tp);
1103	wtfs(nextblock, sectorsize, (char *)tp);
1104	nextblock++;
1105
1106	/*
1107	 * Terminating Descriptor
1108	 */
1109	bzero(buf, sectorsize);
1110	/* LINTED */
1111	tdp = (struct term_desc *)buf;
1112	tp = &tdp->td_tag;
1113	tp->tag_id =  UD_TERM_DESC;
1114	tp->tag_desc_ver = ecma_version;
1115	tp->tag_sno = serialnum;
1116	tp->tag_crc_len = sizeof (struct term_desc) - sizeof (struct tag);
1117	tp->tag_loc = nextblock;
1118	maketag(tp, tp);
1119	wtfs(nextblock, sectorsize, (char *)tp);
1120	nextblock++;
1121
1122	/* Zero out the rest of the LVI extent */
1123	bzero(buf, sectorsize);
1124	while (nextblock < endblock)
1125		wtfs(nextblock++, sectorsize, buf);
1126}
1127
1128/*
1129 * read a block from the file system
1130 */
1131static void
1132rdfs(daddr_t bno, int size, char *bf)
1133{
1134	int n, saverr;
1135
1136	if (llseek(fsi, (offset_t)bno * sectorsize, 0) < 0) {
1137		saverr = errno;
1138		(void) fprintf(stderr,
1139			gettext("seek error on sector %ld: %s\n"),
1140			bno, strerror(saverr));
1141		exit(32);
1142	}
1143	n = read(fsi, bf, size);
1144	if (n != size) {
1145		saverr = errno;
1146		(void) fprintf(stderr,
1147			gettext("read error on sector %ld: %s\n"),
1148			bno, strerror(saverr));
1149		exit(32);
1150	}
1151}
1152
1153/*
1154 * write a block to the file system
1155 */
1156static void
1157wtfs(daddr_t bno, int size, char *bf)
1158{
1159	int n, saverr;
1160
1161	if (fso == -1)
1162		return;
1163
1164	if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
1165		saverr = errno;
1166		(void) fprintf(stderr,
1167			gettext("seek error on sector %ld: %s\n"),
1168			bno, strerror(saverr));
1169		exit(32);
1170	}
1171	if (Nflag)
1172		return;
1173	n = write(fso, bf, size);
1174	if (n != size) {
1175		saverr = errno;
1176		(void) fprintf(stderr,
1177			gettext("write error on sector %ld: %s\n"),
1178			bno, strerror(saverr));
1179		exit(32);
1180	}
1181}
1182
1183static void
1184usage()
1185{
1186	(void) fprintf(stderr,
1187		gettext("udfs usage: mkfs [-F FSType] [-V]"
1188		" [-m] [-o options] special size(sectors)\n"));
1189	(void) fprintf(stderr,
1190		gettext(" -m : dump fs cmd line used to make"
1191		" this partition\n"));
1192	(void) fprintf(stderr,
1193		gettext(" -V : print this command line and return\n"));
1194	(void) fprintf(stderr,
1195		gettext(" -o : udfs options: :psize=%d:label=%s\n"),
1196		sectorsize, udfs_label);
1197	(void) fprintf(stderr,
1198		gettext("NOTE that all -o suboptions: must"
1199		" be separated only by commas so as to\n"));
1200	(void) fprintf(stderr,
1201		gettext("be parsed as a single argument\n"));
1202	exit(32);
1203}
1204
1205/*ARGSUSED*/
1206static void
1207dump_fscmd(char *fsys, int fsi)
1208{
1209	(void) printf(gettext("mkfs -F udfs -o "));
1210	(void) printf("psize=%d,label=\"%s\" %s %d\n",
1211		sectorsize, oldlabel, fsys, oldfssize);
1212}
1213
1214/* number ************************************************************* */
1215/*									*/
1216/* Convert a numeric arg to binary					*/
1217/*									*/
1218/* Arg:	 big - maximum valid input number				*/
1219/* Global arg:  string - pointer to command arg				*/
1220/*									*/
1221/* Valid forms: 123 | 123k | 123*123 | 123x123				*/
1222/*									*/
1223/* Return:	converted number					*/
1224/*									*/
1225/* ******************************************************************** */
1226
1227static int32_t
1228number(long big, char *param)
1229{
1230	char		*cs;
1231	int64_t		n = 0;
1232	int64_t		cut = BIG;
1233	int32_t		minus = 0;
1234
1235#define	FOUND_MULT	0x1
1236#define	FOUND_K		0x2
1237
1238	cs = string;
1239	if (*cs == '-') {
1240		minus = 1;
1241		cs++;
1242	}
1243	n = 0;
1244	while ((*cs != ' ') && (*cs != '\0') && (*cs != ',')) {
1245		if ((*cs >= '0') && (*cs <= '9')) {
1246			n = n * 10 + *cs - '0';
1247			cs++;
1248		} else if ((*cs == '*') || (*cs == 'x')) {
1249			if (number_flags & FOUND_MULT) {
1250				(void) fprintf(stderr,
1251				gettext("mkfs: only one \"*\" "
1252				"or \"x\" allowed\n"));
1253				exit(2);
1254			}
1255			number_flags |= FOUND_MULT;
1256			cs++;
1257			string = cs;
1258			n = n * number(big, param);
1259			cs = string;
1260			continue;
1261		} else if (*cs == 'k') {
1262			if (number_flags & FOUND_K) {
1263				(void) fprintf(stderr,
1264				gettext("mkfs: only one \"k\" allowed\n"));
1265				exit(2);
1266			}
1267			number_flags |= FOUND_K;
1268			n = n * 1024;
1269			cs++;
1270			continue;
1271		} else {
1272			(void) fprintf(stderr,
1273				gettext("mkfs: bad numeric arg: \"%s\"\n"),
1274				string);
1275			exit(2);
1276		}
1277	}
1278
1279	if (n > cut) {
1280		(void) fprintf(stderr,
1281			gettext("mkfs: value for %s overflowed\n"), param);
1282		exit(2);
1283	}
1284
1285	if (minus) {
1286		n = -n;
1287	}
1288
1289	if ((n > big) || (n < 0)) {
1290		(void) fprintf(stderr,
1291			gettext("mkfs: argument %s out of range\n"), param);
1292		exit(2);
1293	}
1294
1295	string = cs;
1296	return ((int32_t)n);
1297}
1298
1299/* match ************************************************************** */
1300/*									*/
1301/* Compare two text strings for equality				*/
1302/*									*/
1303/* Arg:	 s - pointer to string to match with a command arg		*/
1304/* Global arg:  string - pointer to command arg				*/
1305/*									*/
1306/* Return:	1 if match, 0 if no match				*/
1307/*		If match, also reset `string' to point to the text	*/
1308/*		that follows the matching text.				*/
1309/*									*/
1310/* ******************************************************************** */
1311
1312static int
1313match(char *s)
1314{
1315	char *cs;
1316
1317	cs = string;
1318	while (*cs++ == *s) {
1319		if (*s++ == '\0') {
1320			goto true;
1321		}
1322	}
1323	if (*s != '\0') {
1324		return (0);
1325	}
1326
1327true:
1328	cs--;
1329	string = cs;
1330	return (1);
1331}
1332
1333static uint32_t
1334get_bsize()
1335{
1336	struct dk_cinfo info;
1337	struct fd_char fd_char;
1338	struct dk_minfo dkminfo;
1339
1340	if (ioctl(fso, DKIOCINFO, &info) < 0) {
1341		perror("mkfs DKIOCINFO ");
1342		(void) fprintf(stdout,
1343			gettext("DKIOCINFO failed using psize = 2048"
1344			" for creating file-system\n"));
1345		return (0);
1346	}
1347
1348	switch (info.dki_ctype) {
1349		case DKC_CDROM :
1350			return (2048);
1351		case DKC_SCSI_CCS :
1352			if (ioctl(fso, DKIOCGMEDIAINFO, &dkminfo) != -1) {
1353				if (dkminfo.dki_lbsize != 0 &&
1354				    POWEROF2(dkminfo.dki_lbsize / DEV_BSIZE) &&
1355				    dkminfo.dki_lbsize != DEV_BSIZE) {
1356					fprintf(stderr,
1357					    gettext("The device sector size "
1358					    "%u is not supported by udfs!\n"),
1359					    dkminfo.dki_lbsize);
1360					(void) close(fso);
1361					exit(1);
1362				}
1363			}
1364			/* FALLTHROUGH */
1365		case DKC_INTEL82072 :
1366			/* FALLTHROUGH */
1367		case DKC_INTEL82077 :
1368			/* FALLTHROUGH */
1369		case DKC_DIRECT :
1370			if (ioctl(fso, FDIOGCHAR, &fd_char) >= 0) {
1371				return (fd_char.fdc_sec_size);
1372			}
1373			/* FALLTHROUGH */
1374		case DKC_PCMCIA_ATA :
1375			return (512);
1376		default :
1377			return (0);
1378	}
1379}
1380
1381/*
1382 * Read in the volume sequences descriptors.
1383 */
1384static int
1385readvolseq()
1386{
1387	struct tag *tp;
1388	uint8_t *cp, *end;
1389	int err;
1390	struct pri_vol_desc *pvolp;
1391	struct part_desc *partp;
1392	struct log_vol_desc *logvp;
1393	struct anch_vol_desc_ptr *avp;
1394	char *main_vdbuf;
1395	uint32_t nextblock;
1396
1397	avp = (struct anch_vol_desc_ptr *)malloc(sectorsize);
1398	rdfs(FIRSTAVDP, sectorsize, (char *)avp);
1399	tp = (struct tag *)avp;
1400	err = verifytag(tp, FIRSTAVDP, tp, UD_ANCH_VOL_DESC);
1401	if (err)
1402		return (0);
1403	main_vdbuf = malloc(avp->avd_main_vdse.ext_len);
1404	if (main_vdbuf == NULL) {
1405		(void) fprintf(stderr, gettext("Cannot allocate space for "
1406			"volume sequences\n"));
1407		exit(32);
1408	}
1409	rdfs(avp->avd_main_vdse.ext_loc, avp->avd_main_vdse.ext_len,
1410		main_vdbuf);
1411	end = (uint8_t *)main_vdbuf + avp->avd_main_vdse.ext_len;
1412
1413	nextblock = avp->avd_main_vdse.ext_loc;
1414	for (cp = (uint8_t *)main_vdbuf; cp < end; cp += sectorsize,
1415		nextblock++) {
1416		/* LINTED */
1417		tp = (struct tag *)cp;
1418		err = verifytag(tp, nextblock, tp, 0);
1419		if (err)
1420			continue;
1421
1422		switch (tp->tag_id) {
1423		case UD_PRI_VOL_DESC:
1424			/* Bump serial number, according to spec. */
1425			serialnum = tp->tag_sno + 1;
1426			pvolp = (struct pri_vol_desc *)tp;
1427			oldlabel = pvolp->pvd_vol_id + 1;
1428			break;
1429		case UD_ANCH_VOL_DESC:
1430			avp = (struct anch_vol_desc_ptr *)tp;
1431			break;
1432		case UD_VOL_DESC_PTR:
1433			break;
1434		case UD_IMPL_USE_DESC:
1435			break;
1436		case UD_PART_DESC:
1437			partp = (struct part_desc *)tp;
1438			part_start = partp->pd_part_start;
1439			part_len = partp->pd_part_length;
1440			oldfssize = part_start + part_len;
1441			break;
1442		case UD_LOG_VOL_DESC:
1443			logvp = (struct log_vol_desc *)tp;
1444			break;
1445		case UD_UNALL_SPA_DESC:
1446			break;
1447		case UD_TERM_DESC:
1448			goto done;
1449			break;
1450		case UD_LOG_VOL_INT:
1451			break;
1452		default:
1453			break;
1454		}
1455	}
1456done:
1457	if (!partp || !logvp) {
1458		return (0);
1459	}
1460	return (1);
1461}
1462
1463uint32_t
1464get_last_block()
1465{
1466	struct vtoc vtoc;
1467	struct dk_cinfo dki_info;
1468
1469	if (ioctl(fsi, DKIOCGVTOC, (intptr_t)&vtoc) != 0) {
1470		(void) fprintf(stderr, gettext("Unable to read VTOC\n"));
1471		return (0);
1472	}
1473
1474	if (vtoc.v_sanity != VTOC_SANE) {
1475		(void) fprintf(stderr, gettext("Vtoc.v_sanity != VTOC_SANE\n"));
1476		return (0);
1477	}
1478
1479	if (ioctl(fsi, DKIOCINFO, (intptr_t)&dki_info) != 0) {
1480		(void) fprintf(stderr,
1481		    gettext("Could not get the slice information\n"));
1482		return (0);
1483	}
1484
1485	if (dki_info.dki_partition > V_NUMPAR) {
1486		(void) fprintf(stderr,
1487		    gettext("dki_info.dki_partition > V_NUMPAR\n"));
1488		return (0);
1489	}
1490
1491	return ((uint32_t)vtoc.v_part[dki_info.dki_partition].p_size);
1492}
1493