/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Portions of this source code were derived from Berkeley 4.3 BSD * under license from the Regents of the University of California. */ /* * make file system for udfs (UDF - ISO13346) * * usage: * * mkfs [-F FSType] [-V] [-m] [options] * [-o specific_options] special size * * where specific_options are: * N - no create * label - volume label * psize - physical block size */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for ENDIAN defines */ #include #include #include #include extern char *getfullrawname(char *); extern char *getfullblkname(char *); extern struct tm *localtime_r(const time_t *, struct tm *); extern void maketag(struct tag *, struct tag *); extern int verifytag(struct tag *, uint32_t, struct tag *, int); extern void setcharspec(struct charspec *, int32_t, uint8_t *); #define UMASK 0755 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) #define MB (1024*1024) /* * Forward declarations */ static void rdfs(daddr_t bno, int size, char *bf); static void wtfs(daddr_t bno, int size, char *bf); static void dump_fscmd(char *fsys, int fsi); static int32_t number(long big, char *param); static void usage(); static int match(char *s); static int readvolseq(); static uint32_t get_last_block(); /* * variables set up by front end. */ static int Nflag = 0; /* run mkfs without writing */ /* file system */ static int mflag = 0; /* return the command line used */ /* to create this FS */ static int fssize; /* file system size */ static uint32_t disk_size; /* partition size from VTOC */ static uint32_t unused; /* unused sectors in partition */ static int sectorsize = 2048; /* bytes/sector default */ /* If nothing specified */ static char *fsys; static int fsi; static int fso; #define BIG LONG_MAX static uint32_t number_flags = 0; static char *string; static void setstamp(tstamp_t *); static void setextad(extent_ad_t *, uint32_t, uint32_t); static void setdstring(dstring_t *, char *, int32_t); static void wtvolseq(tag_t *, daddr_t, daddr_t); static void volseqinit(); static void setstamp(tstamp_t *); static uint32_t get_bsize(); #define VOLRECSTART (32 * 1024) #define VOLSEQSTART 128 #define VOLSEQLEN 16 #define INTSEQSTART 192 #define INTSEQLEN 8192 #define FIRSTAVDP 256 #define AVDPLEN 1 #define FILESETLEN 2 #define SPACEMAP_OFF 24 #define MAXID 16 static time_t mkfstime; static struct tm res; static long tzone; static char vsibuf[128]; static regid_t sunmicro = { 0, "*SUN SOLARIS UDF", 4, 2 }; static regid_t lvinfo = { 0, "*UDF LV Info", 0x50, 0x1, 4, 2 }; static regid_t partid = { 0, "+NSR02", 0 }; static regid_t udf_compliant = { 0, "*OSTA UDF Compliant", 0x50, 0x1, 0 }; static uint8_t osta_unicode[] = "OSTA Compressed Unicode"; static int bdevismounted; static int ismounted; static int directory; static char buf[MAXBSIZE]; static char buf2[MAXBSIZE]; static char lvid[MAXBSIZE]; uint32_t ecma_version = 2; static int serialnum = 1; /* Tag serial number */ static char udfs_label[128] = "*NoLabel*"; static int acctype = PART_ACC_OW; static uint32_t part_start; static uint32_t part_len; static uint32_t part_bmp_bytes; static uint32_t part_bmp_sectors; static int32_t part_unalloc = -1; static uint32_t filesetblock; /* Set by readvolseq for -m option */ static uint32_t oldfssize; static char *oldlabel; int main(int32_t argc, int8_t *argv[]) { long i; FILE *mnttab; struct mnttab mntp; char *special, *raw_special; struct stat statarea; struct ustat ustatarea; int32_t c; uint32_t temp_secsz; int isfs; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) { switch (c) { case 'F': string = optarg; if (strcmp(string, "udfs") != 0) { usage(); } break; case 'V': { char *opt_text; int opt_count; (void) fprintf(stdout, gettext("mkfs -F udfs ")); for (opt_count = 1; opt_count < argc; opt_count++) { opt_text = argv[opt_count]; if (opt_text) { (void) fprintf(stdout, " %s ", opt_text); } } (void) fprintf(stdout, "\n"); } break; case 'm': /* * return command line used * to create this FS */ mflag++; break; case 'o': /* * udfs specific options. */ string = optarg; while (*string != '\0') { if (match("N")) { Nflag++; } else if (match("psize=")) { number_flags = 0; sectorsize = number(BIG, "psize"); } else if (match("label=")) { for (i = 0; i < 31; i++) { if (*string == '\0') { break; } udfs_label[i] = *string++; } udfs_label[i] = '\0'; } else if (*string == '\0') { break; } else { (void) fprintf(stdout, gettext("illegal " "option: %s\n"), string); usage(); } if (*string == ',') { string++; } if (*string == ' ') { string++; } } break; case '?': usage(); break; } } (void) time(&mkfstime); if (optind > (argc - 1)) { usage(); } argc -= optind; argv = &argv[optind]; fsys = argv[0]; raw_special = getfullrawname(fsys); fsi = open(raw_special, 0); if (fsi < 0) { (void) fprintf(stdout, gettext("%s: cannot open\n"), fsys); exit(32); } fso = fsi; if ((temp_secsz = get_bsize()) != 0) { sectorsize = temp_secsz; } /* Get old file system information */ isfs = readvolseq(); if (mflag) { /* * Figure out the block size and * file system size and print the information */ if (isfs) dump_fscmd(fsys, fsi); else (void) printf(gettext( "[not currently a valid file system]\n")); exit(0); } /* * Get the disk size from the drive or VTOC for the N and N-256 * AVDPs and to make sure we don't want to create a file system * bigger than the partition. */ disk_size = get_last_block(); if (argc < 2 && disk_size == 0 || argc < 1) { usage(); } if (argc < 2) { (void) printf(gettext("No size specified, entire partition " "of %u sectors used\n"), disk_size); fssize = disk_size; } else { string = argv[1]; number_flags = 0; fssize = number(BIG, "size"); } if (fssize < 0) { (void) fprintf(stderr, gettext("Negative number of sectors(%d) not allowed\n"), fssize); exit(32); } if (fssize < (512 * sectorsize / DEV_BSIZE)) { (void) fprintf(stdout, gettext("size should be at least %d sectors\n"), (512 * sectorsize / DEV_BSIZE)); exit(32); } if (disk_size != 0) { if (fssize > disk_size) { (void) fprintf(stderr, gettext("Invalid size: %d " "larger than the partition size\n"), fssize); exit(32); } else if (fssize < disk_size) { unused = disk_size - fssize; (void) printf( gettext("File system size %d smaller than " "partition, %u sectors unused\n"), fssize, unused); } } else { /* Use passed-in size */ disk_size = fssize; } if (!Nflag) { special = getfullblkname(fsys); /* * If we found the block device name, * then check the mount table. * if mounted, write lock the file system * */ if ((special != NULL) && (*special != '\0')) { mnttab = fopen(MNTTAB, "r"); while ((getmntent(mnttab, &mntp)) == 0) { if (strcmp(special, mntp.mnt_special) == 0) { (void) fprintf(stdout, gettext("%s is mounted," " can't mkfs\n"), special); exit(32); } } (void) fclose(mnttab); } if ((bdevismounted) && (ismounted == 0)) { (void) fprintf(stdout, gettext("can't check mount point; ")); (void) fprintf(stdout, gettext("%s is mounted but not in mnttab(5)\n"), special); exit(32); } if (directory) { if (ismounted == 0) { (void) fprintf(stdout, gettext("%s is not mounted\n"), special); exit(32); } } fso = creat(fsys, 0666); if (fso < 0) { (void) fprintf(stdout, gettext("%s: cannot create\n"), fsys); exit(32); } if (stat(fsys, &statarea) < 0) { (void) fprintf(stderr, gettext("%s: %s: cannot stat\n"), argv[0], fsys); exit(32); } if (ustat(statarea.st_rdev, &ustatarea) >= 0) { (void) fprintf(stderr, gettext("%s is mounted, can't mkfs\n"), fsys); exit(32); } } else { /* * For the -N case, a file descriptor is needed for the llseek() * in wtfs(). See the comment in wtfs() for more information. * * Get a file descriptor that's read-only so that this code * doesn't accidentally write to the file. */ fso = open(fsys, O_RDONLY); if (fso < 0) { (void) fprintf(stderr, gettext("%s: cannot open\n"), fsys); exit(32); } } /* * Validate the given file system size. * Verify that its last block can actually be accessed. */ fssize = fssize / (sectorsize / DEV_BSIZE); if (fssize <= 0) { (void) fprintf(stdout, gettext("preposterous size %d. sectors\n"), fssize); exit(32); } fssize --; /* * verify device size */ rdfs(fssize - 1, sectorsize, buf); if ((sectorsize < DEV_BSIZE) || (sectorsize > MAXBSIZE)) { (void) fprintf(stdout, gettext("sector size must be" " between 512, 8192 bytes\n")); } if (!POWEROF2(sectorsize)) { (void) fprintf(stdout, gettext("sector size must be a power of 2, not %d\n"), sectorsize); exit(32); } if (Nflag) { exit(0); } (void) printf(gettext("Creating file system with sector size of " "%d bytes\n"), sectorsize); /* * Set up time stamp values */ mkfstime = time(0); (void) localtime_r(&mkfstime, &res); if (res.tm_isdst > 0) { tzone = altzone / 60; } else if (res.tm_isdst == 0) { tzone = tzone / 60; } else { tzone = 2047; /* Unknown */ } /* * Initialize the volume recognition sequence, the volume descriptor * sequences and the anchor pointer. */ volseqinit(); (void) fsync(fso); (void) close(fsi); (void) close(fso); return (0); } static void setstamp(tstamp_t *tp) { tp->ts_usec = 0; tp->ts_husec = 0; tp->ts_csec = 0; tp->ts_sec = res.tm_sec; tp->ts_min = res.tm_min; tp->ts_hour = res.tm_hour; tp->ts_day = res.tm_mday; tp->ts_month = res.tm_mon + 1; tp->ts_year = 1900 + res.tm_year; tp->ts_tzone = 0x1000 + (-tzone & 0xFFF); } static void setextad(extent_ad_t *eap, uint32_t len, uint32_t loc) { eap->ext_len = len; eap->ext_loc = loc; } static void setdstring(dstring_t *dp, char *cp, int len) { int32_t length; bzero(dp, len); length = strlen(cp); if (length > len - 3) { length = len - 3; } dp[len - 1] = length + 1; *dp++ = 8; (void) strncpy(dp, cp, len-2); } static void wtvolseq(tag_t *tp, daddr_t blk1, daddr_t blk2) { static uint32_t vdsn = 0; tp->tag_loc = blk1; switch (tp->tag_id) { case UD_PRI_VOL_DESC : ((struct pri_vol_desc *)tp)->pvd_vdsn = vdsn++; break; case UD_VOL_DESC_PTR : ((struct vol_desc_ptr *)tp)->vdp_vdsn = vdsn++; break; case UD_IMPL_USE_DESC : ((struct iuvd_desc *)tp)->iuvd_vdsn = vdsn++; break; case UD_PART_DESC : ((struct part_desc *)tp)->pd_vdsn = vdsn++; break; case UD_LOG_VOL_DESC : ((struct log_vol_desc *)tp)->lvd_vdsn = vdsn++; break; case UD_UNALL_SPA_DESC : ((struct unall_spc_desc *)tp)->ua_vdsn = vdsn++; break; } bzero(buf2, sectorsize); /* LINTED */ maketag(tp, (struct tag *)buf2); /* * Write at Main Volume Descriptor Sequence */ wtfs(blk1, sectorsize, buf2); tp->tag_loc = blk2; switch (tp->tag_id) { case UD_PRI_VOL_DESC : ((struct pri_vol_desc *)tp)->pvd_vdsn = vdsn++; break; case UD_VOL_DESC_PTR : ((struct vol_desc_ptr *)tp)->vdp_vdsn = vdsn++; break; case UD_IMPL_USE_DESC : ((struct iuvd_desc *)tp)->iuvd_vdsn = vdsn++; break; case UD_PART_DESC : ((struct part_desc *)tp)->pd_vdsn = vdsn++; break; case UD_LOG_VOL_DESC : ((struct log_vol_desc *)tp)->lvd_vdsn = vdsn++; break; case UD_UNALL_SPA_DESC : ((struct unall_spc_desc *)tp)->ua_vdsn = vdsn++; break; } maketag(tp, tp); /* * Write at Reserve Volume Descriptor Sequence */ wtfs(blk2, sectorsize, buf); } static void volseqinit(void) { struct tag *tp; struct nsr_desc *nsp; struct pri_vol_desc *pvdp; struct iuvd_desc *iudp; struct part_desc *pp; struct phdr_desc *php; struct log_vol_desc *lvp; long_ad_t *lap; struct pmap_typ1 *pmp; struct unall_spc_desc *uap; struct log_vol_int_desc *lvip; struct term_desc *tdp; struct anch_vol_desc_ptr *avp; struct lvid_iu *lviup; struct file_set_desc *fsp; struct file_entry *fp; struct icb_tag *icb; struct short_ad *sap; struct file_id *fip; struct space_bmap_desc *sbp; uint8_t *cp; daddr_t nextblock, endblock; int32_t volseq_sectors, nextlogblock, rootfelen, i; uint32_t mvds_loc, rvds_loc; bzero(buf, MAXBSIZE); /* * Starting from MAXBSIZE, clear out till 256 sectors. */ for (i = MAXBSIZE / sectorsize; i < FIRSTAVDP; i++) { wtfs(i, sectorsize, buf); } /* Zero out the avdp at N - 257 */ wtfs(fssize - 256, sectorsize, buf); /* * Leave 1st 32K for O.S. */ nextblock = VOLRECSTART / sectorsize; /* * Write BEA01/NSR02/TEA01 sequence. * Each one must be 2K bytes in length. */ nsp = (struct nsr_desc *)buf; nsp->nsr_str_type = 0; nsp->nsr_ver = 1; (void) strncpy((int8_t *)nsp->nsr_id, "BEA01", 5); nsp = (struct nsr_desc *)&buf[2048]; nsp->nsr_str_type = 0; nsp->nsr_ver = 1; (void) strncpy((int8_t *)nsp->nsr_id, "NSR02", 5); nsp = (struct nsr_desc *)&buf[4096]; nsp->nsr_str_type = 0; nsp->nsr_ver = 1; (void) strncpy((int8_t *)nsp->nsr_id, "TEA01", 5); wtfs(nextblock, 8192, buf); bzero(buf, MAXBSIZE); /* * Minimum length of volume sequences */ volseq_sectors = 16; /* * Round up to next 32K boundary for * volume descriptor sequences */ nextblock = VOLSEQSTART; bzero(buf, sectorsize); mvds_loc = VOLSEQSTART; rvds_loc = mvds_loc + volseq_sectors; /* * Primary Volume Descriptor */ /* LINTED */ pvdp = (struct pri_vol_desc *)buf; tp = &pvdp->pvd_tag; tp->tag_id = UD_PRI_VOL_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct pri_vol_desc) - sizeof (struct tag); pvdp->pvd_vdsn = 0; pvdp->pvd_pvdn = 0; setdstring(pvdp->pvd_vol_id, udfs_label, 32); pvdp->pvd_vsn = 1; pvdp->pvd_mvsn = 1; pvdp->pvd_il = 2; /* Single-volume */ pvdp->pvd_mil = 3; /* Multi-volume */ pvdp->pvd_csl = 1; /* CS0 */ pvdp->pvd_mcsl = 1; /* CS0 */ (void) sprintf(vsibuf, "%08X", SWAP_32((uint32_t)mkfstime)); setdstring(pvdp->pvd_vsi, vsibuf, 128); (void) strncpy(pvdp->pvd_vsi + 17, udfs_label, 128 - 17); setcharspec(&pvdp->pvd_desc_cs, 0, osta_unicode); setcharspec(&pvdp->pvd_exp_cs, 0, osta_unicode); setextad(&pvdp->pvd_vol_abs, 0, 0); setextad(&pvdp->pvd_vcn, 0, 0); bzero(&pvdp->pvd_appl_id, sizeof (regid_t)); setstamp(&pvdp->pvd_time); bcopy(&sunmicro, &pvdp->pvd_ii, sizeof (regid_t)); pvdp->pvd_flags = 0; wtvolseq(tp, nextblock, nextblock + volseq_sectors); nextblock++; /* * Implementation Use Descriptor */ bzero(buf, sectorsize); /* LINTED */ iudp = (struct iuvd_desc *)buf; tp = &iudp->iuvd_tag; tp->tag_id = UD_IMPL_USE_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct iuvd_desc) - sizeof (struct tag); iudp->iuvd_vdsn = 0; bcopy(&lvinfo, &iudp->iuvd_ii, sizeof (regid_t)); setcharspec(&iudp->iuvd_cset, 0, osta_unicode); setdstring(iudp->iuvd_lvi, udfs_label, 128); setdstring(iudp->iuvd_ifo1, "", 36); setdstring(iudp->iuvd_ifo2, "", 36); setdstring(iudp->iuvd_ifo3, "", 36); /* * info1,2,3 = user specified */ bcopy(&sunmicro, &iudp->iuvd_iid, sizeof (regid_t)); wtvolseq(tp, nextblock, nextblock + volseq_sectors); nextblock++; /* * Partition Descriptor */ bzero(buf, sectorsize); /* LINTED */ pp = (struct part_desc *)buf; tp = &pp->pd_tag; tp->tag_id = UD_PART_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct part_desc) - sizeof (struct tag); pp->pd_vdsn = 0; pp->pd_pflags = 1; /* Allocated */ pp->pd_pnum = 0; bcopy(&partid, &pp->pd_pcontents, sizeof (regid_t)); part_start = FIRSTAVDP + AVDPLEN; part_len = fssize - part_start; part_bmp_bytes = (part_len + NBBY - 1) / NBBY; part_bmp_sectors = (part_bmp_bytes + SPACEMAP_OFF + sectorsize - 1) / sectorsize; pp->pd_part_start = part_start; pp->pd_part_length = part_len; pp->pd_acc_type = acctype; nextlogblock = 0; /* * Do the partition header */ /* LINTED */ php = (struct phdr_desc *)&pp->pd_pc_use; /* * Set up unallocated space bitmap */ if (acctype == PART_ACC_RW || acctype == PART_ACC_OW) { php->phdr_usb.sad_ext_len = (part_bmp_bytes + SPACEMAP_OFF + sectorsize - 1) & (~(sectorsize - 1)); php->phdr_usb.sad_ext_loc = nextlogblock; part_unalloc = nextlogblock; nextlogblock += part_bmp_sectors; } bcopy(&sunmicro, &pp->pd_ii, sizeof (regid_t)); wtvolseq(tp, nextblock, nextblock + volseq_sectors); nextblock++; /* * Logical Volume Descriptor */ bzero(buf, sectorsize); /* LINTED */ lvp = (struct log_vol_desc *)buf; tp = &lvp->lvd_tag; tp->tag_id = UD_LOG_VOL_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct log_vol_desc) - sizeof (struct tag); lvp->lvd_vdsn = 0; setcharspec(&lvp->lvd_desc_cs, 0, osta_unicode); setdstring(lvp->lvd_lvid, udfs_label, 128); lvp->lvd_log_bsize = sectorsize; bcopy(&udf_compliant, &lvp->lvd_dom_id, sizeof (regid_t)); lap = (long_ad_t *)&lvp->lvd_lvcu; lap->lad_ext_len = FILESETLEN * sectorsize; filesetblock = nextlogblock; lap->lad_ext_loc = nextlogblock; lap->lad_ext_prn = 0; lvp->lvd_mtbl_len = 6; lvp->lvd_num_pmaps = 1; bcopy(&sunmicro, &lvp->lvd_ii, sizeof (regid_t)); /* LINTED */ pmp = (struct pmap_typ1 *)&lvp->lvd_pmaps; pmp->map1_type = 1; pmp->map1_length = 6; pmp->map1_vsn = SWAP_16(1); pmp->map1_pn = 0; tp->tag_crc_len = (char *)(pmp + 1) - buf - sizeof (struct tag); setextad(&lvp->lvd_int_seq_ext, INTSEQLEN, INTSEQSTART); wtvolseq(tp, nextblock, nextblock + volseq_sectors); nextblock++; /* * Unallocated Space Descriptor */ bzero(buf, sectorsize); /* LINTED */ uap = (struct unall_spc_desc *)buf; tp = &uap->ua_tag; tp->tag_id = UD_UNALL_SPA_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; uap->ua_vdsn = 0; uap->ua_nad = 0; tp->tag_crc_len = (char *)uap->ua_al_dsc - buf - sizeof (struct tag); wtvolseq(tp, nextblock, nextblock + volseq_sectors); nextblock++; /* * Terminating Descriptor */ bzero(buf, sectorsize); /* LINTED */ tdp = (struct term_desc *)buf; tp = &tdp->td_tag; tp->tag_id = UD_TERM_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct term_desc) - sizeof (struct tag); tp->tag_loc = nextblock; wtvolseq(tp, nextblock, nextblock + volseq_sectors); nextblock++; /* * Do the anchor volume descriptor */ if (nextblock > FIRSTAVDP) { (void) fprintf(stdout, gettext("Volume integrity sequence" " descriptors too long\n")); exit(32); } nextblock = FIRSTAVDP; bzero(buf, sectorsize); /* LINTED */ avp = (struct anch_vol_desc_ptr *)buf; tp = &avp->avd_tag; tp->tag_id = UD_ANCH_VOL_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct anch_vol_desc_ptr) - sizeof (struct tag); tp->tag_loc = nextblock; setextad(&avp->avd_main_vdse, volseq_sectors * sectorsize, mvds_loc); setextad(&avp->avd_res_vdse, volseq_sectors * sectorsize, rvds_loc); bzero(buf2, sectorsize); /* LINTED */ maketag(tp, (struct tag *)buf2); wtfs(nextblock, sectorsize, buf2); nextblock++; tp->tag_loc = fssize; /* LINTED */ maketag(tp, (struct tag *)buf2); wtfs(fssize, sectorsize, buf2); /* * File Set Descriptor */ bzero(buf, sectorsize); /* LINTED */ fsp = (struct file_set_desc *)&buf; tp = &fsp->fsd_tag; tp->tag_id = UD_FILE_SET_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct file_set_desc) - sizeof (struct tag); tp->tag_loc = nextlogblock; setstamp(&fsp->fsd_time); fsp->fsd_ilevel = 3; fsp->fsd_mi_level = 3; fsp->fsd_cs_list = 1; fsp->fsd_mcs_list = 1; fsp->fsd_fs_no = 0; fsp->fsd_fsd_no = 0; setcharspec(&fsp->fsd_lvidcs, 0, osta_unicode); setdstring(fsp->fsd_lvid, udfs_label, 128); setcharspec(&fsp->fsd_fscs, 0, osta_unicode); setdstring(fsp->fsd_fsi, udfs_label, 32); setdstring(fsp->fsd_cfi, "", 32); setdstring(fsp->fsd_afi, "", 32); lap = (long_ad_t *)&fsp->fsd_root_icb; lap->lad_ext_len = sectorsize; lap->lad_ext_loc = filesetblock + FILESETLEN; lap->lad_ext_prn = 0; bcopy(&udf_compliant, &fsp->fsd_did, sizeof (regid_t)); maketag(tp, tp); wtfs(nextlogblock + part_start, sectorsize, (char *)tp); nextlogblock++; /* * Terminating Descriptor */ bzero(buf, sectorsize); /* LINTED */ tdp = (struct term_desc *)buf; tp = &tdp->td_tag; tp->tag_id = UD_TERM_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct term_desc) - sizeof (struct tag); tp->tag_loc = nextlogblock; maketag(tp, tp); wtfs(nextlogblock + part_start, sectorsize, (char *)tp); nextlogblock++; if (nextlogblock > filesetblock + FILESETLEN) { (void) fprintf(stdout, gettext("File set descriptor too long\n")); exit(32); } nextlogblock = filesetblock + FILESETLEN; /* * Root File Entry */ bzero(buf, sectorsize); /* LINTED */ fp = (struct file_entry *)&buf; tp = &fp->fe_tag; tp->tag_id = UD_FILE_ENTRY; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_loc = nextlogblock; icb = &fp->fe_icb_tag; icb->itag_prnde = 0; icb->itag_strategy = STRAT_TYPE4; icb->itag_param = 0; /* what does this mean? */ icb->itag_max_ent = 1; icb->itag_ftype = FTYPE_DIRECTORY; icb->itag_lb_loc = 0; icb->itag_lb_prn = 0; icb->itag_flags = ICB_FLAG_ARCHIVE; fp->fe_uid = getuid(); fp->fe_gid = getgid(); fp->fe_perms = (0x1f << 10) | (0x5 << 5) | 0x5; fp->fe_lcount = 1; fp->fe_rec_for = 0; fp->fe_rec_dis = 0; fp->fe_rec_len = 0; fp->fe_info_len = sizeof (struct file_id); fp->fe_lbr = 1; setstamp(&fp->fe_acc_time); setstamp(&fp->fe_mod_time); setstamp(&fp->fe_attr_time); fp->fe_ckpoint = 1; bcopy(&sunmicro, &fp->fe_impl_id, sizeof (regid_t)); fp->fe_uniq_id = 0; fp->fe_len_ear = 0; fp->fe_len_adesc = sizeof (short_ad_t); /* LINTED */ sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear); sap->sad_ext_len = sizeof (struct file_id); sap->sad_ext_loc = nextlogblock + 1; rootfelen = (char *)(sap + 1) - buf; tp->tag_crc_len = rootfelen - sizeof (struct tag); maketag(tp, tp); wtfs(nextlogblock + part_start, sectorsize, (char *)tp); nextlogblock++; /* * Root Directory */ bzero(buf, sectorsize); /* LINTED */ fip = (struct file_id *)&buf; tp = &fip->fid_tag; tp->tag_id = UD_FILE_ID_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct file_id) - sizeof (struct tag); tp->tag_loc = nextlogblock; fip->fid_ver = 1; fip->fid_flags = FID_DIR | FID_PARENT; fip->fid_idlen = 0; fip->fid_iulen = 0; fip->fid_icb.lad_ext_len = sectorsize; /* rootfelen; */ fip->fid_icb.lad_ext_loc = nextlogblock - 1; fip->fid_icb.lad_ext_prn = 0; maketag(tp, tp); wtfs(nextlogblock + part_start, sectorsize, (char *)tp); nextlogblock++; /* * Now do the space bitmaps */ if (part_unalloc >= 0) { int size = sectorsize * part_bmp_sectors; sbp = (struct space_bmap_desc *)malloc(size); if (!sbp) { (void) fprintf(stdout, gettext("Can't allocate bitmap space\n")); exit(32); } bzero((char *)sbp, sectorsize * part_bmp_sectors); tp = &sbp->sbd_tag; tp->tag_id = UD_SPA_BMAP_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = 0; /* Don't do CRCs on bitmaps */ tp->tag_loc = part_unalloc; sbp->sbd_nbits = part_len; sbp->sbd_nbytes = part_bmp_bytes; maketag(tp, tp); if (part_unalloc >= 0) { int32_t i; cp = (uint8_t *)sbp + SPACEMAP_OFF; i = nextlogblock / NBBY; cp[i++] = (0xff << (nextlogblock % NBBY)) & 0xff; while (i < part_bmp_bytes) cp[i++] = 0xff; if (part_len % NBBY) cp[--i] = (unsigned)0xff >> (NBBY - part_len % NBBY); wtfs(part_unalloc + part_start, size, (char *)tp); } free((char *)sbp); } /* * Volume Integrity Descriptor */ nextblock = INTSEQSTART; endblock = nextblock + INTSEQLEN / sectorsize; /* LINTED */ lvip = (struct log_vol_int_desc *)&lvid; tp = &lvip->lvid_tag; tp->tag_id = UD_LOG_VOL_INT; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_loc = nextblock; setstamp(&lvip->lvid_tstamp); lvip->lvid_int_type = LOG_VOL_CLOSE_INT; setextad(&lvip->lvid_nie, 0, 0); lvip->lvid_npart = 1; lvip->lvid_liu = 0x2e; lvip->lvid_uniqid = MAXID + 1; lvip->lvid_fst[0] = part_len - nextlogblock; /* Free space */ lvip->lvid_fst[1] = part_len; /* Size */ lviup = (struct lvid_iu *)&lvip->lvid_fst[2]; bcopy(&sunmicro, &lviup->lvidiu_regid, sizeof (regid_t)); lviup->lvidiu_nfiles = 0; lviup->lvidiu_ndirs = 1; lviup->lvidiu_mread = 0x102; lviup->lvidiu_mwrite = 0x102; lviup->lvidiu_maxwr = 0x150; tp->tag_crc_len = sizeof (struct log_vol_int_desc) + lvip->lvid_liu - sizeof (struct tag); maketag(tp, tp); wtfs(nextblock, sectorsize, (char *)tp); nextblock++; /* * Terminating Descriptor */ bzero(buf, sectorsize); /* LINTED */ tdp = (struct term_desc *)buf; tp = &tdp->td_tag; tp->tag_id = UD_TERM_DESC; tp->tag_desc_ver = ecma_version; tp->tag_sno = serialnum; tp->tag_crc_len = sizeof (struct term_desc) - sizeof (struct tag); tp->tag_loc = nextblock; maketag(tp, tp); wtfs(nextblock, sectorsize, (char *)tp); nextblock++; /* Zero out the rest of the LVI extent */ bzero(buf, sectorsize); while (nextblock < endblock) wtfs(nextblock++, sectorsize, buf); } /* * read a block from the file system */ static void rdfs(daddr_t bno, int size, char *bf) { int n, saverr; if (llseek(fsi, (offset_t)bno * sectorsize, 0) < 0) { saverr = errno; (void) fprintf(stderr, gettext("seek error on sector %ld: %s\n"), bno, strerror(saverr)); exit(32); } n = read(fsi, bf, size); if (n != size) { saverr = errno; (void) fprintf(stderr, gettext("read error on sector %ld: %s\n"), bno, strerror(saverr)); exit(32); } } /* * write a block to the file system */ static void wtfs(daddr_t bno, int size, char *bf) { int n, saverr; if (fso == -1) return; if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) { saverr = errno; (void) fprintf(stderr, gettext("seek error on sector %ld: %s\n"), bno, strerror(saverr)); exit(32); } if (Nflag) return; n = write(fso, bf, size); if (n != size) { saverr = errno; (void) fprintf(stderr, gettext("write error on sector %ld: %s\n"), bno, strerror(saverr)); exit(32); } } static void usage(void) { (void) fprintf(stderr, gettext("udfs usage: mkfs [-F FSType] [-V]" " [-m] [-o options] special size(sectors)\n")); (void) fprintf(stderr, gettext(" -m : dump fs cmd line used to make" " this partition\n")); (void) fprintf(stderr, gettext(" -V : print this command line and return\n")); (void) fprintf(stderr, gettext(" -o : udfs options: :psize=%d:label=%s\n"), sectorsize, udfs_label); (void) fprintf(stderr, gettext("NOTE that all -o suboptions: must" " be separated only by commas so as to\n")); (void) fprintf(stderr, gettext("be parsed as a single argument\n")); exit(32); } /*ARGSUSED*/ static void dump_fscmd(char *fsys, int fsi) { (void) printf(gettext("mkfs -F udfs -o ")); (void) printf("psize=%d,label=\"%s\" %s %d\n", sectorsize, oldlabel, fsys, oldfssize); } /* number ************************************************************* */ /* */ /* Convert a numeric arg to binary */ /* */ /* Arg: big - maximum valid input number */ /* Global arg: string - pointer to command arg */ /* */ /* Valid forms: 123 | 123k | 123*123 | 123x123 */ /* */ /* Return: converted number */ /* */ /* ******************************************************************** */ static int32_t number(long big, char *param) { char *cs; int64_t n = 0; int64_t cut = BIG; int32_t minus = 0; #define FOUND_MULT 0x1 #define FOUND_K 0x2 cs = string; if (*cs == '-') { minus = 1; cs++; } n = 0; while ((*cs != ' ') && (*cs != '\0') && (*cs != ',')) { if ((*cs >= '0') && (*cs <= '9')) { n = n * 10 + *cs - '0'; cs++; } else if ((*cs == '*') || (*cs == 'x')) { if (number_flags & FOUND_MULT) { (void) fprintf(stderr, gettext("mkfs: only one \"*\" " "or \"x\" allowed\n")); exit(2); } number_flags |= FOUND_MULT; cs++; string = cs; n = n * number(big, param); cs = string; continue; } else if (*cs == 'k') { if (number_flags & FOUND_K) { (void) fprintf(stderr, gettext("mkfs: only one \"k\" allowed\n")); exit(2); } number_flags |= FOUND_K; n = n * 1024; cs++; continue; } else { (void) fprintf(stderr, gettext("mkfs: bad numeric arg: \"%s\"\n"), string); exit(2); } } if (n > cut) { (void) fprintf(stderr, gettext("mkfs: value for %s overflowed\n"), param); exit(2); } if (minus) { n = -n; } if ((n > big) || (n < 0)) { (void) fprintf(stderr, gettext("mkfs: argument %s out of range\n"), param); exit(2); } string = cs; return ((int32_t)n); } /* match ************************************************************** */ /* */ /* Compare two text strings for equality */ /* */ /* Arg: s - pointer to string to match with a command arg */ /* Global arg: string - pointer to command arg */ /* */ /* Return: 1 if match, 0 if no match */ /* If match, also reset `string' to point to the text */ /* that follows the matching text. */ /* */ /* ******************************************************************** */ static int match(char *s) { char *cs; cs = string; while (*cs++ == *s) { if (*s++ == '\0') { goto true; } } if (*s != '\0') { return (0); } true: cs--; string = cs; return (1); } static uint32_t get_bsize(void) { struct dk_cinfo info; struct fd_char fd_char; struct dk_minfo dkminfo; if (ioctl(fso, DKIOCINFO, &info) < 0) { perror("mkfs DKIOCINFO "); (void) fprintf(stdout, gettext("DKIOCINFO failed using psize = 2048" " for creating file-system\n")); return (0); } switch (info.dki_ctype) { case DKC_CDROM : return (2048); case DKC_SCSI_CCS : if (ioctl(fso, DKIOCGMEDIAINFO, &dkminfo) != -1) { if (dkminfo.dki_lbsize != 0 && POWEROF2(dkminfo.dki_lbsize / DEV_BSIZE) && dkminfo.dki_lbsize != DEV_BSIZE) { fprintf(stderr, gettext("The device sector size " "%u is not supported by udfs!\n"), dkminfo.dki_lbsize); (void) close(fso); exit(1); } } /* FALLTHROUGH */ case DKC_INTEL82072 : /* FALLTHROUGH */ case DKC_INTEL82077 : /* FALLTHROUGH */ case DKC_DIRECT : if (ioctl(fso, FDIOGCHAR, &fd_char) >= 0) { return (fd_char.fdc_sec_size); } /* FALLTHROUGH */ case DKC_PCMCIA_ATA : return (512); default : return (0); } } /* * Read in the volume sequences descriptors. */ static int readvolseq(void) { struct tag *tp; uint8_t *cp, *end; int err; struct pri_vol_desc *pvolp; struct part_desc *partp = NULL; struct log_vol_desc *logvp = NULL; struct anch_vol_desc_ptr *avp; char *main_vdbuf; uint32_t nextblock; avp = (struct anch_vol_desc_ptr *)malloc(sectorsize); rdfs(FIRSTAVDP, sectorsize, (char *)avp); tp = (struct tag *)avp; err = verifytag(tp, FIRSTAVDP, tp, UD_ANCH_VOL_DESC); if (err) return (0); main_vdbuf = malloc(avp->avd_main_vdse.ext_len); if (main_vdbuf == NULL) { (void) fprintf(stderr, gettext("Cannot allocate space for " "volume sequences\n")); exit(32); } rdfs(avp->avd_main_vdse.ext_loc, avp->avd_main_vdse.ext_len, main_vdbuf); end = (uint8_t *)main_vdbuf + avp->avd_main_vdse.ext_len; nextblock = avp->avd_main_vdse.ext_loc; for (cp = (uint8_t *)main_vdbuf; cp < end; cp += sectorsize, nextblock++) { /* LINTED */ tp = (struct tag *)cp; err = verifytag(tp, nextblock, tp, 0); if (err) continue; switch (tp->tag_id) { case UD_PRI_VOL_DESC: /* Bump serial number, according to spec. */ serialnum = tp->tag_sno + 1; pvolp = (struct pri_vol_desc *)tp; oldlabel = pvolp->pvd_vol_id + 1; break; case UD_ANCH_VOL_DESC: avp = (struct anch_vol_desc_ptr *)tp; break; case UD_VOL_DESC_PTR: break; case UD_IMPL_USE_DESC: break; case UD_PART_DESC: partp = (struct part_desc *)tp; part_start = partp->pd_part_start; part_len = partp->pd_part_length; oldfssize = part_start + part_len; break; case UD_LOG_VOL_DESC: logvp = (struct log_vol_desc *)tp; break; case UD_UNALL_SPA_DESC: break; case UD_TERM_DESC: goto done; break; case UD_LOG_VOL_INT: break; default: break; } } done: if (!partp || !logvp) { return (0); } return (1); } uint32_t get_last_block(void) { struct vtoc vtoc; struct dk_cinfo dki_info; if (ioctl(fsi, DKIOCGVTOC, (intptr_t)&vtoc) != 0) { (void) fprintf(stderr, gettext("Unable to read VTOC\n")); return (0); } if (vtoc.v_sanity != VTOC_SANE) { (void) fprintf(stderr, gettext("Vtoc.v_sanity != VTOC_SANE\n")); return (0); } if (ioctl(fsi, DKIOCINFO, (intptr_t)&dki_info) != 0) { (void) fprintf(stderr, gettext("Could not get the slice information\n")); return (0); } if (dki_info.dki_partition > V_NUMPAR) { (void) fprintf(stderr, gettext("dki_info.dki_partition > V_NUMPAR\n")); return (0); } return ((uint32_t)vtoc.v_part[dki_info.dki_partition].p_size); }