# # 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 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # SUBDIR1= fstyp SUBDIR2= fsck fsdb labelit mkfs mount SUBDIRS= $(SUBDIR1) $(SUBDIR2) all: TARGET= all install: TARGET= install clean: TARGET= clean clobber: TARGET= clobber catalog: TARGET= catalog # for messaging catalog # POFILE= udfs.po # Hammerhead: GNU Make % substitution only replaces first %; use foreach. POFILES= $(foreach d,$(SUBDIR2),$(d)/$(d).po) .KEEP_STATE: .PARALLEL: $(SUBDIRS) all install clean clobber: $(SUBDIRS) catalog: $(POFILE) $(POFILE): $(SUBDIR2) $(RM) $@ cat $(POFILES) > $@ $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: /* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ud_lib.h" extern char *getfullrawname(char *); static int32_t ud_get_ecma_ver(ud_handle_t, uint32_t); static int32_t ud_get_fs_bsize(ud_handle_t, uint32_t, uint32_t *); static int32_t ud_parse_fill_vds(ud_handle_t, struct vds *, uint32_t, uint32_t); static int32_t ud_read_and_translate_lvd(ud_handle_t, uint32_t, uint32_t); static int32_t ud_get_latest_lvid(ud_handle_t, uint32_t, uint32_t); static int32_t ud_get_latest_fsd(ud_handle_t, uint16_t, uint32_t, uint32_t); static uint16_t ud_crc(uint8_t *, int32_t); static int32_t UdfTxName(uint16_t *, int32_t); static int32_t UncompressUnicode(int32_t, uint8_t *, uint16_t *); static int32_t ud_compressunicode(int32_t, int32_t, uint16_t *, uint8_t *); static int32_t ud_convert2utf8(uint8_t *, uint8_t *, int32_t); static int32_t ud_convert2utf16(uint8_t *, uint8_t *, int32_t); int ud_init(int fd, ud_handle_t *hp) { struct ud_handle *h; if ((h = calloc(1, sizeof (struct ud_handle))) == NULL) { return (ENOMEM); } h->fd = fd; *hp = h; return (0); } void ud_fini(ud_handle_t h) { free(h); } /* ARGSUSED */ int32_t ud_open_dev(ud_handle_t h, char *special, uint32_t flags) { char *temp; struct stat i_stat, r_stat; (void) bzero(&i_stat, sizeof (struct stat)); (void) bzero(&r_stat, sizeof (struct stat)); temp = special; /* * Get the stat structure */ if (stat(special, &i_stat) == 0) { if ((i_stat.st_mode & S_IFMT) == S_IFBLK) { /* * Block device try to convert to raw device */ temp = getfullrawname(special); /* * Stat the converted device name and verify * both the raw and block device belong to * the same device */ if (stat(temp, &r_stat) < 0) { temp = special; } else { if (((r_stat.st_mode & S_IFMT) == S_IFBLK) || (r_stat.st_rdev != i_stat.st_rdev)) { temp = special; } } } } /* * Now finally open the device */ h->fd = open(temp, flags); return (h->fd); } /* ARGSUSED */ void ud_close_dev(ud_handle_t h) { /* * Too simple Just close it */ (void) close(h->fd); } int32_t ud_read_dev(ud_handle_t h, uint64_t offset, uint8_t *buf, uint32_t count) { /* * Seek to the given offset */ if (lseek(h->fd, offset, SEEK_SET) == -1) { return (1); } /* * Read the required number of bytes */ if (read(h->fd, buf, count) != count) { return (1); } return (0); } int32_t ud_write_dev(ud_handle_t h, uint64_t offset, uint8_t *buf, uint32_t count) { /* * Seek to the given offset */ if (lseek(h->fd, offset, SEEK_SET) == -1) { return (1); } /* * Read the appropriate number of bytes */ if (write(h->fd, buf, count) != count) { return (1); } return (0); } /* ----- BEGIN Read and translate the on disk VDS to IN CORE format -------- */ int32_t ud_fill_udfs_info(ud_handle_t h) { struct anch_vol_desc_ptr *avdp = NULL; uint32_t offset = 0; if (ioctl(h->fd, CDROMREADOFFSET, &offset) == -1) { offset = 0; } h->udfs.flags = INVALID_UDFS; h->udfs.ecma_version = ud_get_ecma_ver(h, offset); if (h->udfs.ecma_version == UD_ECMA_UNKN) { return (1); } h->udfs.lbsize = ud_get_fs_bsize(h, offset, &h->udfs.avdp_loc); if (h->udfs.lbsize == 0) { return (2); } h->udfs.avdp_len = lb_roundup(512, h->udfs.lbsize); if ((avdp = (struct anch_vol_desc_ptr *) malloc(h->udfs.lbsize)) == NULL) { return (3); } if (ud_read_dev(h, h->udfs.avdp_loc * h->udfs.lbsize, (uint8_t *)avdp, h->udfs.lbsize) != 0) { free(avdp); return (4); } if (ud_verify_tag(h, &avdp->avd_tag, UD_ANCH_VOL_DESC, h->udfs.avdp_loc, 1, 0) != 0) { free(avdp); return (5); } h->udfs.mvds_loc = SWAP_32(avdp->avd_main_vdse.ext_loc); h->udfs.mvds_len = SWAP_32(avdp->avd_main_vdse.ext_len); h->udfs.rvds_loc = SWAP_32(avdp->avd_res_vdse.ext_loc); h->udfs.rvds_len = SWAP_32(avdp->avd_res_vdse.ext_len); free(avdp); /* * get information from mvds and rvds */ if (ud_parse_fill_vds(h, &h->udfs.mvds, h->udfs.mvds_loc, h->udfs.mvds_len) == 0) { h->udfs.flags |= VALID_MVDS; } if (ud_parse_fill_vds(h, &h->udfs.rvds, h->udfs.rvds_loc, h->udfs.rvds_len) == 0) { h->udfs.flags |= VALID_RVDS; } if ((h->udfs.flags & (VALID_MVDS | VALID_RVDS)) == 0) { return (6); } /* * If we are here we have * a valid Volume Descriptor Seqence * Read and understand lvd */ if (h->udfs.flags & VALID_MVDS) { if (ud_read_and_translate_lvd(h, h->udfs.mvds.lvd_loc, h->udfs.mvds.lvd_len) != 0) { return (7); } } else { if (ud_read_and_translate_lvd(h, h->udfs.rvds.lvd_loc, h->udfs.rvds.lvd_len) != 0) { return (8); } } h->udfs.flags |= VALID_UDFS; return (0); } static int32_t ud_get_ecma_ver(ud_handle_t h, uint32_t offset) { uint8_t *buf; uint64_t off; uint64_t end_off; struct nsr_desc *ndsc; uint32_t ecma_ver = UD_ECMA_UNKN; /* * Allocate a buffer of size UD_VOL_REC_BSZ */ if ((buf = (uint8_t *)malloc(UD_VOL_REC_BSZ)) == NULL) { /* * Uh could not even allocate this much */ goto end; } /* * Start from 32k and keep reading 2k blocks we * should be able to find NSR if we have one by 256 * 2k bytes */ off = offset * 2048 + UD_VOL_REC_START; end_off = offset * 2048 + UD_VOL_REC_END; for (; off < end_off; off += UD_VOL_REC_BSZ) { if (ud_read_dev(h, off, buf, UD_VOL_REC_BSZ) == 0) { ndsc = (struct nsr_desc *)buf; /* * Is this either NSR02 or NSR03 */ if ((ndsc->nsr_str_type == 0) && (ndsc->nsr_ver == 1) && (ndsc->nsr_id[0] == 'N') && (ndsc->nsr_id[1] == 'S') && (ndsc->nsr_id[2] == 'R') && (ndsc->nsr_id[3] == '0') && ((ndsc->nsr_id[4] == '2') || (ndsc->nsr_id[4] == '3'))) { (void) strncpy((char *)h->udfs.ecma_id, (char *)ndsc->nsr_id, 5); switch (ndsc->nsr_id[4]) { case '2' : /* * ECMA 167/2 */ ecma_ver = UD_ECMA_VER2; goto end; case '3' : /* * ECMA 167/3 */ ecma_ver = UD_ECMA_VER3; goto end; } } } } end: /* * Cleanup */ free(buf); return (ecma_ver); } static uint32_t last_block_index[] = {0, 0, 256, 2, 2 + 256, 150, 150 + 256, 152, 152 + 256}; static int32_t ud_get_fs_bsize(ud_handle_t h, uint32_t offset, uint32_t *avd_loc) { uint64_t off; int32_t index, bsize, shift, end_index; uint32_t num_blocks, sub_blk; uint8_t *buf = NULL; struct anch_vol_desc_ptr *avdp; if ((buf = (uint8_t *)malloc(MAXBSIZE)) == NULL) { return (0); } /* * If we could figure out the last block * search at 256, N, N - 256 blocks * otherwise just check at 256 */ if (ud_get_num_blks(h, &num_blocks) != 0) { end_index = 1; num_blocks = 0; } else { end_index = sizeof (last_block_index) / 4; } for (index = 0; index < end_index; index++) { sub_blk = last_block_index[index]; /* * Start guessing from DEV_BSIZE to MAXBSIZE */ for (bsize = DEV_BSIZE, shift = 0; bsize <= MAXBSIZE; bsize <<= 1, shift++) { if (index == 0) { /* * Check if we atleast have 256 of bsize * blocks on the device */ if ((end_index == 0) || (num_blocks > (256 << shift))) { *avd_loc = 256; if (bsize <= 2048) { *avd_loc += offset * 2048 / bsize; } else { *avd_loc += offset / (bsize / 2048); } } else { continue; } } else { /* * Calculate the bsize avd block */ if ((num_blocks) && (num_blocks > (sub_blk << shift))) { *avd_loc = (num_blocks >> shift) - sub_blk; } else { continue; } } off = (uint64_t)*avd_loc * bsize; /* * Read bsize bytes at off */ if (ud_read_dev(h, off, buf, bsize) != 0) { continue; } /* * Check if we have a Anchor Volume Descriptor here */ /* LINTED */ avdp = (struct anch_vol_desc_ptr *)buf; if (ud_verify_tag(h, &avdp->avd_tag, UD_ANCH_VOL_DESC, *avd_loc, 1, 0) != 0) { continue; } goto end; } } end: if (bsize > MAXBSIZE) { bsize = 0; *avd_loc = 0; } free(buf); return (bsize); } static int32_t ud_parse_fill_vds(ud_handle_t h, struct vds *v, uint32_t vds_loc, uint32_t vds_len) { uint8_t *addr, *taddr, *eaddr; uint16_t id; int32_t i; uint64_t off; struct tag *tag; struct pri_vol_desc *pvd; struct log_vol_desc *lvd; struct vol_desc_ptr *vds; struct unall_spc_desc *usd; begin: if ((addr = (uint8_t *)malloc(vds_len)) == NULL) { return (1); } off = vds_loc * h->udfs.lbsize; if (ud_read_dev(h, off, addr, vds_len) != 0) { goto end; } for (taddr = addr, eaddr = addr + h->udfs.mvds_len; taddr < eaddr; taddr += h->udfs.lbsize, vds_loc ++) { /* LINTED */ tag = (struct tag *)taddr; id = SWAP_16(tag->tag_id); /* * If you cannot verify the tag just skip it * This is not a fatal error */ if (ud_verify_tag(h, tag, id, vds_loc, 1, 0) != 0) { continue; } switch (id) { case UD_PRI_VOL_DESC : /* * Primary Volume Descriptor */ /* LINTED */ pvd = (struct pri_vol_desc *)taddr; if ((v->pvd_len == 0) || (SWAP_32(pvd->pvd_vdsn) > v->pvd_vdsn)) { v->pvd_vdsn = SWAP_32(pvd->pvd_vdsn); v->pvd_loc = vds_loc; v->pvd_len = h->udfs.lbsize; } break; case UD_VOL_DESC_PTR : /* * Curent sequence is continued from * the location pointed by vdp */ /* LINTED */ vds = (struct vol_desc_ptr *)taddr; if (SWAP_32(vds->vdp_nvdse.ext_len) != 0) { vds_loc = SWAP_32(vds->vdp_nvdse.ext_loc); vds_len = SWAP_32(vds->vdp_nvdse.ext_len); free(addr); goto begin; } break; case UD_IMPL_USE_DESC : /* * Implementation Use Volume Descriptor */ v->iud_loc = vds_loc; v->iud_len = lb_roundup(512, h->udfs.lbsize); break; case UD_PART_DESC : { struct ud_part *p; struct phdr_desc *ph; struct part_desc *pd; /* * Partition Descriptor */ /* LINTED */ pd = (struct part_desc *)taddr; for (i = 0; i < h->n_parts; i++) { p = &h->part[i]; if ((SWAP_16(pd->pd_pnum) == p->udp_number) && (SWAP_32(pd->pd_vdsn) > p->udp_seqno)) { break; } } v->part_loc[i] = vds_loc; v->part_len[i] = lb_roundup(512, h->udfs.lbsize); p = &h->part[i]; p->udp_number = SWAP_16(pd->pd_pnum); p->udp_seqno = SWAP_32(pd->pd_vdsn); p->udp_access = SWAP_32(pd->pd_acc_type); p->udp_start = SWAP_32(pd->pd_part_start); p->udp_length = SWAP_32(pd->pd_part_length); /* LINTED */ ph = (struct phdr_desc *)pd->pd_pc_use; if (ph->phdr_ust.sad_ext_len) { p->udp_flags = UDP_SPACETBLS; p->udp_unall_loc = SWAP_32(ph->phdr_ust.sad_ext_loc); p->udp_unall_len = SWAP_32(ph->phdr_ust.sad_ext_len); p->udp_freed_loc = SWAP_32(ph->phdr_fst.sad_ext_loc); p->udp_freed_len = SWAP_32(ph->phdr_fst.sad_ext_len); } else { p->udp_flags = UDP_BITMAPS; p->udp_unall_loc = SWAP_32(ph->phdr_usb.sad_ext_loc); p->udp_unall_len = SWAP_32(ph->phdr_usb.sad_ext_len); p->udp_freed_loc = SWAP_32(ph->phdr_fsb.sad_ext_loc); p->udp_freed_len = SWAP_32(ph->phdr_fsb.sad_ext_len); } if (i == h->n_parts) { h->n_parts ++; } } break; case UD_LOG_VOL_DESC : /* * Logical Volume Descriptor */ /* LINTED */ lvd = (struct log_vol_desc *)taddr; if ((v->lvd_len == 0) || (SWAP_32(lvd->lvd_vdsn) > v->lvd_vdsn)) { v->lvd_vdsn = SWAP_32(lvd->lvd_vdsn); v->lvd_loc = vds_loc; v->lvd_len = ((uint32_t) &((struct log_vol_desc *)0)->lvd_pmaps); v->lvd_len = lb_roundup(v->lvd_len, h->udfs.lbsize); } break; case UD_UNALL_SPA_DESC : /* * Unallocated Space Descriptor */ /* LINTED */ usd = (struct unall_spc_desc *)taddr; v->usd_loc = vds_loc; v->usd_len = ((uint32_t) &((unall_spc_desc_t *)0)->ua_al_dsc) + SWAP_32(usd->ua_nad) * sizeof (struct extent_ad); v->usd_len = lb_roundup(v->usd_len, h->udfs.lbsize); break; case UD_TERM_DESC : /* * Success fully completed */ goto end; default : /* * If you donot undetstand any tag just skip * it. This is not a fatal error */ break; } } end: free(addr); if ((v->pvd_len == 0) || (v->part_len[0] == 0) || (v->lvd_len == 0)) { return (1); } return (0); } static int32_t ud_read_and_translate_lvd(ud_handle_t h, uint32_t lvd_loc, uint32_t lvd_len) { caddr_t addr; uint16_t fsd_prn; uint32_t fsd_loc, fsd_len; uint32_t lvds_loc, lvds_len; uint64_t off; struct log_vol_desc *lvd = NULL; int32_t max_maps, i, mp_sz, index; struct ud_map *m; struct pmap_hdr *ph; struct pmap_typ1 *typ1; struct pmap_typ2 *typ2; if (lvd_len == 0) { return (1); } if ((lvd = (struct log_vol_desc *) malloc(lvd_len)) == NULL) { return (1); } off = lvd_loc * h->udfs.lbsize; if (ud_read_dev(h, off, (uint8_t *)lvd, lvd_len) != 0) { free(lvd); return (1); } if (ud_verify_tag(h, &lvd->lvd_tag, UD_LOG_VOL_DESC, lvd_loc, 1, 0) != 0) { free(lvd); return (1); } /* * Take care of maps */ max_maps = SWAP_32(lvd->lvd_num_pmaps); ph = (struct pmap_hdr *)lvd->lvd_pmaps; for (h->n_maps = index = 0; index < max_maps; index++) { m = &h->maps[h->n_maps]; switch (ph->maph_type) { case MAP_TYPE1 : /* LINTED */ typ1 = (struct pmap_typ1 *)ph; m->udm_flags = UDM_MAP_NORM; m->udm_vsn = SWAP_16(typ1->map1_vsn); m->udm_pn = SWAP_16(typ1->map1_pn); h->n_maps++; break; case MAP_TYPE2 : /* LINTED */ typ2 = (struct pmap_typ2 *)ph; if (strncmp(typ2->map2_pti.reg_id, UDF_VIRT_PART, 23) == 0) { m->udm_flags = UDM_MAP_VPM; m->udm_vsn = SWAP_16(typ2->map2_vsn); m->udm_pn = SWAP_16(typ2->map2_pn); } else if (strncmp(typ2->map2_pti.reg_id, UDF_SPAR_PART, 23) == 0) { if ((SWAP_16(typ2->map2_pl) != 32) || (typ2->map2_nst < 1) || (typ2->map2_nst > 4)) { break; } m->udm_flags = UDM_MAP_SPM; m->udm_vsn = SWAP_16(typ2->map2_vsn); m->udm_pn = SWAP_16(typ2->map2_pn); m->udm_plen = SWAP_16(typ2->map2_pl); m->udm_nspm = typ2->map2_nst; m->udm_spsz = SWAP_32(typ2->map2_sest); mp_sz = lb_roundup(m->udm_spsz, h->udfs.lbsize); if ((addr = malloc(mp_sz * m->udm_nspm)) == NULL) { break; } for (i = 0; i < m->udm_nspm; i++) { m->udm_loc[i] = SWAP_32(typ2->map2_st[index]); m->udm_spaddr[i] = addr + i * mp_sz; off = m->udm_loc[i] * h->udfs.lbsize; if (ud_read_dev(h, off, (uint8_t *)m->udm_spaddr[i], mp_sz) != 0) { m->udm_spaddr[i] = NULL; continue; } } } h->n_maps++; default : break; } ph = (struct pmap_hdr *)(((uint8_t *)h) + ph->maph_length); } lvds_loc = SWAP_32(lvd->lvd_int_seq_ext.ext_loc); lvds_len = SWAP_32(lvd->lvd_int_seq_ext.ext_len); fsd_prn = SWAP_16(lvd->lvd_lvcu.lad_ext_prn); fsd_loc = SWAP_32(lvd->lvd_lvcu.lad_ext_loc); fsd_len = SWAP_32(lvd->lvd_lvcu.lad_ext_len); free(lvd); /* * Get the latest LVID */ if (ud_get_latest_lvid(h, lvds_loc, lvds_len) != 0) { return (1); } if (ud_get_latest_fsd(h, fsd_prn, fsd_loc, fsd_len) != 0) { return (1); } return (0); } static int32_t ud_get_latest_lvid(ud_handle_t h, uint32_t lvds_loc, uint32_t lvds_len) { uint8_t *addr, *taddr, *eaddr; uint16_t id; uint64_t off; struct tag *tag; struct log_vol_int_desc *lvid; begin: if ((addr = (uint8_t *)malloc(lvds_len)) == NULL) { return (1); } off = lvds_loc * h->udfs.lbsize; if (ud_read_dev(h, off, addr, lvds_len) != 0) { goto end; } for (taddr = addr, eaddr = addr + h->udfs.mvds_len; taddr < eaddr; taddr += h->udfs.lbsize, lvds_loc ++) { /* LINTED */ tag = (struct tag *)taddr; id = SWAP_16(tag->tag_id); /* * If you cannot verify the tag just skip it * This is not a fatal error */ if (ud_verify_tag(h, tag, id, lvds_loc, 1, 0) != 0) { continue; } switch (id) { case UD_LOG_VOL_INT : /* * Logical Volume Integrity Descriptor */ /* LINTED */ lvid = (struct log_vol_int_desc *)taddr; h->udfs.lvid_loc = lvds_loc; h->udfs.lvid_len = ((uint32_t) &((struct log_vol_int_desc *)0)->lvid_fst) + SWAP_32(lvid->lvid_npart) * 8 + SWAP_32(lvid->lvid_liu); h->udfs.lvid_len = lb_roundup(h->udfs.lvid_len, h->udfs.lbsize); /* * It seems we have a next integrity * sequence */ if (SWAP_32(lvid->lvid_nie.ext_len) != 0) { free(addr); lvds_loc = SWAP_32(lvid->lvid_nie.ext_loc); lvds_len = SWAP_32(lvid->lvid_nie.ext_len); goto begin; } goto end; case UD_TERM_DESC : /* * Success fully completed */ goto end; default : /* * If you donot undetstand any tag just skip * it. This is not a fatal error */ break; } } end: free(addr); if (h->udfs.lvid_len == 0) { return (1); } return (0); } static int32_t ud_get_latest_fsd(ud_handle_t h, uint16_t fsd_prn, uint32_t fsd_loc, uint32_t fsd_len) { uint8_t *addr, *taddr, *eaddr; uint16_t id; uint64_t off; uint32_t fsds_loc, fsds_len; struct tag *tag; struct file_set_desc *fsd; uint32_t old_fsn = 0; begin: h->udfs.fsds_prn = fsd_prn; h->udfs.fsds_loc = fsd_loc; h->udfs.fsds_len = fsd_len; fsds_loc = ud_xlate_to_daddr(h, fsd_prn, fsd_loc); fsds_len = lb_roundup(fsd_len, h->udfs.lbsize); if ((addr = (uint8_t *)malloc(fsds_len)) == NULL) { return (1); } off = fsds_loc * h->udfs.lbsize; if (ud_read_dev(h, off, addr, fsds_len) != 0) { goto end; } for (taddr = addr, eaddr = addr + h->udfs.mvds_len; taddr < eaddr; taddr += h->udfs.lbsize, fsds_loc ++) { /* LINTED */ tag = (struct tag *)taddr; id = SWAP_16(tag->tag_id); /* * If you cannot verify the tag just skip it * This is not a fatal error */ if (ud_verify_tag(h, tag, id, fsds_loc, 1, 0) != 0) { continue; } switch (id) { case UD_FILE_SET_DESC : /* LINTED */ fsd = (struct file_set_desc *)taddr; if ((h->udfs.fsd_len == 0) || (SWAP_32(fsd->fsd_fs_no) > old_fsn)) { old_fsn = SWAP_32(fsd->fsd_fs_no); h->udfs.fsd_loc = fsds_loc; h->udfs.fsd_len = lb_roundup(512, h->udfs.lbsize); h->udfs.ricb_prn = SWAP_16(fsd->fsd_root_icb.lad_ext_prn); h->udfs.ricb_loc = SWAP_32(fsd->fsd_root_icb.lad_ext_loc); h->udfs.ricb_len = SWAP_32(fsd->fsd_root_icb.lad_ext_len); } if (SWAP_32(fsd->fsd_next.lad_ext_len) != 0) { fsd_prn = SWAP_16(fsd->fsd_next.lad_ext_prn); fsd_loc = SWAP_32(fsd->fsd_next.lad_ext_loc); fsd_len = SWAP_32(fsd->fsd_next.lad_ext_len); goto begin; } break; case UD_TERM_DESC : /* * Success fully completed */ goto end; default : /* * If you donot undetstand any tag just skip * it. This is not a fatal error */ break; } } end: free(addr); if (h->udfs.fsd_len == 0) { return (1); } return (0); } int32_t ud_get_num_blks(ud_handle_t h, uint32_t *blkno) { struct vtoc vtoc; struct dk_cinfo dki_info; int32_t error; /* * Get VTOC from driver */ if ((error = ioctl(h->fd, DKIOCGVTOC, (intptr_t)&vtoc)) != 0) { return (error); } /* * Verify if is proper */ if (vtoc.v_sanity != VTOC_SANE) { return (EINVAL); } /* * Get dk_cinfo from driver */ if ((error = ioctl(h->fd, DKIOCINFO, (intptr_t)&dki_info)) != 0) { return (error); } if (dki_info.dki_partition >= V_NUMPAR) { return (EINVAL); } /* * Return the size of the partition */ *blkno = vtoc.v_part[dki_info.dki_partition].p_size; return (0); } uint32_t ud_xlate_to_daddr(ud_handle_t h, uint16_t prn, uint32_t blkno) { int32_t i; struct ud_map *m; struct ud_part *p; if (prn < h->n_maps) { m = &h->maps[prn]; for (i = 0; i < h->n_parts; i++) { p = &h->part[i]; if (m->udm_pn == p->udp_number) { return (p->udp_start + blkno); } } } return (0); } /* ------ END Read and translate the on disk VDS to IN CORE format -------- */ int32_t ud_verify_tag(ud_handle_t h, struct tag *tag, uint16_t id, uint32_t blockno, int32_t do_crc, int32_t print_msg) { int32_t i; uint8_t *addr, cksum = 0; uint16_t crc; /* * Verify Tag Identifier */ if (tag->tag_id != SWAP_16(id)) { if (print_msg != 0) { (void) fprintf(stderr, gettext("tag does not verify tag %x req %x\n"), SWAP_16(tag->tag_id), id); } return (1); } /* * Verify Tag Descriptor Version */ if (SWAP_16(tag->tag_desc_ver) != h->udfs.ecma_version) { if (print_msg != 0) { (void) fprintf(stderr, gettext("tag version does not match with " "NSR descriptor version TAG %x NSR %x\n"), SWAP_16(tag->tag_desc_ver), h->udfs.ecma_version); } return (1); } /* * Caliculate Tag Checksum */ addr = (uint8_t *)tag; for (i = 0; i <= 15; i++) { if (i != 4) { cksum += addr[i]; } } /* * Verify Tag Checksum */ if (cksum != tag->tag_cksum) { if (print_msg != 0) { (void) fprintf(stderr, gettext("Checksum Does not Verify TAG" " %x CALC %x\n"), tag->tag_cksum, cksum); } return (1); } /* * Do we want to do crc */ if (do_crc) { if (tag->tag_crc_len) { /* * Caliculate CRC for the descriptor */ crc = ud_crc(addr + 0x10, SWAP_16(tag->tag_crc_len)); /* * Verify CRC */ if (crc != SWAP_16(tag->tag_crc)) { if (print_msg != 0) { (void) fprintf(stderr, gettext("CRC Does not verify" " TAG %x CALC %x %x\n"), SWAP_16(tag->tag_crc), crc, addr); } } } /* * Verify Tag Location */ if (SWAP_32(blockno) != tag->tag_loc) { if (print_msg != 0) { (void) fprintf(stderr, gettext("Tag Location Does not verify" " blockno %x tag_blockno %x\n"), blockno, SWAP_32(tag->tag_loc)); } } } return (0); } /* ARGSUSED1 */ void ud_make_tag(ud_handle_t h, struct tag *tag, uint16_t tag_id, uint32_t blkno, uint16_t crc_len) { int32_t i; uint16_t crc; uint8_t *addr, cksum = 0; tag->tag_id = SWAP_16(tag_id); tag->tag_desc_ver = SWAP_16(h->udfs.ecma_version); tag->tag_cksum = 0; tag->tag_res = 0; /* * Calicualte and assign CRC, CRC_LEN */ addr = (uint8_t *)tag; crc = ud_crc(addr + 0x10, crc_len); tag->tag_crc = SWAP_16(crc); tag->tag_crc_len = SWAP_16(crc_len); tag->tag_loc = SWAP_32(blkno); /* * Caliculate Checksum */ for (i = 0; i <= 15; i++) { cksum += addr[i]; } /* * Assign Checksum */ tag->tag_cksum = cksum; } /* **************** udf specific subroutines *********************** */ static uint16_t ud_crc_table[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; static uint16_t ud_crc(uint8_t *addr, int32_t len) { uint16_t crc = 0; while (len-- > 0) { crc = ud_crc_table[(crc >> 8 ^ *addr++) & 0xff] ^ (crc<<8); } return (crc); } #define MAXNAMLEN 0x200 #define POUND 0x0023 #define DOT 0x002E #define SLASH 0x002F #define UNDERBAR 0x005F static uint16_t htoc[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /* * unicode is the string of 16-bot characters * length is the number of 16-bit characters */ static int32_t UdfTxName(uint16_t *unicode, int32_t count) { int32_t i, j, k, lic, make_crc, dot_loc; uint16_t crc; if ((unicode[0] == DOT) && ((count == 1) || ((count == 2) && (unicode[1] == DOT)))) { crc = DOT; if (count == 2) { crc += DOT; } unicode[0] = UNDERBAR; unicode[1] = POUND; unicode[2] = htoc[(uint16_t)(crc & 0xf000) >> 12]; unicode[3] = htoc[(uint16_t)(crc & 0xf00) >> 8]; unicode[4] = htoc[(uint16_t)(crc & 0xf0) >> 4]; unicode[5] = htoc[crc & 0xf]; return (6); } crc = 0; j = make_crc = 0; lic = dot_loc = -1; for (i = 0; i < count; i++) { if (make_crc) { crc += unicode[i]; } if (unicode[i] == DOT) { dot_loc = j; } if ((unicode[i] == SLASH) || (unicode[i] == 0)) { if (make_crc == 0) { for (k = 0; k <= i; k++) { crc += unicode[k]; } make_crc = 1; } if (lic != (i - 1)) { unicode[j++] = UNDERBAR; } lic = i; } else { unicode[j++] = unicode[i]; } } if (make_crc) { if (dot_loc != -1) { if ((j + 5) > MAXNAMLEN) { if ((j - dot_loc + 5) > MAXNAMLEN) { j = MAXNAMLEN - 5 + dot_loc; for (k = MAXNAMLEN; j >= dot_loc; k --, j--) { unicode[k] = unicode[j]; } k = 0; } else { for (k = MAXNAMLEN; j >= dot_loc; k--, j--) { unicode[k] = unicode[j]; } k -= 4; } j = MAXNAMLEN; } else { for (k = j; k >= dot_loc; k--) { unicode[k + 5] = unicode[k]; } k = dot_loc; j += 5; } } else { if ((j + 5) > MAXNAMLEN) { j = MAXNAMLEN; k = MAXNAMLEN - 5; } else { k = j; j += 5; } } unicode[k++] = POUND; unicode[k++] = htoc[(uint16_t)(crc & 0xf000) >> 12]; unicode[k++] = htoc[(uint16_t)(crc & 0xf00) >> 8]; unicode[k++] = htoc[(uint16_t)(crc & 0xf0) >> 4]; unicode[k++] = htoc[crc & 0xf]; } return (j); } /* * Assumes the output buffer is large * enough to hold the uncompressed * code */ static int32_t UncompressUnicode( int32_t numberOfBytes, /* (Input) number of bytes read from media. */ uint8_t *UDFCompressed, /* (Input) bytes read from media. */ uint16_t *unicode) /* (Output) uncompressed unicode characters. */ { int32_t compID; int32_t returnValue, unicodeIndex, byteIndex; /* * Use UDFCompressed to store current byte being read. */ compID = UDFCompressed[0]; /* First check for valid compID. */ if (compID != 8 && compID != 16) { returnValue = -1; } else { unicodeIndex = 0; byteIndex = 1; /* Loop through all the bytes. */ while (byteIndex < numberOfBytes) { if (compID == 16) { /* * Move the first byte to the * high bits of the unicode char. */ unicode[unicodeIndex] = UDFCompressed[byteIndex++] << 8; } else { unicode[unicodeIndex] = 0; } if (byteIndex < numberOfBytes) { /* * Then the next byte to the low bits. */ unicode[unicodeIndex] |= UDFCompressed[byteIndex++]; } unicodeIndex++; } returnValue = unicodeIndex; } return (returnValue); } static int32_t ud_compressunicode( int32_t numberOfChars, /* (Input) number of unicode characters. */ int32_t compID, /* (Input) compression ID to be used. */ uint16_t *unicode, /* (Input) unicode characters to compress. */ uint8_t *UDFCompressed) /* (Output) compressed string, as bytes. */ { int32_t byteIndex; if (compID != 8 && compID != 16) { /* * Unsupported compression ID ! */ byteIndex = -1; } else { /* * Place compression code in first byte. */ UDFCompressed[0] = (uint8_t)compID; (void) strncpy((caddr_t)&UDFCompressed[1], (caddr_t)unicode, numberOfChars); byteIndex = numberOfChars + 1; } return (byteIndex); } static int32_t ud_convert2utf8(uint8_t *ibuf, uint8_t *obuf, int32_t length) { int i, size; uint16_t *buf; /* LINTED */ buf = (uint16_t *)obuf; size = UncompressUnicode(length, ibuf, buf); size = UdfTxName(buf, size); for (i = 0; i < size; i++) { obuf[i] = (uint8_t)buf[i]; } obuf[i] = '\0'; return (size); } static int32_t ud_convert2utf16(uint8_t *ibuf, uint8_t *obuf, int32_t length) { int32_t comp_len; uint16_t *ptr; /* LINTED */ ptr = (uint16_t *)ibuf; comp_len = ud_compressunicode(length, 8, ptr, obuf); return (comp_len); } /* * Assumption code set is zero in udfs */ void ud_convert2local(int8_t *ibuf, int8_t *obuf, int32_t length) { wchar_t buf4c[128]; int32_t i, comp, index; /* * Special uncompress code * written to accomodate solaris wchar_t */ comp = ibuf[0]; for (i = 0, index = 1; i < length; i++) { if (comp == 16) { buf4c[i] = ibuf[index++] << 8; } else { buf4c[i] = 0; } if (index < length) { buf4c[i] |= ibuf[index++]; } } (void) wcstombs((char *)obuf, buf4c, 128); } /* ------------ Routines to print basic structures Part 1 ---------------- */ void print_charspec(FILE *fout, char *name, struct charspec *cspec) { int i = 0; (void) fprintf(fout, "%s : %x - \"", name, cspec->cs_type); for (i = 0; i < 63; i++) { (void) fprintf(fout, "%c", cspec->cs_info[i]); } (void) fprintf(fout, "\n"); } /* ARGSUSED */ void print_dstring(FILE *fout, char *name, uint16_t cset, char *bufc, uint8_t length) { int8_t bufmb[1024]; ud_convert2local(bufc, bufmb, length); (void) fprintf(fout, "%s %s\n", name, bufmb); } void set_dstring(dstring_t *dp, char *cp, int32_t len) { int32_t length; bzero(dp, len); length = strlen(cp); if (length > len - 1) { length = len - 1; } (void) strncpy(dp, cp, length); dp[len - 1] = length; } void print_tstamp(FILE *fout, char *name, tstamp_t *ts) { (void) fprintf(fout, "%s tz : %d yr : %d mo : %d da : %d " "Time : %d : %d : %d : %d : %d : %d\n", name, SWAP_16(ts->ts_tzone), SWAP_16(ts->ts_year), ts->ts_month, ts->ts_day, ts->ts_hour, ts->ts_min, ts->ts_sec, ts->ts_csec, ts->ts_husec, ts->ts_usec); } void make_regid(ud_handle_t h, struct regid *reg, char *id, int32_t type) { reg->reg_flags = 0; (void) strncpy(reg->reg_id, id, 23); if (type == REG_DOM_ID) { struct dom_id_suffix *dis; /* LINTED */ dis = (struct dom_id_suffix *)reg->reg_ids; dis->dis_udf_revison = SWAP_16(h->udfs.ma_write); dis->dis_domain_flags = 0; } else if (type == REG_UDF_ID) { struct udf_id_suffix *uis; /* LINTED */ uis = (struct udf_id_suffix *)reg->reg_ids; uis->uis_udf_revision = SWAP_16(h->udfs.ma_write); uis->uis_os_class = OS_CLASS_UNIX; uis->uis_os_identifier = OS_IDENTIFIER_SOLARIS; } else if (type == REG_UDF_II) { struct impl_id_suffix *iis; iis = (struct impl_id_suffix *)reg->reg_ids; iis->iis_os_class = OS_CLASS_UNIX; iis->iis_os_identifier = OS_IDENTIFIER_SOLARIS; } } void print_regid(FILE *fout, char *name, struct regid *reg, int32_t type) { (void) fprintf(fout, "%s : 0x%x : \"%s\" :", name, reg->reg_flags, reg->reg_id); if (type == REG_DOM_ID) { struct dom_id_suffix *dis; /* LINTED */ dis = (struct dom_id_suffix *)reg->reg_ids; (void) fprintf(fout, " 0x%x : %s : %s\n", SWAP_16(dis->dis_udf_revison), (dis->dis_domain_flags & PROTECT_SOFT_WRITE) ? "HW Protect" : "No HW Write Protect", (dis->dis_domain_flags & PROTECT_HARD_WRITE) ? "SW Protect" : "No SW Protect"); } else if (type == REG_UDF_ID) { struct udf_id_suffix *uis; /* LINTED */ uis = (struct udf_id_suffix *)reg->reg_ids; (void) fprintf(fout, " 0x%x : OS Class 0x%x : OS Identifier 0x%x\n", SWAP_16(uis->uis_udf_revision), uis->uis_os_class, uis->uis_os_identifier); } else { struct impl_id_suffix *iis; iis = (struct impl_id_suffix *)reg->reg_ids; (void) fprintf(fout, " OS Class 0x%x : OS Identifier 0x%x\n", iis->iis_os_class, iis->iis_os_identifier); } } #ifdef OLD void print_regid(FILE *fout, char *name, struct regid *reg) { (void) fprintf(fout, "%s : 0x%x : \"%s\" :", name, reg->reg_flags, reg->reg_id); if (strncmp(reg->reg_id, "*OSTA UDF Compliant", 19) == 0) { (void) fprintf(fout, " 0x%x : %s : %s\n", reg->reg_ids[0] | (reg->reg_ids[1] << 8), (reg->reg_ids[2] & 1) ? "HW Protect" : "No HW Write Protect", (reg->reg_ids[2] & 2) ? "SW Protect" : "No SW Protect"); } else if ((strncmp(reg->reg_id, "*UDF Virtual Partition", 22) == 0) || (strncmp(reg->reg_id, "*UDF Sparable Partition", 23) == 0) || (strncmp(reg->reg_id, "*UDF Virtual Alloc Tbl", 22) == 0) || (strncmp(reg->reg_id, "*UDF Sparing Table", 18) == 0)) { (void) fprintf(fout, " 0x%x : OS Class 0x%x : OS Identifier 0x%x\n", reg->reg_ids[0] | (reg->reg_ids[1] << 8), reg->reg_ids[2], reg->reg_ids[3]); } else { (void) fprintf(fout, " OS Class 0x%x : OS Identifier 0x%x\n", reg->reg_ids[0], reg->reg_ids[1]); } } #endif /* ------------ Routines to print basic structures Part 2 ---------------- */ /* * Part 2 * This part is OS specific and is currently * not supported */ /* ------------ Routines to print basic structures Part 3 ---------------- */ void print_ext_ad(FILE *fout, char *name, struct extent_ad *ead) { (void) fprintf(fout, "%s EAD Len %x Loc %x\n", name, SWAP_32(ead->ext_len), SWAP_32(ead->ext_loc)); } void print_tag(FILE *fout, struct tag *tag) { (void) fprintf(fout, "tag_id : %x ver : %x cksum : %x " "sno : %x crc : %x crc_len : %x loc : %x\n", SWAP_16(tag->tag_id), SWAP_16(tag->tag_desc_ver), tag->tag_cksum, SWAP_16(tag->tag_sno), SWAP_16(tag->tag_crc), SWAP_16(tag->tag_crc_len), SWAP_32(tag->tag_loc)); } void print_pvd(FILE *fout, struct pri_vol_desc *pvd) { (void) fprintf(fout, "\n\t\t\tPrimary Volume Descriptor\n"); print_tag(fout, &pvd->pvd_tag); (void) fprintf(fout, "vdsn : %x vdn : %x\n", SWAP_32(pvd->pvd_vdsn), SWAP_32(pvd->pvd_pvdn)); print_dstring(fout, "volid : ", pvd->pvd_desc_cs.cs_type, pvd->pvd_vol_id, 32); (void) fprintf(fout, "vsn : %x mvsn : %x il : %x mil :" " %x csl : %x mcsl %x\n", SWAP_16(pvd->pvd_vsn), SWAP_16(pvd->pvd_mvsn), SWAP_16(pvd->pvd_il), SWAP_16(pvd->pvd_mil), SWAP_32(pvd->pvd_csl), SWAP_32(pvd->pvd_mcsl)); print_dstring(fout, "vsid :", pvd->pvd_desc_cs.cs_type, pvd->pvd_vsi, 128); print_charspec(fout, "desc_cs", &pvd->pvd_desc_cs); print_charspec(fout, "exp_cs", &pvd->pvd_exp_cs); print_ext_ad(fout, "val ", &pvd->pvd_vol_abs); print_ext_ad(fout, "vcnl ", &pvd->pvd_vcn); print_regid(fout, "ai", &pvd->pvd_appl_id, REG_UDF_II); print_regid(fout, "ii", &pvd->pvd_ii, REG_UDF_II); (void) fprintf(fout, "pvdsl : %x flags : %x\n", SWAP_32(pvd->pvd_pvdsl), SWAP_16(pvd->pvd_flags)); } void print_avd(FILE *fout, struct anch_vol_desc_ptr *avdp) { (void) fprintf(fout, "\n\t\t\tAnchor Volume Descriptor\n"); print_tag(fout, &avdp->avd_tag); print_ext_ad(fout, "Main Volume Descriptor Sequence : ", &avdp->avd_main_vdse); print_ext_ad(fout, "Reserve Volume Descriptor Sequence : ", &avdp->avd_res_vdse); } void print_vdp(FILE *fout, struct vol_desc_ptr *vdp) { (void) fprintf(fout, "\n\t\t\tVolume Descriptor Pointer\n"); print_tag(fout, &vdp->vdp_tag); (void) fprintf(fout, "vdsn : %x ", SWAP_32(vdp->vdp_vdsn)); print_ext_ad(fout, "vdse ", &vdp->vdp_nvdse); } void print_iuvd(FILE *fout, struct iuvd_desc *iuvd) { (void) fprintf(fout, "\n\t\t\tImplementation Use Volume Descriptor\n"); print_tag(fout, &iuvd->iuvd_tag); (void) fprintf(fout, "vdsn : %x ", SWAP_32(iuvd->iuvd_vdsn)); print_regid(fout, "Impl Id : ", &iuvd->iuvd_ii, REG_UDF_ID); print_charspec(fout, "cset ", &iuvd->iuvd_cset); print_dstring(fout, "lvi : ", iuvd->iuvd_cset.cs_type, iuvd->iuvd_lvi, 128); print_dstring(fout, "ifo1 : ", iuvd->iuvd_cset.cs_type, iuvd->iuvd_ifo1, 36); print_dstring(fout, "ifo2 : ", iuvd->iuvd_cset.cs_type, iuvd->iuvd_ifo2, 36); print_dstring(fout, "ifo3 : ", iuvd->iuvd_cset.cs_type, iuvd->iuvd_ifo3, 36); print_regid(fout, "iid ", &iuvd->iuvd_iid, REG_UDF_II); } void print_part(FILE *fout, struct part_desc *pd) { (void) fprintf(fout, "\n\t\t\tPartition Descriptor\n"); print_tag(fout, &pd->pd_tag); (void) fprintf(fout, "vdsn : %x flags : %x num : %x ", SWAP_32(pd->pd_vdsn), SWAP_16(pd->pd_pflags), SWAP_16(pd->pd_pnum)); print_regid(fout, "contents ", &pd->pd_pcontents, REG_UDF_II); /* LINTED */ print_phdr(fout, (struct phdr_desc *)(&pd->pd_pc_use)); (void) fprintf(fout, "acc : %x start : %x length : %x ", SWAP_32(pd->pd_acc_type), SWAP_32(pd->pd_part_start), SWAP_32(pd->pd_part_length)); print_regid(fout, "Impl Id : ", &pd->pd_ii, REG_UDF_II); } void print_lvd(FILE *fout, struct log_vol_desc *lvd) { (void) fprintf(fout, "\n\t\t\tLogical Volume Descriptor\n"); print_tag(fout, &lvd->lvd_tag); (void) fprintf(fout, "vdsn : %x ", SWAP_32(lvd->lvd_vdsn)); print_charspec(fout, "Desc Char Set ", &lvd->lvd_desc_cs); print_dstring(fout, "lvid : ", lvd->lvd_desc_cs.cs_type, lvd->lvd_lvid, 28); (void) fprintf(fout, "lbsize : %x ", SWAP_32(lvd->lvd_log_bsize)); print_regid(fout, "Dom Id", &lvd->lvd_dom_id, REG_DOM_ID); print_long_ad(fout, "lvcu", &lvd->lvd_lvcu); (void) fprintf(fout, "mtlen : %x nmaps : %x ", SWAP_32(lvd->lvd_mtbl_len), SWAP_32(lvd->lvd_num_pmaps)); print_regid(fout, "Impl Id : ", &lvd->lvd_ii, REG_UDF_II); print_ext_ad(fout, "Int Seq", &lvd->lvd_int_seq_ext); print_pmaps(fout, lvd->lvd_pmaps, SWAP_32(lvd->lvd_num_pmaps)); } void print_usd(FILE *fout, struct unall_spc_desc *ua) { int32_t i, count; (void) fprintf(fout, "\n\t\t\tUnallocated Space Descriptor\n"); print_tag(fout, &ua->ua_tag); count = SWAP_32(ua->ua_nad); (void) fprintf(fout, "vdsn : %x nad : %x\n", SWAP_32(ua->ua_vdsn), count); for (i = 0; i < count; i++) { (void) fprintf(fout, "loc : %x len : %x\n", SWAP_32(ua->ua_al_dsc[i * 2]), SWAP_32(ua->ua_al_dsc[i * 2 + 1])); } } void print_lvid(FILE *fout, struct log_vol_int_desc *lvid) { int32_t i, count; caddr_t addr; struct lvid_iu *liu; (void) fprintf(fout, "\n\t\t\tLogical Volume Integrity Descriptor\n"); print_tag(fout, &lvid->lvid_tag); print_tstamp(fout, "Rec TM ", &lvid->lvid_tstamp); if (SWAP_32(lvid->lvid_int_type) == 0) { (void) fprintf(fout, "int_typ : Open\n"); } else if (SWAP_32(lvid->lvid_int_type) == 1) { (void) fprintf(fout, "int_typ : Closed\n"); } else { (void) fprintf(fout, "int_typ : Unknown\n"); } print_ext_ad(fout, "Nie ", &lvid->lvid_nie); count = SWAP_32(lvid->lvid_npart); (void) fprintf(fout, "Uniq : %llx npart : %x liu : %x\n", SWAP_64(lvid->lvid_lvcu.lvhd_uniqid), count, SWAP_32(lvid->lvid_liu)); for (i = 0; i < count; i++) { (void) fprintf(fout, "Part : %x Free : %x Size : %x\n", i, SWAP_32(lvid->lvid_fst[i]), SWAP_32(lvid->lvid_fst[count + i])); } addr = (caddr_t)lvid->lvid_fst; /* LINTED */ liu = (struct lvid_iu *)(addr + 2 * count * 4); print_regid(fout, "Impl Id :", &liu->lvidiu_regid, REG_UDF_II); (void) fprintf(fout, "nfiles : %x ndirs : %x miread : %x" " miwrite : %x mawrite : %x\n", SWAP_32(liu->lvidiu_nfiles), SWAP_32(liu->lvidiu_ndirs), SWAP_16(liu->lvidiu_mread), SWAP_16(liu->lvidiu_mwrite), SWAP_16(liu->lvidiu_maxwr)); } /* ------------ Routines to print basic structures Part 4 ---------------- */ void print_fsd(FILE *fout, ud_handle_t h, struct file_set_desc *fsd) { (void) fprintf(fout, "\n\t\t\tFile Set Descriptor\n"); print_tag(fout, &fsd->fsd_tag); print_tstamp(fout, "Rec TM ", &fsd->fsd_time); (void) fprintf(fout, "ilvl : %x milvl : %x csl : %x" " mcsl : %x fsn : %x fsdn : %x\n", SWAP_16(fsd->fsd_ilevel), SWAP_16(fsd->fsd_mi_level), SWAP_32(fsd->fsd_cs_list), SWAP_32(fsd->fsd_mcs_list), SWAP_32(fsd->fsd_fs_no), SWAP_32(fsd->fsd_fsd_no)); print_charspec(fout, "ID CS ", &fsd->fsd_lvidcs); print_dstring(fout, "lvi : ", fsd->fsd_lvidcs.cs_type, fsd->fsd_lvid, 128); print_charspec(fout, "ID CS ", &fsd->fsd_fscs); print_dstring(fout, "fsi : ", fsd->fsd_lvidcs.cs_type, fsd->fsd_fsi, 32); print_dstring(fout, "cfi : ", fsd->fsd_lvidcs.cs_type, fsd->fsd_cfi, 32); print_dstring(fout, "afi : ", fsd->fsd_lvidcs.cs_type, fsd->fsd_afi, 32); print_long_ad(fout, "Ricb ", &fsd->fsd_root_icb); print_regid(fout, "DI ", &fsd->fsd_did, REG_DOM_ID); print_long_ad(fout, "Next Fsd ", &fsd->fsd_next); if (h->udfs.ecma_version == UD_ECMA_VER3) { print_long_ad(fout, "System Stream Directory ICB ", &fsd->fsd_next); } } void print_phdr(FILE *fout, struct phdr_desc *ph) { print_short_ad(fout, "ust ", &ph->phdr_ust); print_short_ad(fout, "usb ", &ph->phdr_usb); print_short_ad(fout, "int ", &ph->phdr_it); print_short_ad(fout, "fst ", &ph->phdr_fst); print_short_ad(fout, "fsh ", &ph->phdr_fsb); } void print_fid(FILE *fout, struct file_id *fid) { int32_t i; uint8_t *addr; (void) fprintf(fout, "File Identifier Descriptor\n"); print_tag(fout, &fid->fid_tag); (void) fprintf(fout, "fvn : %x fc : %x length : %x ", fid->fid_ver, fid->fid_flags, fid->fid_idlen); print_long_ad(fout, "ICB", &fid->fid_icb); addr = &fid->fid_spec[SWAP_16(fid->fid_iulen)]; (void) fprintf(fout, "iulen : %x comp : %x name : ", SWAP_16(fid->fid_iulen), *addr); addr++; for (i = 0; i < fid->fid_idlen; i++) { (void) fprintf(fout, "%c", *addr++); } (void) fprintf(fout, "\n"); } void print_aed(FILE *fout, struct alloc_ext_desc *aed) { (void) fprintf(fout, "Allocation Extent Descriptor\n"); print_tag(fout, &aed->aed_tag); (void) fprintf(fout, "prev ael loc : %x laed : %x\n", SWAP_32(aed->aed_rev_ael), SWAP_32(aed->aed_len_aed)); } static char *ftype[] = { "NON", "USE", "PIE", "IE", "DIR", "REG", "BDEV", "CDEV", "EATT", "FIFO", "SOCK", "TERM", "SYML", "SDIR" }; void print_icb_tag(FILE *fout, struct icb_tag *itag) { (void) fprintf(fout, "prnde : %x strat : %x param : %x max_ent %x\n", SWAP_32(itag->itag_prnde), SWAP_16(itag->itag_strategy), SWAP_16(itag->itag_param), SWAP_16(itag->itag_max_ent)); (void) fprintf(fout, "ftype : %s prn : %x loc : %x flags : %x\n", (itag->itag_ftype >= 14) ? ftype[0] : ftype[itag->itag_ftype], SWAP_16(itag->itag_lb_prn), SWAP_32(itag->itag_lb_loc), SWAP_16(itag->itag_flags)); } void print_ie(FILE *fout, struct indirect_entry *ie) { (void) fprintf(fout, "Indirect Entry\n"); print_tag(fout, &ie->ie_tag); print_icb_tag(fout, &ie->ie_icb_tag); print_long_ad(fout, "ICB", &ie->ie_indirecticb); } void print_td(FILE *fout, struct term_desc *td) { (void) fprintf(fout, "Terminating Descriptor\n"); print_tag(fout, &td->td_tag); } void print_fe(FILE *fout, struct file_entry *fe) { (void) fprintf(fout, "File Entry\n"); print_tag(fout, &fe->fe_tag); print_icb_tag(fout, &fe->fe_icb_tag); (void) fprintf(fout, "uid : %x gid : %x perms : %x nlnk : %x\n", SWAP_32(fe->fe_uid), SWAP_32(fe->fe_gid), SWAP_32(fe->fe_perms), SWAP_16(fe->fe_lcount)); (void) fprintf(fout, "rec_for : %x rec_dis : %x rec_len : %x " "sz : %llx blks : %llx\n", fe->fe_rec_for, fe->fe_rec_dis, SWAP_32(fe->fe_rec_len), SWAP_64(fe->fe_info_len), SWAP_64(fe->fe_lbr)); print_tstamp(fout, "ctime ", &fe->fe_acc_time); print_tstamp(fout, "mtime ", &fe->fe_mod_time); print_tstamp(fout, "atime ", &fe->fe_attr_time); (void) fprintf(fout, "ckpoint : %x ", SWAP_32(fe->fe_ckpoint)); print_long_ad(fout, "ICB", &fe->fe_ea_icb); print_regid(fout, "impl", &fe->fe_impl_id, REG_UDF_II); (void) fprintf(fout, "uniq_id : %llx len_ear : %x len_adesc %x\n", SWAP_64(fe->fe_uniq_id), SWAP_32(fe->fe_len_ear), SWAP_32(fe->fe_len_adesc)); } void print_pmaps(FILE *fout, uint8_t *addr, int32_t count) { struct pmap_hdr *hdr; struct pmap_typ1 *map1; struct pmap_typ2 *map2; while (count--) { hdr = (struct pmap_hdr *)addr; switch (hdr->maph_type) { case 1 : /* LINTED */ map1 = (struct pmap_typ1 *)hdr; (void) fprintf(fout, "Map type 1 "); (void) fprintf(fout, "VSN %x prn %x\n", SWAP_16(map1->map1_vsn), SWAP_16(map1->map1_pn)); break; case 2 : /* LINTED */ map2 = (struct pmap_typ2 *)hdr; (void) fprintf(fout, "Map type 2 "); (void) fprintf(fout, "VSN %x prn %x\n", SWAP_16(map2->map2_vsn), SWAP_16(map2->map2_pn)); print_regid(fout, "Partition Type Identifier", &map2->map2_pti, REG_UDF_ID); break; default : (void) fprintf(fout, "unknown map type\n"); } addr += hdr->maph_length; } } void print_short_ad(FILE *fout, char *name, struct short_ad *sad) { (void) fprintf(fout, "%s loc : %x len : %x\n", name, SWAP_32(sad->sad_ext_loc), SWAP_32(sad->sad_ext_len)); } void print_long_ad(FILE *fout, char *name, struct long_ad *lad) { (void) fprintf(fout, "%s prn : %x loc : %x len : %x\n", name, SWAP_16(lad->lad_ext_prn), SWAP_32(lad->lad_ext_loc), SWAP_32(lad->lad_ext_len)); } /* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _UD_LIB_H #define _UD_LIB_H #ifdef __cplusplus extern "C" { #endif #define UD_VOL_REC_START (32 * 1024) #define UD_VOL_REC_BSZ 2048 #define UD_VOL_REC_END (256 * UD_VOL_REC_BSZ) #define UD_ECMA_VER2 0x00000002 #define UD_ECMA_VER3 0x00000003 #define UD_ECMA_UNKN 0xFFFFFFFF #define MAX_PARTS 10 #define MAX_MAPS 10 #define MAX_SPM 4 #define lb_roundup(sz, lbsz) \ (((sz) + (lbsz - 1)) & (~(lbsz - 1))) struct vds { uint32_t pvd_loc; uint32_t pvd_len; uint32_t pvd_vdsn; uint32_t iud_loc; uint32_t iud_len; uint32_t part_loc[MAX_PARTS]; uint32_t part_len[MAX_PARTS]; uint32_t lvd_loc; uint32_t lvd_len; uint32_t lvd_vdsn; uint32_t usd_loc; uint32_t usd_len; }; /* * All addresses are the lbsize block numbers * offseted into the partition */ struct udf { uint32_t flags; #define INVALID_UDFS 0x0000 #define VALID_UDFS 0x0001 #define VALID_MVDS 0x0002 #define VALID_RVDS 0x0004 uint32_t ecma_version; uint8_t ecma_id[5]; uint16_t mi_read; uint16_t ma_read; uint16_t ma_write; uint32_t lbsize; uint32_t avdp_loc; /* First Readable avdp */ uint32_t avdp_len; uint32_t mvds_loc; uint32_t mvds_len; uint32_t rvds_len; uint32_t rvds_loc; struct vds mvds; struct vds rvds; /* * location of the latest lvid */ uint32_t lvid_loc; uint32_t lvid_len; uint16_t fsds_prn; uint32_t fsds_loc; uint32_t fsds_len; /* * Location of the most usable fsd * on WORM we have to follow till the * end of the chain * FSD location is absolute disk location * after translating using maps and partitions */ uint32_t fsd_loc; uint32_t fsd_len; uint16_t ricb_prn; uint32_t ricb_loc; uint32_t ricb_len; uint32_t vat_icb_loc; uint32_t vat_icb_len; }; struct ud_part { uint16_t udp_flags; /* See below */ #define UDP_BITMAPS 0x00 #define UDP_SPACETBLS 0x01 uint16_t udp_number; /* partition Number */ uint32_t udp_seqno; /* to find the prevailaing desc */ uint32_t udp_access; /* access type */ uint32_t udp_start; /* Starting block no of partition */ uint32_t udp_length; /* Lenght of the partition */ uint32_t udp_unall_loc; /* unall space tbl or bitmap loc */ uint32_t udp_unall_len; /* unall space tbl or bitmap length */ uint32_t udp_freed_loc; /* freed space tbl or bitmap loc */ uint32_t udp_freed_len; /* freed space tbl or bitmap length */ /* From part desc */ uint32_t udp_nfree; /* No of free blocks in the partition */ uint32_t udp_nblocks; /* Total no of blks in the partition */ /* From lvid */ }; struct ud_map { uint16_t udm_flags; #define UDM_MAP_NORM 0x00 #define UDM_MAP_VPM 0x01 #define UDM_MAP_SPM 0x02 uint16_t udm_vsn; uint16_t udm_pn; uint32_t udm_vat_icb_loc; uint32_t udm_nent; uint32_t *udm_count; struct buf **udm_bp; uint32_t **udm_addr; int32_t udm_plen; int32_t udm_nspm; uint32_t udm_spsz; uint32_t udm_loc[MAX_SPM]; struct buf *udm_sbp[MAX_SPM]; caddr_t udm_spaddr[MAX_SPM]; }; #define REG_DOM_ID 0x1 #define REG_UDF_ID 0x2 #define REG_UDF_II 0x4 #define EI_FLG_DIRTY 0x01 #define EI_FLG_PROT 0x02 struct dom_id_suffix { uint16_t dis_udf_revison; uint8_t dis_domain_flags; uint8_t dis_pad[5]; }; #define PROTECT_SOFT_WRITE 0x01 #define PROTECT_HARD_WRITE 0x02 struct udf_id_suffix { uint16_t uis_udf_revision; uint8_t uis_os_class; uint8_t uis_os_identifier; uint8_t uis_pad[4]; }; struct impl_id_suffix { uint8_t iis_os_class; uint8_t iis_os_identifier; uint8_t iis_pad[6]; }; #define OS_CLASS_UNDEFINED 0x00 #define OS_CLASS_DOS_WIN3x 0x01 #define OS_CLASS_OS_2 0x02 #define OS_CLASS_MAC_OS_7 0x02 #define OS_CLASS_UNIX 0x04 #define OS_CLASS_WIN_95 0x05 #define OS_CLASS_WIN_NT 0x06 #define OS_IDENTIFIER_GENERIC 0x00 #define OS_IDENTIFIER_IBM_AIX 0x01 #define OS_IDENTIFIER_SOLARIS 0x02 #define OS_IDENTIFIER_HP_UX 0x03 #define OS_IDENTIFIER_SG_IRIX 0x04 #define OS_IDENTIFIER_LINUX 0x05 #define OS_IDENTIFIER_MK_LINUX 0x06 #define OS_IDENTIFIER_FREE_BSD 0x07 struct ud_handle { int fd; struct udf udfs; struct ud_part part[MAX_PARTS]; int32_t n_parts; struct ud_map maps[MAX_MAPS]; int32_t n_maps; }; typedef struct ud_handle *ud_handle_t; int ud_init(int, ud_handle_t *); void ud_fini(ud_handle_t); int32_t ud_open_dev(ud_handle_t, char *, uint32_t); void ud_close_dev(ud_handle_t); int32_t ud_read_dev(ud_handle_t, uint64_t, uint8_t *, uint32_t); int32_t ud_write_dev(ud_handle_t, uint64_t, uint8_t *, uint32_t); int32_t ud_fill_udfs_info(ud_handle_t); int32_t ud_get_num_blks(ud_handle_t, uint32_t *); int32_t ud_verify_tag(ud_handle_t, struct tag *, uint16_t, uint32_t, int32_t, int32_t); void ud_make_tag(ud_handle_t, struct tag *, uint16_t, uint32_t, uint16_t); uint32_t ud_xlate_to_daddr(ud_handle_t, uint16_t, uint32_t); void ud_convert2local(int8_t *, int8_t *, int32_t); void print_charspec(FILE *, char *, struct charspec *); void print_dstring(FILE *, char *, uint16_t, char *, uint8_t); void set_dstring(dstring_t *, char *, int32_t); void print_tstamp(FILE *, char *, tstamp_t *); void print_regid(FILE *, char *, struct regid *, int32_t); void print_ext_ad(FILE *, char *, struct extent_ad *); void print_tag(FILE *, struct tag *); void print_pvd(FILE *, struct pri_vol_desc *); void print_avd(FILE *, struct anch_vol_desc_ptr *); void print_vdp(FILE *, struct vol_desc_ptr *); void print_iuvd(FILE *, struct iuvd_desc *); void print_part(FILE *, struct part_desc *); void print_lvd(FILE *, struct log_vol_desc *); void print_usd(FILE *, struct unall_spc_desc *); void print_lvid(FILE *, struct log_vol_int_desc *); void print_part(FILE *, struct part_desc *); void print_fsd(FILE *, ud_handle_t h, struct file_set_desc *); void print_phdr(FILE *, struct phdr_desc *); void print_fid(FILE *, struct file_id *); void print_aed(FILE *, struct alloc_ext_desc *); void print_icb_tag(FILE *, struct icb_tag *); void print_ie(FILE *, struct indirect_entry *); void print_td(FILE *, struct term_desc *); void print_fe(FILE *, struct file_entry *); void print_pmaps(FILE *, uint8_t *, int32_t); void print_short_ad(FILE *, char *, struct short_ad *); void print_long_ad(FILE *, char *, struct long_ad *); #ifdef __cplusplus } #endif #endif /* _UD_LIB_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 (c) 1999 by Sun Microsystems, Inc. # All rights reserved. # # Copyright (c) 2018, Joyent, Inc. FSTYPE= udfs LIBPROG= fsck ATTMK= $(LIBPROG) include ../../Makefile.fstype FSCKOBJS= main.o setup.o utilities.o pass1.o inode.o FSCKSRCS= $(FSCKOBJS:%.o=%.c) UDFSDIR= ../mkfs UDFSOBJS= udfslib.o #UDFSSRCS= $(UDFSOBJS:%.o=%.c) CERRWARN += -Wno-parentheses # not linted SMATCH=off OBJS= $(FSCKOBJS) $(UDFSOBJS) SRCS= $(FSCKSRCS) $(UDFSSRCS) ../mkfs/udfslib.c #CPPFLAGS += -D_LARGEFILE64_SOURCE CPPFLAGS += -I../mkfs LDLIBS += -ladm $(LIBPROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) %.o: $(UDFSDIR)/%.c $(COMPILE.c) $< # for messaging catalog # POFILE= fsck.po # for messaging catalog # catalog: $(POFILE) $(POFILE): $(SRCS) $(RM) $@ $(COMPILE.cpp) $(SRCS) > $(POFILE).i $(XGETTEXT) $(XGETFLAGS) $(POFILE).i sed "/^domain/d" messages.po > $@ $(RM) $(POFILE).i messages.po clean: $(RM) $(FSCKOBJS) $(UDFSOBJS) * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. PORTIONS OF UDFS FUNCTIONALITY /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Copyright (c) 1996, 1998-1999 by Sun Microsystems, Inc. * All rights reserved. */ #ifndef _FSCK_H #define _FSCK_H #ifdef __cplusplus extern "C" { #endif #define MAXDUP 10 /* limit on dup blks (per inode) */ #define MAXBAD 10 /* limit on bad blks (per inode) */ #define MAXBUFSPACE 256*1024 /* maximum space to allocate */ /* to buffers */ #define INOBUFSIZE 256*1024 /* size of buffer to read */ /* inodes in pass1 */ #define MAXBSIZE 8192 /* maximum allowed block size */ #define FIRSTAVDP 256 #ifndef BUFSIZ #define BUFSIZ 1024 #endif #ifdef sparc #define SWAP16(x) (((x) & 0xff) << 8 | ((x) >> 8) & 0xff) #define SWAP32(x) (((x) & 0xff) << 24 | ((x) & 0xff00) << 8 | \ ((x) & 0xff0000) >> 8 | ((x) >> 24) & 0xff) #define SWAP64(x) (SWAP32((x) >> 32) & 0xffffffff | SWAP32(x) << 32) #else #define SWAP16(x) (x) #define SWAP32(x) (x) #define SWAP64(x) (x) #endif #define NOTBUSY 00 /* Not busy when busymarked is set */ #define USTATE 01 /* inode not allocated */ #define FSTATE 02 /* inode is file */ #define DSTATE 03 /* inode is directory */ #define DFOUND 04 /* directory found during descent */ #define DCLEAR 05 /* directory is to be cleared */ #define FCLEAR 06 /* file is to be cleared */ #define SSTATE 07 /* inode is a shadow */ #define SCLEAR 010 /* shadow is to be cleared */ #define ESTATE 011 /* Inode extension */ #define ECLEAR 012 /* inode extension is to be cleared */ #define IBUSY 013 /* inode is marked busy by first pass */ #define LSTATE 014 /* Link tags */ struct dinode { int dummy; }; /* * buffer cache structure. */ struct bufarea { struct bufarea *b_next; /* free list queue */ struct bufarea *b_prev; /* free list queue */ daddr_t b_bno; int b_size; int b_errs; int b_flags; union { char *b_buf; /* buffer space */ daddr_t *b_indir; /* indirect block */ struct fs *b_fs; /* super block */ struct cg *b_cg; /* cylinder group */ struct dinode *b_dinode; /* inode block */ } b_un; char b_dirty; }; #define B_INUSE 1 #define MINBUFS 5 /* minimum number of buffers required */ extern struct log_vol_int_desc *lvintp; extern struct lvid_iu *lviup; extern struct space_bmap_desc *spacep; #define dirty(bp) (bp)->b_dirty = isdirty = 1 #define initbarea(bp) \ (bp)->b_dirty = 0; \ (bp)->b_bno = (daddr_t)-1; \ (bp)->b_flags = 0; enum fixstate {DONTKNOW, NOFIX, FIX}; struct inodesc { enum fixstate id_fix; /* policy on fixing errors */ int (*id_func)(); /* function to be applied to blocks of inode */ ino_t id_number; /* inode number described */ ino_t id_parent; /* for DATA nodes, their parent */ daddr_t id_blkno; /* current block number being examined */ int id_numfrags; /* number of frags contained in block */ offset_t id_filesize; /* for DATA nodes, the size of the directory */ int id_loc; /* for DATA nodes, current location in dir */ int id_entryno; /* for DATA nodes, current entry number */ struct direct *id_dirp; /* for DATA nodes, ptr to current entry */ char *id_name; /* for DATA nodes, name to find or enter */ char id_type; /* type of descriptor, DATA or ADDR */ }; /* file types */ #define DATA 1 #define ADDR 2 /* * File entry cache structures. */ typedef struct fileinfo { struct fileinfo *fe_nexthash; /* next entry in hash chain */ uint32_t fe_block; /* location of this file entry */ uint16_t fe_len; /* size of file entry */ uint16_t fe_lseen; /* number of links seen */ uint16_t fe_lcount; /* count from the file entry */ uint8_t fe_type; /* type of file entry */ uint8_t fe_state; /* flag bits */ } fileinfo_t; extern fileinfo_t *inphead, **inphash, *inpnext, *inplast; extern long listmax; #define FEGROW 512 extern char *devname; /* name of device being checked */ extern long secsize; /* actual disk sector size */ extern long fsbsize; /* file system block size (same as secsize) */ extern char nflag; /* assume a no response */ extern char yflag; /* assume a yes response */ extern int debug; /* output debugging info */ extern int rflag; /* check raw file systems */ extern int fflag; /* check regardless of clean flag (force) */ extern char preen; /* just fix normal inconsistencies */ extern char mountedfs; /* checking mounted device */ extern int exitstat; /* exit status (set to 8 if 'No' response) */ extern int fsmodified; /* 1 => write done to file system */ extern int fsreadfd; /* file descriptor for reading file system */ extern int fswritefd; /* file descriptor for writing file system */ extern int iscorrupt; /* known to be corrupt/inconsistent */ extern int isdirty; /* 1 => write pending to file system */ extern char mountpoint[100]; /* string set to contain mount point */ extern char *busymap; /* ptr to primary blk busy map */ extern char *freemap; /* ptr to copy of disk map */ extern uint32_t part_start; extern uint32_t part_len; extern uint32_t part_bmp_bytes; extern uint32_t part_bmp_sectors; extern uint32_t part_bmp_loc; extern uint32_t rootblock; extern uint32_t rootlen; extern uint32_t lvintblock; extern uint32_t lvintlen; extern daddr_t n_blks; /* number of blocks in use */ extern daddr_t n_files; /* number of files in use */ extern daddr_t n_dirs; /* number of dirs in use */ /* * bit map related macros */ #define bitloc(a, i) ((a)[(i)/NBBY]) #define setbit(a, i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) #define clrbit(a, i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) #define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) #define isclr(a, i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) #define setbmap(blkno) setbit(blockmap, blkno) #define testbmap(blkno) isset(blockmap, blkno) #define clrbmap(blkno) clrbit(blockmap, blkno) #define setbusy(blkno) setbit(busymap, blkno) #define testbusy(blkno) isset(busymap, blkno) #define clrbusy(blkno) clrbit(busymap, blkno) #define fsbtodb(blkno) ((blkno) * (fsbsize / DEV_BSIZE)) #define dbtofsb(blkno) ((blkno) / (fsbsize / DEV_BSIZE)) #define STOP 0x01 #define SKIP 0x02 #define KEEPON 0x04 #define ALTERED 0x08 #define FOUND 0x10 time_t time(); struct dinode *ginode(); struct inoinfo *getinoinfo(); struct fileinfo *cachefile(); ino_t allocino(); int findino(); char *setup(); void markbusy(daddr_t, long); #ifndef MNTTYPE_UDFS #define MNTTYPE_UDFS "udfs" #endif #define SPACEMAP_OFF 24 #define FID_LENGTH(fid) (((sizeof (struct file_id) + \ (fid)->fid_iulen + (fid)->fid_idlen - 2) + 3) & ~3) #define EXTYPE(len) (((len) >> 30) & 3) #define EXTLEN(len) ((len) & 0x3fffffff) /* Integrity descriptor types */ #define LVI_OPEN 0 #define LVI_CLOSE 1 #ifdef __cplusplus } #endif #endif /* _FSCK_H */ /* * Copyright 1999 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 */ /* * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include #include #include #include #include #include #include #include #include #include "fsck.h" #include #include extern void errexit(char *, ...); extern unsigned int largefile_count; /* * Enter inodes into the cache. */ struct fileinfo * cachefile(feblock, len) uint32_t feblock; uint32_t len; { register struct fileinfo *inp; struct fileinfo **inpp; inpp = &inphash[feblock % listmax]; for (inp = *inpp; inp; inp = inp->fe_nexthash) { if (inp->fe_block == feblock) break; } if (!inp) { if (inpnext >= inplast) { inpnext = (struct fileinfo *)calloc(FEGROW + 1, sizeof (struct fileinfo)); if (inpnext == NULL) errexit(gettext("Cannot grow inphead list\n")); /* Link at extra entry so that we can find them */ inplast->fe_nexthash = inpnext; inplast->fe_block = (uint32_t)-1; inplast = &inpnext[FEGROW]; } inp = inpnext++; inp->fe_block = feblock; inp->fe_len = (uint16_t)len; inp->fe_lseen = 1; inp->fe_nexthash = *inpp; *inpp = inp; if (debug) { (void) printf("cacheing %x\n", feblock); } } else { inp->fe_lseen++; if (debug) { (void) printf("cache hit %x lcount %d lseen %d\n", feblock, inp->fe_lcount, inp->fe_lseen); } } return (inp); } /* * Copyright 2005 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 */ /* * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include /* use isdigit macro rather than 4.1 libc routine */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fsck.h" #include int debug; char nflag; char yflag; int rflag; static int wflag; /* check only writable filesystems */ int fflag; static int sflag; /* print status flag */ int isdirty; int fsmodified; int iscorrupt; int exitstat; uint32_t part_len; daddr_t n_blks; daddr_t n_files; daddr_t n_dirs; char preen; char mountpoint[100]; char mountedfs; char *devname; struct log_vol_int_desc *lvintp; extern int32_t writable(char *); extern void pfatal(char *, ...); extern void printfree(); extern void pwarn(char *, ...); extern void pass1(); extern void dofreemap(); extern void dolvint(); extern char *getfullblkname(); extern char *getfullrawname(); static int mflag = 0; /* sanity check only */ char *mntopt(); void catch(), catchquit(), voidquit(); int returntosingle; static void checkfilesys(); static void check_sanity(); static void usage(); static char *subopts [] = { #define PREEN 0 "p", #define DEBUG 1 "d", #define READ_ONLY 2 "r", #define ONLY_WRITES 3 "w", #define FORCE 4 /* force checking, even if clean */ "f", #define STATS 5 /* print time and busy stats */ "s", NULL }; uint32_t ecma_version = 2; int main(int argc, char *argv[]) { int c; char *suboptions, *value; int suboption; (void) setlocale(LC_ALL, ""); while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) { switch (c) { case 'm': mflag++; break; case 'n': /* default no answer flag */ case 'N': nflag++; yflag = 0; break; case 'o': /* * udfs specific options. */ suboptions = optarg; while (*suboptions != '\0') { suboption = getsubopt(&suboptions, subopts, &value); switch (suboption) { case PREEN: preen++; break; case DEBUG: debug++; break; case READ_ONLY: break; case ONLY_WRITES: /* check only writable filesystems */ wflag++; break; case FORCE: fflag++; break; case STATS: sflag++; break; default: usage(); } } break; case 'V': { int opt_count; char *opt_text; (void) fprintf(stdout, "fsck -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 'y': /* default yes answer flag */ case 'Y': yflag++; nflag = 0; break; case '?': usage(); } } argc -= optind; argv = &argv[optind]; rflag++; /* check raw devices */ if (signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, catch); } if (preen) { (void) signal(SIGQUIT, catchquit); } if (argc) { while (argc-- > 0) { if (wflag && !writable(*argv)) { (void) fprintf(stderr, gettext("not writeable '%s'\n"), *argv); argv++; } else checkfilesys(*argv++); } exit(exitstat); } return (0); } static void checkfilesys(char *filesys) { char *devstr; mountedfs = 0; iscorrupt = 1; if ((devstr = setup(filesys)) == 0) { if (iscorrupt == 0) return; if (preen) pfatal(gettext("CAN'T CHECK FILE SYSTEM.")); if ((exitstat == 0) && (mflag)) exitstat = 32; exit(exitstat); } else devname = devstr; if (mflag) check_sanity(filesys); /* this never returns */ iscorrupt = 0; /* * 1: scan inodes tallying blocks used */ if (preen == 0) { if (mountedfs) (void) printf(gettext("** Currently Mounted on %s\n"), mountpoint); if (mflag) { (void) printf( gettext("** Phase 1 - Sanity Check only\n")); return; } else (void) printf( gettext("** Phase 1 - Check Directories " "and Blocks\n")); } pass1(); if (sflag) { if (preen) (void) printf("%s: ", devname); else (void) printf("** "); } if (debug) (void) printf("pass1 isdirty %d\n", isdirty); if (debug) printfree(); dofreemap(); dolvint(); /* * print out summary statistics */ pwarn(gettext("%d files, %d dirs, %d used, %d free\n"), n_files, n_dirs, n_blks, part_len - n_blks); if (iscorrupt) exitstat = 36; if (!fsmodified) return; if (!preen) (void) printf( gettext("\n***** FILE SYSTEM WAS MODIFIED *****\n")); if (mountedfs) { exitstat = 40; } } /* * exit 0 - file system is unmounted and okay * exit 32 - file system is unmounted and needs checking * exit 33 - file system is mounted * for root file system * exit 34 - cannot stat device */ static void check_sanity(char *filename) { struct stat stbd, stbr; struct ustat usb; char *devname; struct vfstab vfsbuf; FILE *vfstab; int is_root = 0; int is_usr = 0; int is_block = 0; if (stat(filename, &stbd) < 0) { (void) fprintf(stderr, gettext("udfs fsck: sanity check failed : cannot stat " "%s\n"), filename); exit(34); } if ((stbd.st_mode & S_IFMT) == S_IFBLK) is_block = 1; else if ((stbd.st_mode & S_IFMT) == S_IFCHR) is_block = 0; else { (void) fprintf(stderr, gettext("udfs fsck: sanity check failed: %s not " "block or character device\n"), filename); exit(34); } /* * Determine if this is the root file system via vfstab. Give up * silently on failures. The whole point of this is not to care * if the root file system is already mounted. * * XXX - similar for /usr. This should be fixed to simply return * a new code indicating, mounted and needs to be checked. */ if ((vfstab = fopen(VFSTAB, "r")) != 0) { if (getvfsfile(vfstab, &vfsbuf, "/") == 0) { if (is_block) devname = vfsbuf.vfs_special; else devname = vfsbuf.vfs_fsckdev; if (stat(devname, &stbr) == 0) if (stbr.st_rdev == stbd.st_rdev) is_root = 1; } if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) { if (is_block) devname = vfsbuf.vfs_special; else devname = vfsbuf.vfs_fsckdev; if (stat(devname, &stbr) == 0) if (stbr.st_rdev == stbd.st_rdev) is_usr = 1; } } /* * XXX - only works if filename is a block device or if * character and block device has the same dev_t value */ if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) { (void) fprintf(stderr, gettext("udfs fsck: sanity check: %s " "already mounted\n"), filename); exit(33); } if (lvintp->lvid_int_type == LVI_CLOSE) { (void) fprintf(stderr, gettext("udfs fsck: sanity check: %s okay\n"), filename); } else { (void) fprintf(stderr, gettext("udfs fsck: sanity check: %s needs checking\n"), filename); exit(32); } exit(0); } char * unrawname(char *name) { char *dp; if ((dp = getfullblkname(name)) == NULL) return (""); return (dp); } char * rawname(char *name) { char *dp; if ((dp = getfullrawname(name)) == NULL) return (""); return (dp); } char * hasvfsopt(struct vfstab *vfs, char *opt) { char *f, *opts; static char *tmpopts; if (vfs->vfs_mntopts == NULL) return (NULL); if (tmpopts == 0) { tmpopts = (char *)calloc(256, sizeof (char)); if (tmpopts == 0) return (0); } (void) strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1)); opts = tmpopts; f = mntopt(&opts); for (; *f; f = mntopt(&opts)) { if (strncmp(opt, f, strlen(opt)) == 0) return (f - tmpopts + vfs->vfs_mntopts); } return (NULL); } static void usage() { (void) fprintf(stderr, gettext("udfs usage: fsck [-F udfs] " "[generic options] [-o p,w,s] [special ....]\n")); exit(31+1); } /* * Copyright 1999 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 */ /* * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include #include #include #include #include #include #include #include #include #include "fsck.h" #include "udfs.h" #include uint64_t maxuniqid; /* maximum unique id on medium */ /* * for each large file ( size > MAXOFF_T) this global counter * gets incremented here. */ extern unsigned int largefile_count; extern void pwarn(char *, ...); extern void pfatal(char *, ...); extern void errexit(char *, ...); extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); extern char *tagerrs[]; extern void maketag(struct tag *, struct tag *); extern void flush(int32_t, struct bufarea *); extern void putfilentry(struct bufarea *); extern int32_t bread(int32_t, char *, daddr_t, long); extern void bwrite(int, char *, daddr_t, long); extern int32_t dofix(struct inodesc *, char *); extern int32_t reply(char *); extern void ud_swap_short_ad(short_ad_t *); extern void ud_swap_long_ad(long_ad_t *); extern void dump16(char *, char *); static void adjust(struct fileinfo *); static void opndir(struct file_entry *); static int32_t getdir(struct file_entry *, struct bufarea **, u_offset_t *, struct file_id **); static void ckinode(struct file_entry *); struct bufarea *getfilentry(); /* Fields for traversing an allocation extent */ static uint32_t dir_adrsize; static uint32_t dir_adrindx; static uint32_t dir_naddrs; static uint8_t *extbuf; static uint8_t *dir_adrlist; /* Keep track of where we are in the directory */ static u_offset_t dir_baseoff; static uint32_t dir_basesize; static uint8_t *dirbuf; static uint8_t *dir_fidp; static uint32_t baseblock; #define MAXFIDSIZE 2048 static uint8_t fidbuf[MAXFIDSIZE]; void pass1(void) { struct file_entry *fp; struct fileinfo *fip; struct bufarea *bp; struct file_id *fidp; struct bufarea *fbp; int err; (void) cachefile(rootblock, rootlen); fip = &inphead[0]; /* The root */ fip->fe_lseen = 0; /* Didn't get here through directory */ n_files = n_dirs = 0; while (fip->fe_block) { u_offset_t offset, end; markbusy(fip->fe_block, fip->fe_len); bp = getfilentry(fip->fe_block, fip->fe_len); if (bp == NULL) { pwarn(gettext("Unable to read file entry at %x\n"), fip->fe_block); goto next; } fp = (struct file_entry *)bp->b_un.b_buf; fip->fe_lcount = fp->fe_lcount; fip->fe_type = fp->fe_icb_tag.itag_ftype; if (fp->fe_uniq_id >= maxuniqid) maxuniqid = fp->fe_uniq_id + 1; if (fip->fe_block == rootblock && fip->fe_type != FTYPE_DIRECTORY) errexit(gettext("Root file entry is not a " "directory\n")); if (debug) { (void) printf("do %x len %d type %d lcount %d" " lseen %d end %llx\n", fip->fe_block, fip->fe_len, fip->fe_type, fip->fe_lcount, fip->fe_lseen, fp->fe_info_len); } switch (fip->fe_type) { case FTYPE_DIRECTORY: n_dirs++; offset = 0; end = fp->fe_info_len; fbp = NULL; opndir(fp); for (offset = 0; offset < end; offset += FID_LENGTH(fidp)) { err = getdir(fp, &fbp, &offset, &fidp); if (err) { pwarn(gettext("Bad directory entry in " "file %x at offset %llx\n"), fip->fe_block, offset); offset = end; } if (fidp->fid_flags & FID_DELETED) continue; (void) cachefile(fidp->fid_icb.lad_ext_loc, fidp->fid_icb.lad_ext_len); } if (dirbuf) { free(dirbuf); dirbuf = NULL; } if (fbp) fbp->b_flags &= ~B_INUSE; if (debug) (void) printf("Done %x\n", fip->fe_block); break; case FTYPE_FILE: case FTYPE_SYMLINK: ckinode(fp); /* FALLTHROUGH */ default: n_files++; break; } putfilentry(bp); bp->b_flags &= ~B_INUSE; next: /* At end of this set of fips, get the next set */ if ((++fip)->fe_block == (uint32_t)-1) fip = fip->fe_nexthash; } /* Find bad link counts */ fip = &inphead[0]; while (fip->fe_block) { if (fip->fe_lcount != fip->fe_lseen) adjust(fip); /* At end of this set of fips, get the next set */ if ((++fip)->fe_block == (uint32_t)-1) fip = fip->fe_nexthash; } } static void opndir(struct file_entry *fp) { if (dirbuf) { free(dirbuf); dirbuf = NULL; } if (extbuf) { free(extbuf); extbuf = NULL; } dir_baseoff = 0; dir_basesize = 0; dir_adrindx = 0; switch (fp->fe_icb_tag.itag_flags & 0x3) { case ICB_FLAG_SHORT_AD: dir_adrsize = sizeof (short_ad_t); dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t); dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); break; case ICB_FLAG_LONG_AD: dir_adrsize = sizeof (long_ad_t); dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t); dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); break; case ICB_FLAG_EXT_AD: errexit(gettext("Can't handle ext_ads in directories/n")); break; case ICB_FLAG_ONE_AD: dir_adrsize = 0; dir_naddrs = 0; dir_adrlist = NULL; dir_basesize = fp->fe_len_adesc; dir_fidp = (uint8_t *)(fp->fe_spec + fp->fe_len_ear); baseblock = fp->fe_tag.tag_loc; break; } } /* Allocate and read in an allocation extent */ /* ARGSUSED */ int getallocext(struct file_entry *fp, uint32_t loc, uint32_t len) { uint32_t nb; uint8_t *ap; int i; int err; struct alloc_ext_desc *aep; if (debug) (void) printf(" allocext loc %x len %x\n", loc, len); nb = roundup(len, secsize); if (extbuf) free(extbuf); extbuf = (uint8_t *)malloc(nb); if (extbuf == NULL) errexit(gettext("Can't allocate directory extent buffer\n")); if (bread(fsreadfd, (char *)extbuf, fsbtodb(loc + part_start), nb) != 0) { (void) fprintf(stderr, gettext("Can't read allocation extent\n")); return (1); } aep = (struct alloc_ext_desc *)extbuf; err = verifytag(&aep->aed_tag, loc, &aep->aed_tag, UD_ALLOC_EXT_DESC); if (err) { (void) printf( gettext("Bad tag on alloc extent: %s\n"), tagerrs[err]); free(extbuf); return (1); } dir_adrlist = (uint8_t *)(aep + 1); dir_naddrs = aep->aed_len_aed / dir_adrsize; dir_adrindx = 0; /* Swap the descriptors */ for (i = 0, ap = dir_adrlist; i < dir_naddrs; i++, ap += dir_adrsize) { if (dir_adrsize == sizeof (short_ad_t)) { ud_swap_short_ad((short_ad_t *)ap); } else if (dir_adrsize == sizeof (long_ad_t)) { ud_swap_long_ad((long_ad_t *)ap); } } return (0); } /* * Variables used in this function and their relationships: * *poffset - read pointer in the directory * dir_baseoff - offset at start of dirbuf * dir_baselen - length of valid data in current extent * dir_adrindx - index into current allocation extent for location of * dir_baseoff * dir_naddrs - number of entries in current allocation extent * dir_fidp - pointer to dirbuf or immediate data in file entry * baseblock - block address of dir_baseoff * newoff - *poffset - dir_baseoff */ /* ARGSUSED1 */ static int32_t getdir(struct file_entry *fp, struct bufarea **fbp, u_offset_t *poffset, struct file_id **fidpp) { struct file_id *fidp = (struct file_id *)fidbuf; struct short_ad *sap; struct long_ad *lap; int i, newoff, xoff = 0; uint32_t block = 0, nb, len = 0, left; u_offset_t offset; int err, type = 0; again: offset = *poffset; again2: if (debug) (void) printf("getdir %llx\n", offset); newoff = offset - dir_baseoff; if (newoff >= dir_basesize) { if (dirbuf) { free(dirbuf); dirbuf = NULL; } } else { if (block == 0) block = baseblock + (newoff / secsize); goto nextone; } again3: switch (fp->fe_icb_tag.itag_flags & 0x3) { case ICB_FLAG_SHORT_AD: sap = &((short_ad_t *)dir_adrlist)[dir_adrindx]; for (i = dir_adrindx; i < dir_naddrs; i++, sap++) { len = EXTLEN(sap->sad_ext_len); type = EXTYPE(sap->sad_ext_len); if (type == 3) { if (i < dir_naddrs - 1) errexit(gettext("Allocation extent not " "at end of list\n")); markbusy(sap->sad_ext_loc, len); if (getallocext(fp, sap->sad_ext_loc, len)) return (1); goto again3; } if (newoff < len) break; newoff -= len; dir_baseoff += len; if (debug) (void) printf( " loc %x len %x\n", sap->sad_ext_loc, len); } dir_adrindx = i; if (debug) (void) printf(" loc %x len %x\n", sap->sad_ext_loc, sap->sad_ext_len); baseblock = sap->sad_ext_loc; if (block == 0) block = baseblock; dir_basesize = len; if (type < 2) markbusy(sap->sad_ext_loc, len); if (type != 0) { *poffset += dir_basesize; goto again; } nb = roundup(len, secsize); dirbuf = (uint8_t *)malloc(nb); if (dirbuf == NULL) errexit(gettext("Can't allocate directory extent " "buffer\n")); if (bread(fsreadfd, (char *)dirbuf, fsbtodb(baseblock + part_start), nb) != 0) { errexit(gettext("Can't read directory extent\n")); } dir_fidp = dirbuf; break; case ICB_FLAG_LONG_AD: lap = &((long_ad_t *)dir_adrlist)[dir_adrindx]; for (i = dir_adrindx; i < dir_naddrs; i++, lap++) { len = EXTLEN(lap->lad_ext_len); type = EXTYPE(lap->lad_ext_len); if (type == 3) { if (i < dir_naddrs - 1) errexit(gettext("Allocation extent not " "at end of list\n")); markbusy(lap->lad_ext_loc, len); if (getallocext(fp, lap->lad_ext_loc, len)) return (1); goto again3; } if (newoff < len) break; newoff -= len; dir_baseoff += len; if (debug) (void) printf( " loc %x len %x\n", lap->lad_ext_loc, len); } dir_adrindx = i; if (debug) (void) printf(" loc %x len %x\n", lap->lad_ext_loc, lap->lad_ext_len); baseblock = lap->lad_ext_loc; if (block == 0) block = baseblock; dir_basesize = len; if (type < 2) markbusy(lap->lad_ext_loc, len); if (type != 0) { *poffset += dir_basesize; goto again; } nb = roundup(len, secsize); dirbuf = (uint8_t *)malloc(nb); if (dirbuf == NULL) errexit(gettext("Can't allocate directory extent " "buffer\n")); if (bread(fsreadfd, (char *)dirbuf, fsbtodb(baseblock + part_start), nb) != 0) { errexit(gettext("Can't read directory extent\n")); } dir_fidp = dirbuf; break; case ICB_FLAG_EXT_AD: break; case ICB_FLAG_ONE_AD: errexit(gettext("Logic error in getdir - at ICB_FLAG_ONE_AD " "case\n")); break; } nextone: if (debug) (void) printf("getdirend blk %x dir_baseoff %llx newoff %x\n", block, dir_baseoff, newoff); left = dir_basesize - newoff; if (xoff + left > MAXFIDSIZE) left = MAXFIDSIZE - xoff; bcopy((char *)dir_fidp + newoff, (char *)fidbuf + xoff, left); xoff += left; /* * If we have a fid that crosses an extent boundary, then force * a read of the next extent, and fill up the rest of the fid. */ if (xoff < sizeof (fidp->fid_tag) || xoff < sizeof (fidp->fid_tag) + SWAP16(fidp->fid_tag.tag_crc_len)) { offset += left; if (debug) (void) printf("block crossing at offset %llx\n", offset); goto again2; } err = verifytag(&fidp->fid_tag, block, &fidp->fid_tag, UD_FILE_ID_DESC); if (debug) { dump16((char *)fidp, "\n"); } if (err) { pwarn(gettext("Bad directory tag: %s\n"), tagerrs[err]); return (err); } *fidpp = fidp; return (0); } static void ckinode(struct file_entry *fp) { struct short_ad *sap = NULL; struct long_ad *lap; int i, type, len; switch (fp->fe_icb_tag.itag_flags & 0x3) { case ICB_FLAG_SHORT_AD: dir_adrsize = sizeof (short_ad_t); dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t); sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear); again1: for (i = 0; i < dir_naddrs; i++, sap++) { len = EXTLEN(sap->sad_ext_len); type = EXTYPE(sap->sad_ext_len); if (type < 2) markbusy(sap->sad_ext_loc, len); if (debug) (void) printf( " loc %x len %x\n", sap->sad_ext_loc, sap->sad_ext_len); if (type == 3) { markbusy(sap->sad_ext_loc, len); /* This changes dir_naddrs and dir_adrlist */ if (getallocext(fp, sap->sad_ext_loc, len)) break; sap = (short_ad_t *)dir_adrlist; goto again1; } } break; case ICB_FLAG_LONG_AD: dir_adrsize = sizeof (long_ad_t); dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t); lap = (long_ad_t *)(fp->fe_spec + fp->fe_len_ear); again2: for (i = 0; i < dir_naddrs; i++, lap++) { len = EXTLEN(lap->lad_ext_len); type = EXTYPE(lap->lad_ext_len); if (type < 2) markbusy(lap->lad_ext_loc, len); if (debug) (void) printf( " loc %x len %x\n", lap->lad_ext_loc, lap->lad_ext_len); if (type == 3) { markbusy(sap->sad_ext_loc, len); /* This changes dir_naddrs and dir_adrlist */ if (getallocext(fp, lap->lad_ext_loc, len)) break; lap = (long_ad_t *)dir_adrlist; goto again2; } } break; case ICB_FLAG_EXT_AD: break; case ICB_FLAG_ONE_AD: break; } } static void adjust(struct fileinfo *fip) { struct file_entry *fp; struct bufarea *bp; bp = getfilentry(fip->fe_block, fip->fe_len); if (bp == NULL) errexit(gettext("Unable to read file entry at %x\n"), fip->fe_block); fp = (struct file_entry *)bp->b_un.b_buf; pwarn(gettext("LINK COUNT %s I=%x"), fip->fe_type == FTYPE_DIRECTORY ? "DIR" : fip->fe_type == FTYPE_SYMLINK ? "SYM" : fip->fe_type == FTYPE_FILE ? "FILE" : "???", fip->fe_block); (void) printf(gettext(" COUNT %d SHOULD BE %d"), fip->fe_lcount, fip->fe_lseen); if (preen) { if (fip->fe_lseen > fip->fe_lcount) { (void) printf("\n"); pfatal(gettext("LINK COUNT INCREASING")); } (void) printf(gettext(" (ADJUSTED)\n")); } if (preen || reply(gettext("ADJUST")) == 1) { fp->fe_lcount = fip->fe_lseen; putfilentry(bp); dirty(bp); flush(fswritefd, bp); } bp->b_flags &= ~B_INUSE; } void dofreemap(void) { int i; char *bp, *fp; struct inodesc idesc; if (freemap == NULL) return; /* Flip bits in the busy map */ bp = busymap; for (i = 0, bp = busymap; i < part_bmp_bytes; i++, bp++) *bp = ~*bp; /* Mark leftovers in byte as allocated */ if (part_len % NBBY) bp[-1] &= (unsigned)0xff >> (NBBY - part_len % NBBY); bp = busymap; fp = freemap; bzero((char *)&idesc, sizeof (struct inodesc)); idesc.id_type = ADDR; if (bcmp(bp, fp, part_bmp_bytes) != 0 && dofix(&idesc, gettext("BLK(S) MISSING IN FREE BITMAP"))) { bcopy(bp, fp, part_bmp_bytes); maketag(&spacep->sbd_tag, &spacep->sbd_tag); bwrite(fswritefd, (char *)spacep, fsbtodb(part_bmp_loc), part_bmp_sectors * secsize); } } void dolvint(void) { struct lvid_iu *lviup; struct inodesc idesc; bzero((char *)&idesc, sizeof (struct inodesc)); idesc.id_type = ADDR; lviup = (struct lvid_iu *)&lvintp->lvid_fst[2]; if ((lvintp->lvid_fst[0] != part_len - n_blks || lvintp->lvid_int_type != LVI_CLOSE || lviup->lvidiu_nfiles != n_files || lviup->lvidiu_ndirs != n_dirs || lvintp->lvid_uniqid < maxuniqid) && dofix(&idesc, gettext("LOGICAL VOLUME INTEGRITY COUNTS WRONG"))) { lvintp->lvid_int_type = LVI_CLOSE; lvintp->lvid_fst[0] = part_len - n_blks; lviup->lvidiu_nfiles = n_files; lviup->lvidiu_ndirs = n_dirs; lvintp->lvid_uniqid = maxuniqid; maketag(&lvintp->lvid_tag, &lvintp->lvid_tag); bwrite(fswritefd, (char *)lvintp, fsbtodb(lvintblock), lvintlen); } } /* * Copyright 2005 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 */ /* * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #define DKTYPENAMES #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for ENDIAN defines */ #include #include #include #include #include #include #include #include #include #include #include "fsck.h" extern void errexit(char *, ...); extern int32_t mounted(char *); extern void pwarn(char *, ...); extern void pfatal(char *, ...); extern void printclean(); extern void bufinit(); extern void ckfini(); extern int32_t bread(int32_t, char *, daddr_t, long); extern int32_t reply(char *); static int32_t readvolseq(int32_t); static uint32_t get_last_block(); extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); extern char *tagerrs[]; #define POWEROF2(num) (((num) & ((num) - 1)) == 0) extern int mflag; long fsbsize; static char hotroot; /* checking root device */ char *freemap; char *busymap; uint32_t part_start; uint32_t lvintlen; uint32_t lvintblock; uint32_t rootblock; uint32_t rootlen; uint32_t part_bmp_bytes; uint32_t part_bmp_sectors; uint32_t part_bmp_loc; int fsreadfd; int fswritefd; long secsize; long numdirs, numfiles, listmax; struct fileinfo *inphead, **inphash, *inpnext, *inplast; struct space_bmap_desc *spacep; static struct unall_desc *unallp; static struct pri_vol_desc *pvolp; static struct part_desc *partp; static struct phdr_desc *pheadp; static struct log_vol_desc *logvp; struct lvid_iu *lviup; static struct vdp_desc *volp; static struct anch_vol_desc_ptr *avdp; static struct iuvd_desc *iudp; char avdbuf[MAXBSIZE]; /* buffer for anchor volume descriptor */ char *main_vdbuf; /* buffer for entire main volume sequence */ char *res_vdbuf; /* buffer for reserved volume sequence */ int serialnum = -1; /* set from primary volume descriptor */ char * setup(char *dev) { dev_t rootdev; struct stat statb; static char devstr[MAXPATHLEN]; char *raw, *rawname(), *unrawname(); struct ustat ustatb; if (stat("/", &statb) < 0) errexit(gettext("Can't stat root\n")); rootdev = statb.st_dev; devname = devstr; (void) strncpy(devstr, dev, sizeof (devstr)); restat: if (stat(devstr, &statb) < 0) { (void) printf(gettext("Can't stat %s\n"), devstr); exitstat = 34; return (0); } /* * A mount point is specified. But the mount point doesn't * match entries in the /etc/vfstab. * Search mnttab, because if the fs is error locked, it is * allowed to be fsck'd while mounted. */ if ((statb.st_mode & S_IFMT) == S_IFDIR) { (void) printf(gettext("%s is not a block or " "character device\n"), dev); return (0); } if ((statb.st_mode & S_IFMT) == S_IFBLK) { if (rootdev == statb.st_rdev) hotroot++; else if (ustat(statb.st_rdev, &ustatb) == 0) { (void) printf(gettext("%s is a mounted file system, " "ignored\n"), dev); exitstat = 33; return (0); } } if ((statb.st_mode & S_IFMT) == S_IFDIR) { FILE *vfstab; struct vfstab vfsbuf; /* * Check vfstab for a mount point with this name */ if ((vfstab = fopen(VFSTAB, "r")) == NULL) { errexit(gettext("Can't open checklist file: %s\n"), VFSTAB); } while (getvfsent(vfstab, &vfsbuf) == 0) { if (strcmp(devstr, vfsbuf.vfs_mountp) == 0) { if (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UDFS) != 0) { /* * found the entry but it is not a * udfs filesystem, don't check it */ (void) fclose(vfstab); return (0); } (void) strcpy(devstr, vfsbuf.vfs_special); if (rflag) { raw = rawname( unrawname(vfsbuf.vfs_special)); (void) strcpy(devstr, raw); } goto restat; } } (void) fclose(vfstab); } else if (((statb.st_mode & S_IFMT) != S_IFBLK) && ((statb.st_mode & S_IFMT) != S_IFCHR)) { if (preen) pwarn(gettext("file is not a block or " "character device.\n")); else if (reply(gettext("file is not a block or " "character device; OK")) == 0) return (0); /* * To fsck regular files (fs images) * we need to clear the rflag since * regular files don't have raw names. --CW */ rflag = 0; } if (mounted(devstr)) { if (rflag) mountedfs++; else { (void) printf(gettext("%s is mounted, fsck on BLOCK " "device ignored\n"), devstr); exit(33); } sync(); /* call sync, only when devstr's mounted */ } if (rflag) { char blockname[MAXPATHLEN]; /* * For root device check, must check * block devices. */ (void) strcpy(blockname, devstr); if (stat(unrawname(blockname), &statb) < 0) { (void) printf(gettext("Can't stat %s\n"), blockname); exitstat = 34; return (0); } } if (rootdev == statb.st_rdev) hotroot++; if ((fsreadfd = open(devstr, O_RDONLY)) < 0) { (void) printf(gettext("Can't open %s\n"), devstr); exitstat = 34; return (0); } if (preen == 0 || debug != 0) (void) printf("** %s", devstr); if (nflag || (fswritefd = open(devstr, O_WRONLY)) < 0) { fswritefd = -1; if (preen && !debug) pfatal(gettext("(NO WRITE ACCESS)\n")); (void) printf(gettext(" (NO WRITE)")); } if (preen == 0) (void) printf("\n"); if (debug && (hotroot || mountedfs)) { (void) printf("** %s", devstr); if (hotroot) (void) printf(" is root fs%s", mountedfs? " and": ""); if (mountedfs) (void) printf(" is mounted"); (void) printf(".\n"); } fsmodified = 0; if (readvolseq(1) == 0) return (0); if (fflag == 0 && preen && lvintp->lvid_int_type == LVI_CLOSE) { iscorrupt = 0; printclean(); return (0); } listmax = FEGROW; inphash = (struct fileinfo **)calloc(FEGROW, sizeof (struct fileinfo *)); inphead = (struct fileinfo *)calloc(FEGROW + 1, sizeof (struct fileinfo)); if (inphead == NULL || inphash == NULL) { (void) printf(gettext("cannot alloc %ld bytes for inphead\n"), listmax * sizeof (struct fileinfo)); goto badsb; } inpnext = inphead; inplast = &inphead[listmax]; bufinit(); return (devstr); badsb: ckfini(); exitstat = 39; return (0); } static int check_pri_vol_desc(struct tag *tp) { pvolp = (struct pri_vol_desc *)tp; return (0); } static int check_avdp(struct tag *tp) { avdp = (struct anch_vol_desc_ptr *)tp; return (0); } static int check_vdp(struct tag *tp) { volp = (struct vdp_desc *)tp; return (0); } static int check_iuvd(struct tag *tp) { iudp = (struct iuvd_desc *)tp; return (0); } static int check_part_desc(struct tag *tp) { partp = (struct part_desc *)tp; /* LINTED */ pheadp = (struct phdr_desc *)&partp->pd_pc_use; part_start = partp->pd_part_start; part_len = partp->pd_part_length; if (debug) (void) printf("partition start %x len %x\n", part_start, part_len); return (0); } static int check_log_desc(struct tag *tp) { logvp = (struct log_vol_desc *)tp; return (0); } static int check_unall_desc(struct tag *tp) { unallp = (struct unall_desc *)tp; return (0); } /* ARGSUSED */ static int check_term_desc(struct tag *tp) { return (0); } static int check_lvint(struct tag *tp) { /* LINTED */ lvintp = (struct log_vol_int_desc *)tp; return (0); } void dump16(char *cp, char *nl) { int i; long *ptr; for (i = 0; i < 16; i += 4) { /* LINTED */ ptr = (long *)(cp + i); (void) printf("%08lx ", *ptr); } (void) printf(nl); } /* * Read in the super block and its summary info. */ /* ARGSUSED */ static int readvolseq(int32_t listerr) { struct tag *tp; long_ad_t *lap; struct anch_vol_desc_ptr *avp; uint8_t *cp, *end; daddr_t nextblock; int err; long freelen; daddr_t avdp; struct file_set_desc *fileset; uint32_t filesetblock; uint32_t filesetlen; if (debug) (void) printf("Disk partition size: %x\n", get_last_block()); /* LINTED */ avp = (struct anch_vol_desc_ptr *)avdbuf; tp = &avp->avd_tag; for (fsbsize = 512; fsbsize <= MAXBSIZE; fsbsize <<= 1) { avdp = FIRSTAVDP * fsbsize / DEV_BSIZE; if (bread(fsreadfd, avdbuf, avdp, fsbsize) != 0) return (0); err = verifytag(tp, FIRSTAVDP, tp, UD_ANCH_VOL_DESC); if (debug) (void) printf("bsize %ld tp->tag %d, %s\n", fsbsize, tp->tag_id, tagerrs[err]); if (err == 0) break; } if (fsbsize > MAXBSIZE) errexit(gettext("Can't find anchor volume descriptor\n")); secsize = fsbsize; if (debug) (void) printf("fsbsize = %ld\n", fsbsize); main_vdbuf = malloc(avp->avd_main_vdse.ext_len); res_vdbuf = malloc(avp->avd_res_vdse.ext_len); if (main_vdbuf == NULL || res_vdbuf == NULL) errexit("cannot allocate space for volume sequences\n"); if (debug) (void) printf("reading volume sequences " "(%d bytes at %x and %x)\n", avp->avd_main_vdse.ext_len, avp->avd_main_vdse.ext_loc, avp->avd_res_vdse.ext_loc); if (bread(fsreadfd, main_vdbuf, fsbtodb(avp->avd_main_vdse.ext_loc), avp->avd_main_vdse.ext_len) != 0) return (0); if (bread(fsreadfd, res_vdbuf, fsbtodb(avp->avd_res_vdse.ext_loc), avp->avd_res_vdse.ext_len) != 0) return (0); 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 += fsbsize, nextblock++) { /* LINTED */ tp = (struct tag *)cp; err = verifytag(tp, nextblock, tp, 0); if (debug) { dump16((char *)cp, ""); (void) printf("blk %lx err %s tag %d\n", nextblock, tagerrs[err], tp->tag_id); } if (err == 0) { if (serialnum >= 0 && tp->tag_sno != serialnum) { (void) printf(gettext("serial number mismatch " "tag type %d, block %lx\n"), tp->tag_id, nextblock); continue; } switch (tp->tag_id) { case UD_PRI_VOL_DESC: serialnum = tp->tag_sno; if (debug) { (void) printf("serial number = %d\n", serialnum); } err = check_pri_vol_desc(tp); break; case UD_ANCH_VOL_DESC: err = check_avdp(tp); break; case UD_VOL_DESC_PTR: err = check_vdp(tp); break; case UD_IMPL_USE_DESC: err = check_iuvd(tp); break; case UD_PART_DESC: err = check_part_desc(tp); break; case UD_LOG_VOL_DESC: err = check_log_desc(tp); break; case UD_UNALL_SPA_DESC: err = check_unall_desc(tp); break; case UD_TERM_DESC: err = check_term_desc(tp); goto done; break; case UD_LOG_VOL_INT: err = check_lvint(tp); break; default: (void) printf(gettext("Invalid volume " "sequence tag %d\n"), tp->tag_id); } } else { (void) printf(gettext("Volume sequence tag error %s\n"), tagerrs[err]); } } done: if (!partp || !logvp) { (void) printf(gettext("Missing partition header or" " logical volume descriptor\n")); return (0); } /* Get the logical volume integrity descriptor */ lvintblock = logvp->lvd_int_seq_ext.ext_loc; lvintlen = logvp->lvd_int_seq_ext.ext_len; lvintp = (struct log_vol_int_desc *)malloc(lvintlen); if (debug) (void) printf("Logvolint at %x for %d bytes\n", lvintblock, lvintlen); if (lvintp == NULL) { (void) printf(gettext("Can't allocate space for logical" " volume integrity sequence\n")); return (0); } if (bread(fsreadfd, (char *)lvintp, fsbtodb(lvintblock), lvintlen) != 0) { return (0); } err = verifytag(&lvintp->lvid_tag, lvintblock, &lvintp->lvid_tag, UD_LOG_VOL_INT); if (debug) { dump16((char *)lvintp, "\n"); } if (err) { (void) printf(gettext("Log_vol_int tag error: %s, tag = %d\n"), tagerrs[err], lvintp->lvid_tag.tag_id); return (0); } /* Get pointer to implementation use area */ lviup = (struct lvid_iu *)&lvintp->lvid_fst[lvintp->lvid_npart*2]; if (debug) { (void) printf("free space %d total %d ", lvintp->lvid_fst[0], lvintp->lvid_fst[1]); (void) printf(gettext("nfiles %d ndirs %d\n"), lviup->lvidiu_nfiles, lviup->lvidiu_ndirs); } /* Set up free block map and read in the existing free space map */ freelen = pheadp->phdr_usb.sad_ext_len; if (freelen == 0) { (void) printf(gettext("No partition free map\n")); } part_bmp_bytes = (part_len + NBBY - 1) / NBBY; busymap = calloc((unsigned)part_bmp_bytes, sizeof (char)); if (busymap == NULL) { (void) printf(gettext("Can't allocate free block bitmap\n")); return (0); } if (freelen) { part_bmp_sectors = (part_bmp_bytes + SPACEMAP_OFF + secsize - 1) / secsize; part_bmp_loc = pheadp->phdr_usb.sad_ext_loc + part_start; /* Mark the partition map blocks busy */ markbusy(pheadp->phdr_usb.sad_ext_loc, part_bmp_sectors * secsize); spacep = (struct space_bmap_desc *) malloc(secsize*part_bmp_sectors); if (spacep == NULL) { (void) printf(gettext("Can't allocate partition " "map\n")); return (0); } if (bread(fsreadfd, (char *)spacep, fsbtodb(part_bmp_loc), part_bmp_sectors * secsize) != 0) return (0); cp = (uint8_t *)spacep; err = verifytag(&spacep->sbd_tag, pheadp->phdr_usb.sad_ext_loc, &spacep->sbd_tag, UD_SPA_BMAP_DESC); if (debug) { dump16((char *)cp, ""); (void) printf("blk %x err %s tag %d\n", part_bmp_loc, tagerrs[err], spacep->sbd_tag.tag_id); } freemap = (char *)cp + SPACEMAP_OFF; if (debug) (void) printf("err %s tag %x space bitmap at %x" " length %d nbits %d nbytes %d\n", tagerrs[err], spacep->sbd_tag.tag_id, part_bmp_loc, part_bmp_sectors, spacep->sbd_nbits, spacep->sbd_nbytes); if (err) { (void) printf(gettext("Space bitmap tag error, %s, " "tag = %d\n"), tagerrs[err], spacep->sbd_tag.tag_id); return (0); } } /* Get the fileset descriptor */ lap = (long_ad_t *)&logvp->lvd_lvcu; filesetblock = lap->lad_ext_loc; filesetlen = lap->lad_ext_len; markbusy(filesetblock, filesetlen); if (debug) (void) printf("Fileset descriptor at %x for %d bytes\n", filesetblock, filesetlen); if (!filesetlen) { (void) printf(gettext("No file set descriptor found\n")); return (0); } fileset = (struct file_set_desc *)malloc(filesetlen); if (fileset == NULL) { (void) printf(gettext("Unable to allocate fileset\n")); return (0); } if (bread(fsreadfd, (char *)fileset, fsbtodb(filesetblock + part_start), filesetlen) != 0) { return (0); } err = verifytag(&fileset->fsd_tag, filesetblock, &fileset->fsd_tag, UD_FILE_SET_DESC); if (err) { (void) printf(gettext("Fileset tag error, tag = %d, %s\n"), fileset->fsd_tag.tag_id, tagerrs[err]); return (0); } /* Get the address of the root file entry */ lap = (long_ad_t *)&fileset->fsd_root_icb; rootblock = lap->lad_ext_loc; rootlen = lap->lad_ext_len; if (debug) (void) printf("Root at %x for %d bytes\n", rootblock, rootlen); return (1); } uint32_t get_last_block() { struct vtoc vtoc; struct dk_cinfo dki_info; if (ioctl(fsreadfd, 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(fsreadfd, 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); } /* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fsck.h" #include #include static struct bufarea bufhead; extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); extern char *tagerrs[]; extern void maketag(struct tag *, struct tag *); extern char *hasvfsopt(struct vfstab *, char *); static struct bufarea *getdatablk(daddr_t, long); static struct bufarea *getblk(struct bufarea *, daddr_t, long); void flush(int32_t, struct bufarea *); int32_t bread(int32_t, char *, daddr_t, long); void bwrite(int, char *, daddr_t, long); static int32_t getaline(FILE *, char *, int32_t); void errexit(char *, ...) __NORETURN; static long diskreads, totalreads; /* Disk cache statistics */ offset_t llseek(); extern unsigned int largefile_count; /* * An unexpected inconsistency occured. * Die if preening, otherwise just print message and continue. */ /* VARARGS1 */ void pfatal(char *fmt, ...) { va_list args; va_start(args, fmt); if (preen) { (void) printf("%s: ", devname); (void) vprintf(fmt, args); (void) printf("\n"); (void) printf( gettext("%s: UNEXPECTED INCONSISTENCY; RUN fsck " "MANUALLY.\n"), devname); va_end(args); exit(36); } (void) vprintf(fmt, args); va_end(args); } /* * Pwarn just prints a message when not preening, * or a warning (preceded by filename) when preening. */ /* VARARGS1 */ void pwarn(char *fmt, ...) { va_list args; va_start(args, fmt); if (preen) (void) printf("%s: ", devname); (void) vprintf(fmt, args); va_end(args); } /* VARARGS1 */ void errexit(char *fmt, ...) { va_list args; va_start(args, fmt); (void) vprintf(fmt, args); va_end(args); exit(39); } void markbusy(daddr_t block, long count) { register int i; count = roundup(count, secsize) / secsize; for (i = 0; i < count; i++, block++) { if ((unsigned)block > part_len) { pwarn(gettext("Block %lx out of range\n"), block); break; } if (testbusy(block)) pwarn(gettext("Dup block %lx\n"), block); else { n_blks++; setbusy(block); } } } void printfree() { int i, startfree, endfree; startfree = -1; endfree = -1; for (i = 0; i < part_len; i++) { if (!testbusy(i)) { if (startfree <= 0) startfree = i; endfree = i; } else if (startfree >= 0) { (void) printf("free: %x-%x\n", startfree, endfree - 1); startfree = -1; } } if (startfree >= 0) { (void) printf("free: %x-%x\n", startfree, endfree); } } struct bufarea * getfilentry(uint32_t block, int len) { struct bufarea *bp; struct file_entry *fp; int err; if (len > fsbsize) { (void) printf(gettext("File entry at %x is too long " "(%d bytes)\n"), block, len); len = fsbsize; } bp = getdatablk((daddr_t)(block + part_start), fsbsize); if (bp->b_errs) { bp->b_flags &= ~B_INUSE; return (NULL); } /* LINTED */ fp = (struct file_entry *)bp->b_un.b_buf; err = verifytag(&fp->fe_tag, block, &fp->fe_tag, UD_FILE_ENTRY); if (err) { (void) printf(gettext("Tag error %s or bad file entry, " "tag=%d\n"), tagerrs[err], fp->fe_tag.tag_id); bp->b_flags &= ~B_INUSE; return (NULL); } return (bp); } void putfilentry(struct bufarea *bp) { struct file_entry *fp; /* LINTED */ fp = (struct file_entry *)bp->b_un.b_buf; maketag(&fp->fe_tag, &fp->fe_tag); } int32_t reply(char *question) { char line[80]; if (preen) pfatal(gettext("INTERNAL ERROR: GOT TO reply()")); (void) printf("\n%s? ", question); if (nflag || fswritefd < 0) { (void) printf(gettext(" no\n\n")); iscorrupt = 1; /* known to be corrupt */ return (0); } if (yflag) { (void) printf(gettext(" yes\n\n")); return (1); } if (getaline(stdin, line, sizeof (line)) == EOF) errexit("\n"); (void) printf("\n"); if (line[0] == 'y' || line[0] == 'Y') return (1); else { iscorrupt = 1; /* known to be corrupt */ return (0); } } int32_t getaline(FILE *fp, char *loc, int32_t maxlen) { int n; register char *p, *lastloc; p = loc; lastloc = &p[maxlen-1]; while ((n = getc(fp)) != '\n') { if (n == EOF) return (EOF); if (!isspace(n) && p < lastloc) *p++ = n; } *p = 0; return (p - loc); } /* * Malloc buffers and set up cache. */ void bufinit() { register struct bufarea *bp; long bufcnt, i; char *bufp; bufp = malloc((unsigned int)fsbsize); if (bufp == 0) errexit(gettext("cannot allocate buffer pool\n")); bufhead.b_next = bufhead.b_prev = &bufhead; bufcnt = MAXBUFSPACE / fsbsize; if (bufcnt < MINBUFS) bufcnt = MINBUFS; for (i = 0; i < bufcnt; i++) { bp = (struct bufarea *)malloc(sizeof (struct bufarea)); bufp = malloc((unsigned int)fsbsize); if (bp == NULL || bufp == NULL) { if (i >= MINBUFS) break; errexit(gettext("cannot allocate buffer pool\n")); } bp->b_un.b_buf = bufp; bp->b_prev = &bufhead; bp->b_next = bufhead.b_next; bufhead.b_next->b_prev = bp; bufhead.b_next = bp; initbarea(bp); } bufhead.b_size = i; /* save number of buffers */ } /* * Manage a cache of directory blocks. */ static struct bufarea * getdatablk(daddr_t blkno, long size) { register struct bufarea *bp; for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) if (bp->b_bno == fsbtodb(blkno)) goto foundit; for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) if ((bp->b_flags & B_INUSE) == 0) break; if (bp == &bufhead) errexit(gettext("deadlocked buffer pool\n")); (void) getblk(bp, blkno, size); /* fall through */ foundit: totalreads++; bp->b_prev->b_next = bp->b_next; bp->b_next->b_prev = bp->b_prev; bp->b_prev = &bufhead; bp->b_next = bufhead.b_next; bufhead.b_next->b_prev = bp; bufhead.b_next = bp; bp->b_flags |= B_INUSE; return (bp); } static struct bufarea * getblk(struct bufarea *bp, daddr_t blk, long size) { daddr_t dblk; dblk = fsbtodb(blk); if (bp->b_bno == dblk) return (bp); flush(fswritefd, bp); diskreads++; bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); bp->b_bno = dblk; bp->b_size = size; return (bp); } void flush(int32_t fd, struct bufarea *bp) { if (!bp->b_dirty) return; if (bp->b_errs != 0) pfatal(gettext("WRITING ZERO'ED BLOCK %d TO DISK\n"), bp->b_bno); bp->b_dirty = 0; bp->b_errs = 0; bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); } static void rwerror(char *mesg, daddr_t blk) { if (preen == 0) (void) printf("\n"); pfatal(gettext("CANNOT %s: BLK %ld"), mesg, blk); if (reply(gettext("CONTINUE")) == 0) errexit(gettext("Program terminated\n")); } void ckfini() { struct bufarea *bp, *nbp; int cnt = 0; for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { cnt++; flush(fswritefd, bp); nbp = bp->b_prev; free(bp->b_un.b_buf); free((char *)bp); } if (bufhead.b_size != cnt) errexit(gettext("Panic: lost %d buffers\n"), bufhead.b_size - cnt); if (debug) (void) printf("cache missed %ld of %ld (%ld%%)\n", diskreads, totalreads, totalreads ? diskreads * 100 / totalreads : 0); (void) close(fsreadfd); (void) close(fswritefd); } int32_t bread(int fd, char *buf, daddr_t blk, long size) { char *cp; int i, errs; offset_t offset = ldbtob(blk); offset_t addr; if (llseek(fd, offset, 0) < 0) rwerror(gettext("SEEK"), blk); else if (read(fd, buf, (int)size) == size) return (0); rwerror(gettext("READ"), blk); if (llseek(fd, offset, 0) < 0) rwerror(gettext("SEEK"), blk); errs = 0; bzero(buf, (int)size); pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE READ:")); for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { addr = ldbtob(blk + i); if (llseek(fd, addr, SEEK_CUR) < 0 || read(fd, cp, (int)secsize) < 0) { (void) printf(" %ld", blk + i); errs++; } } (void) printf("\n"); return (errs); } void bwrite(int fd, char *buf, daddr_t blk, long size) { int i, n; char *cp; offset_t offset = ldbtob(blk); offset_t addr; if (fd < 0) return; if (llseek(fd, offset, 0) < 0) rwerror(gettext("SEEK"), blk); else if (write(fd, buf, (int)size) == size) { fsmodified = 1; return; } rwerror(gettext("WRITE"), blk); if (llseek(fd, offset, 0) < 0) rwerror(gettext("SEEK"), blk); pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:")); for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { n = 0; addr = ldbtob(blk + i); if (llseek(fd, addr, SEEK_CUR) < 0 || (n = write(fd, cp, DEV_BSIZE)) < 0) { (void) printf(" %ld", blk + i); } else if (n > 0) { fsmodified = 1; } } (void) printf("\n"); } void catch() { ckfini(); exit(37); } /* * When preening, allow a single quit to signal * a special exit after filesystem checks complete * so that reboot sequence may be interrupted. */ void catchquit() { extern int returntosingle; (void) printf(gettext("returning to single-user after filesystem " "check\n")); returntosingle = 1; (void) signal(SIGQUIT, SIG_DFL); } /* * determine whether an inode should be fixed. */ /* ARGSUSED1 */ int32_t dofix(struct inodesc *idesc, char *msg) { switch (idesc->id_fix) { case DONTKNOW: pwarn(msg); if (preen) { (void) printf(gettext(" (SALVAGED)\n")); idesc->id_fix = FIX; return (ALTERED); } if (reply(gettext("SALVAGE")) == 0) { idesc->id_fix = NOFIX; return (0); } idesc->id_fix = FIX; return (ALTERED); case FIX: return (ALTERED); case NOFIX: return (0); default: errexit(gettext("UNKNOWN INODESC FIX MODE %d\n"), idesc->id_fix); } /* NOTREACHED */ } /* * Check to see if unraw version of name is already mounted. * Since we do not believe /etc/mnttab, we stat the mount point * to see if it is really looks mounted. */ int mounted(char *name) { int found = 0; struct mnttab mnt; FILE *mnttab; struct stat device_stat, mount_stat; char *blkname, *unrawname(); int err; mnttab = fopen(MNTTAB, "r"); if (mnttab == NULL) { (void) printf(gettext("can't open %s\n"), MNTTAB); return (0); } blkname = unrawname(name); while ((getmntent(mnttab, &mnt)) == 0) { if (strcmp(mnt.mnt_fstype, MNTTYPE_UDFS) != 0) { continue; } if (strcmp(blkname, mnt.mnt_special) == 0) { err = stat(mnt.mnt_mountp, &mount_stat); err |= stat(mnt.mnt_special, &device_stat); if (err < 0) continue; if (device_stat.st_rdev == mount_stat.st_dev) { (void) strncpy(mnt.mnt_mountp, mountpoint, sizeof (mountpoint)); if (hasmntopt(&mnt, MNTOPT_RO) != 0) found = 2; /* mounted as RO */ else found = 1; /* mounted as R/W */ } break; } } (void) fclose(mnttab); return (found); } /* * Check to see if name corresponds to an entry in vfstab, and that the entry * does not have option ro. */ int writable(char *name) { int rw = 1; struct vfstab vfsbuf; FILE *vfstab; char *blkname, *unrawname(); vfstab = fopen(VFSTAB, "r"); if (vfstab == NULL) { (void) printf(gettext("can't open %s\n"), VFSTAB); return (1); } blkname = unrawname(name); if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) && (vfsbuf.vfs_fstype != NULL) && (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UDFS) == 0) && (hasvfsopt(&vfsbuf, MNTOPT_RO))) { rw = 0; } (void) fclose(vfstab); return (rw); } /* * print out clean info */ void printclean() { char *s; switch (lvintp->lvid_int_type) { case LVI_CLOSE: s = gettext("clean"); break; case LVI_OPEN: s = gettext("active"); break; default: s = gettext("unknown"); } if (preen) pwarn(gettext("is %s.\n"), s); else (void) printf("** %s is %s.\n", devname, s); } # # 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 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. # FSTYPE= udfs LIBPROG= fsdb include ../../Makefile.fstype # fsdb has a name clash with main() and libl.so.1. However, fsdb must # still export a number of "yy*" (libl) interfaces. Reduce all other symbols # to local scope. MAPFILES += $(MAPFILE.INT) $(MAPFILE.LEX) $(MAPFILE.NGB) MAPOPTS = $(MAPFILES:%=-Wl,-M%) CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 CPPFLAGS += -I../common LDLIBS += -lmalloc -ll -ladm LDFLAGS += $(MAPOPTS) YFLAGS = "-d" CERRWARN += -Wno-implicit-function-declaration CERRWARN += -Wno-unused-variable CERRWARN += -Wno-unused-value CERRWARN += -Wno-unused-function # Hammerhead: Suppress pointer/int cast warnings in legacy UDFS code CERRWARN += -Wno-pointer-to-int-cast CERRWARN += -Wno-int-to-pointer-cast # because of labels from yacc fsdb_yacc.o fsdb_lex.o : CERRWARN += -Wno-unused-label # not linted SMATCH=off SRCS= fsdb.c ../common/ud_lib.c fsdb : fsdb_yacc.o fsdb_lex.o ud_lib.o fsdb.o $(MAPFILES) $(LINK.c) -o $@ fsdb.o fsdb_yacc.o fsdb_lex.o \ ud_lib.o $(LDLIBS) $(POST_PROCESS) fsdb.o : fsdb.c $(COMPILE.c) -o $@ fsdb.c $(POST_PROCESS_O) ud_lib.o : ../common/ud_lib.c ../common/ud_lib.h $(COMPILE.c) -o $@ ../common/ud_lib.c $(POST_PROCESS_O) y.tab.c : fsdb_yacc.y $(YACC.y) fsdb_yacc.y fsdb_yacc.o : y.tab.c $(COMPILE.c) -o $@ y.tab.c $(POST_PROCESS_O) lex.yy.c : fsdb_lex.l $(LEX) -e fsdb_lex.l fsdb_lex.o : lex.yy.c $(COMPILE.c) -o $@ lex.yy.c $(POST_PROCESS_O) clean : $(RM) fsdb.o ud_lib.o fsdb_yacc.o fsdb_lex.o $(RM) fsdb_yacc.c fsdb_lex.c y.tab.c y.tab.h lex.yy.c # for messaging catalog # POFILE= fsdb.po # for messaging catalog # catalog: $(POFILE) CATSRCS= $(SRCS) lex.yy.c y.tab.c $(POFILE): $(CATSRCS) ../common/ud_lib.h $(RM) $@ $(COMPILE.cpp) $(CATSRCS) > $(POFILE).i $(XGETTEXT) $(XGETFLAGS) $(POFILE).i $(SED) "/^domain/d" messages.po > $@ $(RM) $(POFILE).i messages.po /* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ud_lib.h" #include "y.tab.h" typedef unsigned short unicode_t; #define MAXNAMLEN 0x200 extern uint32_t i_number; extern int32_t run_fsdb(); void usage(); void init_buffers(); char *getblk(u_offset_t); int32_t parse_udfs(uint32_t); int32_t parse_vds(uint32_t, uint32_t); int32_t parse_part(struct part_desc *); int32_t parse_lvd(struct log_vol_desc *); int32_t parse_fsds(); int32_t get_vat_loc(); int32_t get_fid(uint32_t, uint8_t *, uint64_t); char *progname; char prompt[256] = "fsdb>"; #define ARG_OVERRIDE 0 #define ARG_NEW_PROMPT 1 #define ARG_WR_ENABLED 2 #define ARG_USAGE 3 char *subopt_v[] = { "o", "p", "w", "?", NULL }; int32_t override = 0; int32_t openflg = O_RDONLY; #define MAX_PARTS 10 /* * udp_flags */ #define UDP_BITMAPS 0x00 #define UDP_SPACETBLS 0x01 ud_handle_t udh; int32_t fd, nparts, nmaps; int32_t bmask, l2d, l2b; uint16_t ricb_prn; uint32_t ricb_loc, ricb_len; extern int value; int32_t main(int argc, char *argv[]) { int opt, ret; uint32_t bsize; char *subopts, *optval; #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); progname = argv[0]; while ((opt = getopt(argc, argv, "o:")) != EOF) { switch (opt) { case 'o' : subopts = optarg; while (*subopts != '\0') { switch (getsubopt(&subopts, subopt_v, &optval)) { case ARG_OVERRIDE : override = 1; (void) fprintf(stdout, gettext("error checking off\n")); break; case ARG_NEW_PROMPT : if (optval == NULL) { usage(); } if (strlen(optval) > 255) { (void) fprintf(stdout, gettext("prompt should be less" "than 255 bytes\n")); exit(1); } (void) strcpy(prompt, optval); break; case ARG_WR_ENABLED : openflg = O_RDWR; break; case ARG_USAGE : default : usage(); } } break; default : usage(); } } if ((argc - optind) != 1) { /* Should just have "special" left */ usage(); } if (ud_init(-1, &udh) != 0) { (void) fprintf(stderr, gettext("udfs labelit: cannot initialize ud_lib\n")); exit(1); } if ((fd = ud_open_dev(udh, argv[optind], openflg)) < 0) { perror("open"); exit(1); } if ((ret = ud_fill_udfs_info(udh)) != 0) { return (ret); } if ((udh->udfs.flags & VALID_UDFS) == 0) { return (1); } bsize = udh->udfs.lbsize; bmask = bsize - 1; l2d = 0; while ((bsize >> l2d) > DEV_BSIZE) { l2d++; } l2b = l2d + 9; ricb_prn = udh->udfs.ricb_prn; ricb_loc = udh->udfs.ricb_loc; ricb_len = udh->udfs.ricb_len; value = i_number = ud_xlate_to_daddr(udh, ricb_prn, ricb_loc); init_buffers(); run_fsdb(); ud_fini(udh); (void) close(fd); return (0); } /* * usage - print usage and exit */ void usage() { (void) fprintf(stdout, gettext("usage: %s [options] special\n"), progname); (void) fprintf(stdout, gettext("options:\n")); (void) fprintf(stdout, gettext("\t-o\tSpecify udfs filesystem sepcific options\n")); (void) fprintf(stdout, gettext("\t\tAvailable suboptions are:\n")); (void) fprintf(stdout, gettext("\t\t?\tdisplay usage\n")); (void) fprintf(stdout, gettext("\t\to\toverride some error conditions\n")); (void) fprintf(stdout, gettext("\t\tp\t\"string\" set prompt to string\n")); (void) fprintf(stdout, gettext("\t\tw\topen for write\n")); exit(1); } #define NBUF 10 static struct lbuf { struct lbuf *fwd; struct lbuf *back; int32_t valid; char *blkaddr; u_offset_t blkno; } lbuf[NBUF], bhdr; #define INSERT(bp) \ { \ bp->back = &bhdr; \ bp->fwd = bhdr.fwd; \ bhdr.fwd->back = bp; \ bhdr.fwd = bp; \ } void init_buffers() { int32_t i; char *addr; struct lbuf *bp; addr = malloc(NBUF * udh->udfs.lbsize); bhdr.fwd = bhdr.back = &bhdr; for (i = 0; i < NBUF; i++) { bp = &lbuf[i]; bp->blkaddr = addr + i * udh->udfs.lbsize; bp->valid = 0; INSERT(bp); } } char * getblk(u_offset_t address) { u_offset_t off, block; struct lbuf *bp; off = address & ~bmask; block = address >> l2b; for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) { if (bp->valid && bp->blkno == block) { goto found; } } bp = bhdr.back; bp->blkno = block; bp->valid = 0; errno = 0; if (llseek(fd, off, SEEK_SET) != off) { (void) fprintf(stdout, gettext("Seek failed fd %x off %llx errno %x\n"), fd, off, errno); return (NULL); } errno = 0; if (read(fd, bp->blkaddr, udh->udfs.lbsize) != udh->udfs.lbsize) { (void) fprintf(stdout, gettext("Read failed fd %x off %llx errno %x\n"), fd, off, errno); return (NULL); } bp->valid = 1; found: bp->back->fwd = bp->fwd; bp->fwd->back = bp->back; INSERT(bp); return (bp->blkaddr); } int32_t putblk(caddr_t address) { u_offset_t off; struct lbuf *bp; if (openflg == O_RDONLY) { (void) fprintf(stdout, gettext("Not run with -w flag\n")); return (1); } for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) { if (bp->valid && bp->blkaddr == address) { goto found; } } (void) fprintf(stdout, gettext("Could not find the buffer\n")); return (1); found: off = bp->blkno << l2b; if (llseek(fd, off, SEEK_SET) == off) { if (write(fd, bp->blkaddr, udh->udfs.lbsize) == udh->udfs.lbsize) { return (0); } (void) fprintf(stdout, gettext("Write failed fd %x off %llx errno %x\n"), fd, off, errno); } else { (void) fprintf(stdout, gettext("Seek failed fd %x off %llx errno %x\n"), fd, off, errno); } return (1); } void inval_bufs() { struct lbuf *bp; for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) { bp->valid = 0; } } /* * If addr == NULL then use id to print the desc * other wise use addr to self identify the type of desc */ void print_desc(uint32_t addr, int32_t id) { struct tag *tag; caddr_t baddr; /* * Read the block at addr * find out the type of tag * and print the descriptor */ if (addr != 0) { if ((baddr = getblk(addr & (~bmask))) == NULL) { (void) fprintf(stdout, gettext("Could not read block %x\n"), addr >> l2b); } /* LINTED */ tag = (struct tag *)(baddr + (addr & bmask)); } else { switch (id) { case AVD : /* LINTED */ if ((tag = (struct tag *)getblk( udh->udfs.avdp_loc << l2b)) == NULL) { (void) fprintf(stdout, gettext("Could not read AVDP\n")); } break; case MVDS : case RVDS : case INTS : { uint32_t i, end; if (id == MVDS) { i = udh->udfs.mvds_loc; end = i + (udh->udfs.mvds_len >> l2b); } else if (id == RVDS) { i = udh->udfs.rvds_loc; end = i + (udh->udfs.rvds_len >> l2b); } else { i = udh->udfs.lvid_loc; end = i + (udh->udfs.lvid_len >> l2b); } for (; i < end; i++) { print_desc(i << l2b, 0); } } return; case FSDS : case ROOT : { uint16_t prn; uint32_t i, end, block; if (id == FSDS) { prn = udh->udfs.fsds_prn; i = udh->udfs.fsds_loc; end = i + (udh->udfs.fsds_len >> l2b); } else { prn = ricb_prn; i = ricb_loc; end = i + (ricb_len >> l2b); } for (; i < end; i++) { if ((block = ud_xlate_to_daddr( udh, prn, i)) == 0) { (void) fprintf(stdout, gettext("Cannot xlate " "prn %x loc %x\n"), prn, i); continue; } print_desc(block << l2b, 0); } } /* FALLTHROUGH */ default : return; } } switch (SWAP_16(tag->tag_id)) { case UD_PRI_VOL_DESC : print_pvd(stdout, (struct pri_vol_desc *)tag); break; case UD_ANCH_VOL_DESC : print_avd(stdout, (struct anch_vol_desc_ptr *)tag); break; case UD_VOL_DESC_PTR : print_vdp(stdout, (struct vol_desc_ptr *)tag); break; case UD_IMPL_USE_DESC : print_iuvd(stdout, (struct iuvd_desc *)tag); break; case UD_PART_DESC : print_part(stdout, (struct part_desc *)tag); break; case UD_LOG_VOL_DESC : print_lvd(stdout, (struct log_vol_desc *)tag); break; case UD_UNALL_SPA_DESC : print_usd(stdout, (struct unall_spc_desc *)tag); break; case UD_TERM_DESC : (void) fprintf(stdout, "TERM DESC\n"); print_tag(stdout, tag); break; case UD_LOG_VOL_INT : print_lvid(stdout, (struct log_vol_int_desc *)tag); break; case UD_FILE_SET_DESC : print_fsd(stdout, udh, (struct file_set_desc *)tag); break; case UD_FILE_ID_DESC : print_fid(stdout, (struct file_id *)tag); break; case UD_ALLOC_EXT_DESC : print_aed(stdout, (struct alloc_ext_desc *)tag); break; case UD_INDIRECT_ENT : print_ie(stdout, (struct indirect_entry *)tag); break; case UD_TERMINAL_ENT : print_td(stdout, (struct term_desc *)tag); break; case UD_FILE_ENTRY : print_fe(stdout, (struct file_entry *)tag); break; case UD_EXT_ATTR_HDR : case UD_UNALL_SPA_ENT : case UD_SPA_BMAP_DESC : case UD_PART_INT_DESC : case UD_EXT_FILE_ENT : break; default : (void) fprintf(stdout, gettext("unknown descriptor\n")); print_tag(stdout, tag); break; } } void set_file(int32_t id, uint32_t iloc, uint64_t value) { uint8_t i8; uint16_t i16; uint32_t i32, block, ea_len, ea_off; uint64_t i64; struct file_entry *fe; struct dev_spec_ear *ds; struct attr_hdr *ah; struct ext_attr_hdr *eah; /* LINTED */ if ((fe = (struct file_entry *)getblk(iloc)) == NULL) { return; } if (ud_verify_tag(udh, &fe->fe_tag, UD_FILE_ENTRY, SWAP_32(fe->fe_tag.tag_loc), 1, 1) != 0) { return; } i8 = (uint8_t)value; i16 = SWAP_16(((uint16_t)value)); i32 = SWAP_32(((uint32_t)value)); i64 = SWAP_64(value); switch (id) { case ATTZ : fe->fe_acc_time.ts_tzone = i16; break; case ATYE : fe->fe_acc_time.ts_year = i16; break; case ATMO : fe->fe_acc_time.ts_month = i8; break; case ATDA : fe->fe_acc_time.ts_day = i8; break; case ATHO : fe->fe_acc_time.ts_hour = i8; break; case ATMI : fe->fe_acc_time.ts_min = i8; break; case ATSE : fe->fe_acc_time.ts_sec = i8; break; case ATCE : fe->fe_acc_time.ts_csec = i8; break; case ATHU : fe->fe_acc_time.ts_husec = i8; break; case ATMIC : fe->fe_acc_time.ts_usec = i8; break; case CTTZ : fe->fe_attr_time.ts_tzone = i16; break; case CTYE : fe->fe_attr_time.ts_year = i16; break; case CTMO : fe->fe_attr_time.ts_month = i8; break; case CTDA : fe->fe_attr_time.ts_day = i8; break; case CTHO : fe->fe_attr_time.ts_hour = i8; break; case CTMI : fe->fe_attr_time.ts_min = i8; break; case CTSE : fe->fe_attr_time.ts_sec = i8; break; case CTCE : fe->fe_attr_time.ts_csec = i8; break; case CTHU : fe->fe_attr_time.ts_husec = i8; break; case CTMIC : fe->fe_attr_time.ts_usec = i8; break; case MTTZ : fe->fe_mod_time.ts_tzone = i16; break; case MTYE : fe->fe_mod_time.ts_year = i16; break; case MTMO : fe->fe_mod_time.ts_month = i8; break; case MTDA : fe->fe_mod_time.ts_day = i8; break; case MTHO : fe->fe_mod_time.ts_hour = i8; break; case MTMI : fe->fe_mod_time.ts_min = i8; break; case MTSE : fe->fe_mod_time.ts_sec = i8; break; case MTCE : fe->fe_mod_time.ts_csec = i8; break; case MTHU : fe->fe_mod_time.ts_husec = i8; break; case MTMIC : fe->fe_mod_time.ts_usec = i8; break; case GID : fe->fe_gid = i32; break; case LN : fe->fe_lcount = i16; break; case MD : fe->fe_perms = i32; break; case MAJ : case MIO : if ((fe->fe_icb_tag.itag_ftype != VBLK) && (fe->fe_icb_tag.itag_ftype != VCHR)) { (void) fprintf(stdout, gettext("Not a device\n")); break; } /* LINTED */ eah = (struct ext_attr_hdr *)fe->fe_spec; ea_off = SWAP_32(eah->eah_ial); ea_len = SWAP_32(fe->fe_len_ear); block = SWAP_32(eah->eah_tag.tag_loc); if (ea_len && (ud_verify_tag(udh, &eah->eah_tag, UD_EXT_ATTR_HDR, block, 1, 1) == 0)) { while (ea_off < ea_len) { /* LINTED */ ah = (struct attr_hdr *) &fe->fe_spec[ea_off]; if ((ah->ahdr_atype == SWAP_32(12)) && (ah->ahdr_astype == 1)) { ds = (struct dev_spec_ear *)ah; if (id == MAJ) { ds->ds_major_id = i32; } else { ds->ds_minor_id = i32; } ud_make_tag(udh, &eah->eah_tag, UD_EXT_ATTR_HDR, block, eah->eah_tag.tag_crc_len); break; } } } (void) fprintf(stdout, gettext("does not have a Device Specification EA\n")); break; case NM : break; case SZ : fe->fe_info_len = i64; break; case UID : fe->fe_uid = i32; break; case UNIQ : fe->fe_uniq_id = i32; break; default : (void) fprintf(stdout, gettext("Unknown set\n")); } ud_make_tag(udh, &fe->fe_tag, UD_FILE_ENTRY, SWAP_32(fe->fe_tag.tag_loc), fe->fe_tag.tag_crc_len); (void) putblk((caddr_t)fe); } caddr_t verify_inode(uint32_t addr, uint32_t type) { struct file_entry *fe; struct tag *tag; /* LINTED */ if ((tag = (struct tag *)getblk(addr & (~bmask))) == NULL) { (void) fprintf(stdout, gettext("Could not read block %x\n"), addr >> l2b); } else { if (ud_verify_tag(udh, tag, UD_FILE_ENTRY, addr >> l2b, 0, 1) != 0) { (void) fprintf(stdout, gettext("Not a file entry(inode) at %x\n"), addr >> l2b); } else { if (ud_verify_tag(udh, tag, UD_FILE_ENTRY, SWAP_32(tag->tag_loc), 1, 1) != 0) { (void) fprintf(stdout, gettext("CRC failed\n")); } else { fe = (struct file_entry *)tag; if ((type == 0) || (type == fe->fe_icb_tag.itag_ftype)) { return ((caddr_t)tag); } } } } return (0); } void print_inode(uint32_t addr) { if (verify_inode(addr, 0) != NULL) { print_desc(addr, 0); } } int32_t verify_dent(uint32_t i_addr, uint32_t nent) { uint32_t ent = 0; uint64_t off = 0; uint8_t buf[1024]; struct file_id *fid; /* LINTED */ fid = (struct file_id *)buf; if (verify_inode(i_addr, 4) == 0) { (void) fprintf(stdout, gettext("Inode is not a directory\n")); return (1); } while (get_fid(i_addr >> l2b, buf, off) == 0) { off += FID_LEN(fid); if (ent == nent) { return (0); } ent++; } (void) fprintf(stdout, gettext("Reached EOF\n")); return (1); } void print_dent(uint32_t i_addr, uint32_t nent) { uint32_t ent = 0; uint64_t off = 0; uint8_t buf[1024]; struct file_id *fid; /* LINTED */ fid = (struct file_id *)buf; if (verify_dent(i_addr, nent) == 0) { while (get_fid(i_addr >> l2b, buf, off) == 0) { off += FID_LEN(fid); if (ent == nent) { print_fid(stdout, fid); return; } ent++; } } } uint32_t in; uint32_t de_count, ie_count; struct ext { uint16_t prn; uint16_t flags; uint32_t blkno; uint32_t len; } *de, *ie; int32_t get_blkno(uint32_t inode, uint32_t *blkno, uint64_t off) { struct file_entry *fe; int32_t i, d, nent; uint16_t prn, flags, elen; uint32_t desc_type, bno, len; struct short_ad *sad; struct long_ad *lad; uint64_t b_off, e_off; if (inode != in) { /* LINTED */ if ((fe = (struct file_entry *) getblk(inode << l2b)) == NULL) { (void) fprintf(stdout, gettext("Could not read block %x\n"), off & (~bmask)); return (1); } desc_type = SWAP_16(fe->fe_icb_tag.itag_flags) & 0x7; sad = NULL; lad = NULL; if (desc_type == ICB_FLAG_SHORT_AD) { elen = sizeof (struct short_ad); /* LINTED */ sad = (struct short_ad *) (fe->fe_spec + SWAP_32(fe->fe_len_ear)); } else if (desc_type == ICB_FLAG_LONG_AD) { elen = sizeof (struct long_ad); /* LINTED */ lad = (struct long_ad *) (fe->fe_spec + SWAP_32(fe->fe_len_ear)); } else if (desc_type == ICB_FLAG_ONE_AD) { *blkno = inode; return (0); } else { /* This cannot happen return */ return (EINVAL); } nent = SWAP_32(fe->fe_len_adesc) / elen; de = malloc(nent * sizeof (struct ext)); if (de == NULL) { (void) fprintf(stdout, gettext("could not allocate memeory\n")); return (1); } in = inode; de_count = nent; for (d = 0, i = 0; i < nent; i++) { switch (desc_type) { case ICB_FLAG_SHORT_AD: prn = 0; bno = SWAP_32(sad->sad_ext_loc); len = SWAP_32(sad->sad_ext_len); break; case ICB_FLAG_LONG_AD: prn = SWAP_16(lad->lad_ext_prn); bno = SWAP_32(lad->lad_ext_loc); len = SWAP_32(lad->lad_ext_len); break; default: prn = 0; bno = 0; len = 0; } flags = len >> 30; if (flags == 0x3) { (void) fprintf(stdout, gettext("Handle IE\n")); } else { de[d].prn = prn; de[d].flags = flags; de[d].blkno = bno; de[d].len = len & 0x3FFFFFFF; d++; } } } b_off = 0; for (i = 0; i < de_count; i++) { e_off = b_off + de[i].len; if (off < e_off) { bno = de[i].blkno + ((off - b_off) >> l2b); if ((*blkno = ud_xlate_to_daddr( udh, de[i].prn, bno)) == 0) { return (1); } return (0); } b_off = e_off; } return (1); } /* * assume the buffer is big enough * for the entire request */ int32_t read_file(uint32_t inode, uint8_t *buf, uint32_t count, uint64_t off) { caddr_t addr; uint32_t bno, tcount; while (count) { if (get_blkno(inode, &bno, off) != 0) { return (1); } if ((addr = getblk(bno << l2b)) == NULL) { return (1); } if (bno == inode) { struct file_entry *fe; /* * embedded file */ /* LINTED */ fe = (struct file_entry *)addr; addr += 0xB0 + SWAP_32(fe->fe_len_ear); if (off >= SWAP_64(fe->fe_info_len)) { return (1); } } tcount = udh->udfs.lbsize - (off & bmask); if (tcount > count) { tcount = count; } addr += off & bmask; (void) memcpy(buf, addr, tcount); count -= tcount; buf += tcount; off += tcount; } return (0); } int32_t get_fid(uint32_t inode, uint8_t *buf, uint64_t off) { struct file_id *fid; /* LINTED */ fid = (struct file_id *)buf; if ((read_file(inode, buf, sizeof (struct file_id), off)) != 0) { return (1); } if (ud_verify_tag(udh, &fid->fid_tag, UD_FILE_ID_DESC, 0, 0, 1) != 0) { (void) fprintf(stdout, gettext("file_id tag does not verify off %llx\n"), off); return (1); } if ((read_file(inode, buf, FID_LEN(fid), off)) != 0) { return (1); } return (0); } /* * Path is absolute path */ int32_t inode_from_path(char *path, uint32_t *in, uint8_t *fl) { char dname[1024]; char fname[256]; int32_t err; uint32_t dinode; struct tag *tag; uint8_t flags; uint8_t buf[1024]; uint64_t off; struct file_id *fid; uint8_t *addr; if (strcmp(path, "/") == 0) { *fl = FID_DIR; if ((*in = ud_xlate_to_daddr(udh, ricb_prn, ricb_loc)) == 0) { return (1); } return (0); } (void) strcpy(dname, path); (void) strcpy(fname, basename(dname)); (void) dirname(dname); if ((err = inode_from_path(dname, &dinode, &flags)) != 0) { return (1); } /* * Check if dname is a directory */ if ((flags & FID_DIR) == 0) { (void) fprintf(stdout, gettext("Path %s is not a directory\n"), path); } /* * Search for the fname in the directory now */ off = 0; /* LINTED */ fid = (struct file_id *)buf; while (get_fid(dinode, buf, off) == 0) { off += FID_LEN(fid); if (fid->fid_flags & FID_DELETED) { continue; } addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1]; if (fid->fid_flags & FID_PARENT) { addr[0] = '.'; addr[1] = '.'; addr[2] = '\0'; } else { addr[fid->fid_idlen] = '\0'; } if (strcmp((caddr_t)addr, fname) == 0) { *fl = fid->fid_flags; if ((*in = ud_xlate_to_daddr(udh, SWAP_16(fid->fid_icb.lad_ext_prn), SWAP_32(fid->fid_icb.lad_ext_loc))) == 0) { return (1); } /* LINTED */ if ((tag = (struct tag *)getblk(*in << l2b)) == NULL) { (void) fprintf(stdout, gettext("Could not read block %x\n"), *in); return (1); } if (ud_verify_tag(udh, tag, UD_FILE_ENTRY, 0, 0, 1) != 0) { (void) fprintf(stdout, gettext("Not a file entry(inode)" " at %x\n"), *in); return (1); } if (ud_verify_tag(udh, tag, UD_FILE_ENTRY, SWAP_32(tag->tag_loc), 1, 1) != 0) { (void) fprintf(stdout, gettext("CRC failed\n")); return (1); } return (0); } } return (err); } struct recu_dir { struct recu_dir *next; uint32_t inode; char *nm; }; void list(char *nm, uint32_t in, uint32_t fl) { uint8_t buf[1024]; uint64_t off; struct file_id *fid; struct recu_dir *rd, *erd, *temp; uint32_t iloc; rd = erd = temp = NULL; if (verify_inode(in << l2b, 4) == 0) { (void) fprintf(stdout, gettext("Inode is not a directory\n")); return; } if (fl & 2) { (void) printf("\n"); if (fl & 1) { (void) fprintf(stdout, gettext("i#: %x\t"), in); } (void) printf("%s\n", nm); } off = 0; /* LINTED */ fid = (struct file_id *)buf; while (get_fid(in, buf, off) == 0) { off += FID_LEN(fid); if (fid->fid_flags & FID_DELETED) { continue; } iloc = ud_xlate_to_daddr(udh, SWAP_16(fid->fid_icb.lad_ext_prn), SWAP_32(fid->fid_icb.lad_ext_loc)); if (fl & 1) { (void) fprintf(stdout, gettext("i#: %x\t"), iloc); } if (fid->fid_flags & FID_PARENT) { (void) fprintf(stdout, gettext("..\n")); } else { int32_t i; uint8_t *addr; addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1]; for (i = 0; i < fid->fid_idlen - 1; i++) (void) fprintf(stdout, "%c", addr[i]); (void) fprintf(stdout, "\n"); if ((fid->fid_flags & FID_DIR) && (fl & 2)) { temp = (struct recu_dir *) malloc(sizeof (struct recu_dir)); if (temp == NULL) { (void) fprintf(stdout, gettext("Could not allocate memory\n")); } else { temp->next = NULL; temp->inode = iloc; temp->nm = malloc(strlen(nm) + 1 + fid->fid_idlen + 1); if (temp->nm != NULL) { (void) strcpy(temp->nm, nm); (void) strcat(temp->nm, "/"); (void) strncat(temp->nm, (char *)addr, fid->fid_idlen); } if (rd == NULL) { erd = rd = temp; } else { erd->next = temp; erd = temp; } } } } } while (rd != NULL) { if (rd->nm != NULL) { list(rd->nm, rd->inode, fl); } else { list(".", rd->inode, fl); } temp = rd; rd = rd->next; if (temp->nm) { free(temp->nm); } free(temp); } } void fill_pattern(uint32_t addr, uint32_t count, char *pattern) { uint32_t beg, end, soff, lcount; int32_t len = strlen(pattern); caddr_t buf, p; if (openflg == O_RDONLY) { (void) fprintf(stdout, gettext("Not run with -w flag\n")); return; } if (count == 0) { count = 1; } beg = addr; end = addr + count * len; soff = beg & (~bmask); lcount = ((end + bmask) & (~bmask)) - soff; inval_bufs(); buf = malloc(lcount); if (llseek(fd, soff, SEEK_SET) != soff) { (void) fprintf(stdout, gettext("Seek failed fd %x off %llx errno %x\n"), fd, soff, errno); goto end; } if (read(fd, buf, lcount) != lcount) { (void) fprintf(stdout, gettext("Read failed fd %x off %llx errno %x\n"), fd, soff, errno); goto end; } p = buf + (addr & bmask); while (count--) { (void) strncpy(p, pattern, len); p += len; } if (write(fd, buf, lcount) != lcount) { (void) fprintf(stdout, gettext("Write failed fd %x off %llx errno %x\n"), fd, soff, errno); goto end; } end: free(buf); } void dump_disk(uint32_t addr, uint32_t count, char *format) { uint32_t beg, end, soff, lcount; int32_t len, prperline, n; uint8_t *buf, *p; uint16_t *p_16; uint32_t *p_32; if (strlen(format) != 1) { (void) fprintf(stdout, gettext("Invalid command\n")); return; } if (count == 0) { count = 1; } switch (*format) { case 'b' : /* FALLTHROUGH */ case 'c' : /* FALLTHROUGH */ case 'd' : /* FALLTHROUGH */ case 'o' : len = 1; prperline = 16; break; case 'x' : len = 2; prperline = 8; break; case 'D' : /* FALLTHROUGH */ case 'O' : /* FALLTHROUGH */ case 'X' : len = 4; prperline = 4; break; default : (void) fprintf(stdout, gettext("Invalid format\n")); return; } beg = addr; end = addr + count * len; soff = beg & (~bmask); lcount = ((end + bmask) & (~bmask)) - soff; inval_bufs(); buf = malloc(lcount); if (llseek(fd, soff, SEEK_SET) != soff) { (void) fprintf(stdout, gettext("Seek failed fd %x off %llx errno %x\n"), fd, soff, errno); goto end; } if (read(fd, buf, lcount) != lcount) { (void) fprintf(stdout, gettext("Read failed fd %x off %llx errno %x\n"), fd, soff, errno); goto end; } p = buf + (addr & bmask); /* LINTED */ p_16 = (uint16_t *)p; /* LINTED */ p_32 = (uint32_t *)p; n = 0; while (n < count) { switch (*format) { case 'b' : (void) fprintf(stdout, "%4x ", *((uint8_t *)p)); break; case 'c' : (void) fprintf(stdout, "%4c ", *((uint8_t *)p)); break; case 'd' : (void) fprintf(stdout, "%4d ", *((uint8_t *)p)); break; case 'o' : (void) fprintf(stdout, "%4o ", *((uint8_t *)p)); break; case 'x' : (void) fprintf(stdout, "%8x ", *p_16); break; case 'D' : (void) fprintf(stdout, "%16d ", *p_32); break; case 'O' : (void) fprintf(stdout, "%16o ", *p_32); break; case 'X' : (void) fprintf(stdout, "%16x ", *p_32); break; } p += len; n++; if ((n % prperline) == 0) { (void) fprintf(stdout, "\n"); } } if (n % prperline) { (void) fprintf(stdout, "\n"); } end: free(buf); } void find_it(char *dir, char *name, uint32_t in, uint32_t fl) { uint8_t buf[1024], *addr; uint64_t off; struct file_id *fid; uint32_t iloc, d_in; uint8_t d_fl; struct recu_dir *rd, *erd, *temp; rd = erd = temp = NULL; if (inode_from_path(dir, &d_in, &d_fl) != 0) { (void) fprintf(stdout, gettext("Could not find directory %s"), dir); return; } if ((d_fl & FID_DIR) == 0) { (void) fprintf(stdout, gettext("Path %s is not a directory\n"), dir); return; } if (verify_inode(d_in << l2b, 4) == 0) { (void) fprintf(stdout, gettext("Inode is not a directory\n")); return; } off = 0; /* LINTED */ fid = (struct file_id *)buf; while (get_fid(d_in, buf, off) == 0) { off += FID_LEN(fid); if ((fid->fid_flags & FID_DELETED) || (fid->fid_flags & FID_PARENT)) { continue; } iloc = ud_xlate_to_daddr(udh, SWAP_16(fid->fid_icb.lad_ext_prn), SWAP_32(fid->fid_icb.lad_ext_loc)); addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1]; if (((fl & 4) && (in == iloc)) || ((fl & 2) && (strcmp(name, (char *)addr) == 0))) { (void) printf("%s %x %s\n", dir, iloc, addr); } if (fid->fid_flags & FID_DIR) { temp = (struct recu_dir *) malloc(sizeof (struct recu_dir)); if (temp == NULL) { (void) fprintf(stdout, gettext("Could not allocate memory\n")); } else { temp->next = NULL; temp->inode = iloc; temp->nm = malloc(strlen(dir) + 1 + fid->fid_idlen + 1); if (temp->nm != NULL) { (void) strcpy(temp->nm, dir); (void) strcat(temp->nm, "/"); (void) strncat(temp->nm, (char *)addr, fid->fid_idlen); } else { (void) fprintf(stdout, gettext( "Could not allocate memory\n")); } if (rd == NULL) { erd = rd = temp; } else { erd->next = temp; erd = temp; } } } } while (rd != NULL) { if (rd->nm != NULL) { find_it(rd->nm, name, in, fl); } temp = rd; rd = rd->next; if (temp->nm) { free(temp->nm); } free(temp); } } %{ /* * 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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "y.tab.h" extern int base; int cmd_no = 1; %} %e 2000 WS [ \t] %% \n { cmd_no++; return NL; } \. { return DOT; } ;{WS}*:{WS}*base{WS}* { return BASE; } ^{WS}*:{WS}*base{WS}* { return BASE; } {WS}*:{WS}*block{WS}* { return BLOCK; } ;{WS}*:{WS}*cd { return CD; } ^{WS}*:{WS}*cd { return CD; } :{WS}*directory{WS}* { return DIRECTORY; } :{WS}*file{WS}* { return TFILE; } ;{WS}*:{WS}*find{WS}* { return FIND; } ^{WS}*:{WS}*find{WS}* { return FIND; } {WS}*:{WS}*fill{WS}* { return FILL; } :{WS}*inode{WS}* { return INODE; } ;{WS}*:{WS}*ls { return LS; } ^{WS}*:{WS}*ls { return LS; } ;{WS}*:{WS}*override{WS}* { return OVERRIDE; } ^{WS}*:{WS}*override{WS}* { return OVERRIDE; } ;{WS}*:{WS}*prompt{WS}* { return PROMPT; } ^{WS}*:{WS}*prompt{WS}* { return PROMPT; } ;{WS}*:{WS}*pwd{WS}* { return PWD; } ^{WS}*:{WS}*pwd{WS}* { return PWD; } ;{WS}*:{WS}*quit{WS}* { return QUIT; } ^{WS}*:{WS}*quit{WS}* { return QUIT; } :{WS}*tag{WS}* { return TAG; } ;{WS}*:{WS}*!{WS}* { return BANG; } ^{WS}*:{WS}*!{WS}* { return BANG; } :{WS}*avd { return AVD; } :{WS}*mvds { return MVDS; } :{WS}*rvds { return RVDS; } :{WS}*ints { return INTS; } :{WS}*fsds { return FSDS; } :{WS}*root { return ROOT; } :{WS}*attz { return ATTZ; } :{WS}*atye { return ATYE; } :{WS}*atmo { return ATMO; } :{WS}*atda { return ATDA; } :{WS}*atho { return ATHO; } :{WS}*atmi { return ATMI; } :{WS}*atse { return ATSE; } :{WS}*atce { return ATCE; } :{WS}*athu { return ATHU; } :{WS}*atmic { return ATMIC; } :{WS}*cttz { return CTTZ; } :{WS}*ctye { return CTYE; } :{WS}*ctmo { return CTMO; } :{WS}*ctda { return CTDA; } :{WS}*ctho { return CTHO; } :{WS}*ctmi { return CTMI; } :{WS}*ccte { return CTSE; } :{WS}*ctce { return CTCE; } :{WS}*cthu { return CTHU; } :{WS}*ctmic { return CTMIC; } :{WS}*mttz { return MTTZ; } :{WS}*mtye { return MTYE; } :{WS}*mtmo { return MTMO; } :{WS}*mtda { return MTDA; } :{WS}*mtho { return MTHO; } :{WS}*mtmi { return MTMI; } :{WS}*mtse { return MTSE; } :{WS}*mtce { return MTCE; } :{WS}*mthu { return MTHU; } :{WS}*mtmic { return MTMIC; } :{WS}*gid { return GID; } :{WS}*ln { return LN; } :{WS}*md { return MD; } :{WS}*maj { return MAJ; } :{WS}*min { return MIO; } :{WS}*nm { return NM; } :{WS}*sz { return SZ; } :{WS}*uid { return UID; } :{WS}*uniq { return UNIQ; } [-0-9a-zA-Z._]+ { yylval.strval = yytext; return WORD; } . { return yytext[0]; } %% void yyerror() { fprintf(stderr, gettext("Syntax error line : %d token : %s \n"), cmd_no, yytext); } /* :{WS}*fsds { return FSDS; } :{WS}*root { return ROOT; } */ %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 (c) 1999-2000 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include char shell_name[128] = "/bin/sh"; extern char prompt[]; extern uint16_t ricb_prn; extern uint32_t ricb_loc; extern int32_t bsize, bmask, l2d, l2b; int base = 16; int old_value = 0; int value = 0; int count = 0; int last_op_type = 0; #define TYPE_NONE 0 #define TYPE_INODE 1 #define TYPE_DIRENT 2 #define TYPE_BLOCK 3 #define TYPE_CD 4 uint32_t i_number = 0; uint32_t d_entry = 0; int error_override = 0; int register_array[256]; char cwd[MAXPATHLEN] = "/"; int32_t ls_flags; #define LONG_LIST 0x1 #define RECU_LIST 0x2 #define LIST_LS 0x4 int32_t find_flags; #define FIND_DIR 0x1 #define FIND_NAME 0x2 #define FIND_INODE 0x4 #define FIND_DONE 0x8 char find_dir[1024]; char find_name[1024]; uint32_t find_in; %} %union { uint8_t *strval; uint64_t intval; }; %token BASE BLOCK CD DIRECTORY TFILE FIND FILL %token INODE LS OVERRIDE PROMPT PWD QUIT TAG BANG %token AVD MVDS RVDS INTS FSDS ROOT %token ATTZ ATYE ATMO ATDA ATHO ATMI ATSE ATCE ATHU ATMIC %token CTTZ CTYE CTMO CTDA CTHO CTMI CTSE CTCE CTHU CTMIC %token MTTZ MTYE MTMO MTDA MTHO MTMI MTSE MTCE MTHU MTMIC %token GID LN MD MAJ MIO NM SZ UID UNIQ %token DOT %token NL %token WORD %left '-' '+' %left '*' '%' %type WORD %type expr %% session : statement_list statement_list : /* empty */ { print_prompt(); } | statement_list statement { ls_flags = 0; } ; statement : empty_statement | current_value | register | base | block | cd | directory | file | find | fill | inode | ls | override | nprompt | pwd | quit | tag | shell | avd | mvds | rvds | ints | fsds | root | at | ct | gid | ln | mt | md | maj | min | nm | sz | uid | uniq | dump | texpr | error { yyclearin; yyerrok; } ; empty_statement : NL { print_prompt(); } ; current_value : DOT { if (last_op_type == TYPE_INODE) { print_inode(i_number << l2b); } else if (last_op_type == TYPE_DIRENT) { print_dent(i_number << l2b, d_entry); } else { fprintf(stdout, gettext("%x\n"), value); } } ; register : '<' WORD { if ((strlen((caddr_t)$2) == 1) && ((($2[0] >= 'a') && ($2[0] <= 'z')) || (($2[0] >= 'A') && ($2[0] <= 'Z')))) { value = register_array[$2[0]]; } else { fprintf(stdout, gettext("Registers can" " be only a-z or A-Z\n")); } } | '>' WORD { if ((strlen((caddr_t)$2) == 1) && ((($2[0] >= 'a') && ($2[0] <= 'z')) || (($2[0] >= 'A') && ($2[0] <= 'Z')))) { register_array[$2[0]] = value; } else { fprintf(stdout, gettext("Registers can" " be only a-z or A-Z\n")); } } ; base : BASE '=' expr { if (($3 == 8) || ($3 == 10) || ($3 == 16)) { base = $3; } else { fprintf(stdout, gettext("Requested %x Only" " Oct, Dec and" " Hex are Supported\n"), $3); } } | BASE { fprintf(stdout, gettext("Current Base in Decimal" " : %d\n"), base); } ; block : BLOCK { last_op_type = TYPE_NONE; value = value * DEV_BSIZE; } ; cd : CD ' ' WORD { uint8_t fl; uint32_t temp; char temp_cwd[MAXPATHLEN]; strcpy(temp_cwd, cwd); if (strcmp((caddr_t)$3, "..") == 0) { if (strlen(temp_cwd) == 1) { if (temp_cwd[0] != '/') { fprintf(stdout, gettext("cwd is invalid" "setting to /\n")); strcpy(temp_cwd, "/"); } } else { dirname(temp_cwd); } } else { int32_t len; len = strlen(temp_cwd); if (temp_cwd[len - 1] != '/') { temp_cwd[len] = '/'; temp_cwd[len + 1] = '\0'; } strcat(temp_cwd, (caddr_t)$3); } if (inode_from_path(temp_cwd, &temp, &fl) != 0) { fprintf(stdout, gettext("Could not locate inode" " for path %s\n"), temp_cwd); strcpy(temp_cwd, "/"); if ((temp = ud_xlate_to_daddr(ricb_prn, ricb_loc)) == 0) { fprintf(stdout, gettext("Failed to translate" " prn %x loc %x\n"), ricb_prn, ricb_loc); } } else { if ((fl & FID_DIR) == 0) { fprintf(stdout, gettext("%s is not a" " directory\n"), temp_cwd); } else { strcpy(cwd, temp_cwd); value = temp << l2b; last_op_type = TYPE_CD; i_number = temp; } } } | CD { uint32_t block; (void) strcpy(cwd, "/"); /* * set current value to root icb */ if ((block = ud_xlate_to_daddr(ricb_prn, ricb_loc)) == 0) { fprintf(stdout, gettext("Failed to translate " "prn %x loc %x\n"), ricb_prn, ricb_loc); } else { value = block << l2b; last_op_type = TYPE_CD; i_number = block; } } ; directory : DIRECTORY { if (verify_dent(i_number << l2b, value) == 0) { last_op_type = TYPE_DIRENT; d_entry = value; } } ; file : TFILE { } ; find : xfind { if ((find_flags & (FIND_NAME | FIND_INODE)) && (find_flags & FIND_DONE)) { if (find_dir[0] != '/') { char buf[1024]; strcpy(buf, find_dir); if ((strlen(cwd) == 1) && (cwd[0] == '/')) { strcpy(find_dir, "/"); } else { strcpy(find_dir, cwd); strcat(find_dir, "/"); } strcat(find_dir, buf); } find_it(find_dir, find_name, find_in, (find_flags & (FIND_NAME | FIND_INODE))); } find_flags = 0; find_dir[0] = '\0'; find_name[0] = '\0'; find_in = 0; } ; xfind : FIND WORD { strcpy(find_dir, (char *)$2); find_flags = FIND_DIR; } | xfind ' ' WORD { if (find_flags == FIND_DIR) { if (strcmp((char *)$3, "-name") == 0) { find_flags = FIND_NAME; } else if (strcmp((char *)$3, "-inum") == 0) { find_flags = FIND_INODE; } else { fprintf(stdout, gettext("find dir-name {-name n | -inum n}\n")); } } else if (find_flags == FIND_NAME) { strcpy(find_name, (char *)$3); find_flags |= FIND_DONE; } else if (find_flags == FIND_INODE) { uint64_t temp; if (check_and_get_int($3, &temp) == 0) { find_in = temp; find_flags |= FIND_DONE; } else { fprintf(stdout, gettext("find dir-name {-name n | -inum n}\n")); } } else { fprintf(stdout, gettext("find dir-name {-name n | -inum n}\n")); } } | xfind ' ' expr { if (find_flags == FIND_INODE) { find_in = $3; find_flags |= FIND_DONE; } else { fprintf(stdout, gettext("find dir-name {-name n | -inum n}\n")); } } ; fill : FILL '=' WORD { fill_pattern(value, count, $3); } ; inode : INODE { uint32_t temp; if (last_op_type == TYPE_CD) { temp = value; } else { temp = value << l2b; } last_op_type = TYPE_INODE; if (verify_inode(temp, 0) != 0) { i_number = temp >> l2b; d_entry = 0; } } ; ls : xls { if (ls_flags & LIST_LS) { list(".", i_number, ls_flags); } } ; xls : LS { /* Do nothing */ ls_flags = LIST_LS; } | xls ' ' WORD { if (strcmp((caddr_t)$3, "-l") == 0) { ls_flags |= LONG_LIST; } else if (strcmp((caddr_t)$3, "-R") == 0) { ls_flags |= RECU_LIST; } else if ((strcmp((caddr_t)$3, "-lR") == 0) || (strcmp((caddr_t)$3, "-Rl") == 0)) { ls_flags |= LONG_LIST | RECU_LIST; } else { list(".", i_number, ls_flags); ls_flags &= ~LIST_LS; } } ; override : OVERRIDE { if (error_override == 0) { error_override = 1; (void) fprintf(stdout, gettext("error checking on\n")); } else { error_override = 0; (void) fprintf(stdout, gettext("error checking off\n")); } } ; nprompt : PROMPT '=' WORD { (void) strcpy(prompt, (caddr_t)$3); } ; pwd : PWD { fprintf(stdout, gettext("%s\n"), cwd); } ; quit : QUIT { exit (0); } ; tag : TAG { print_desc(value, 0); } ; shell : BANG { system(shell_name); } ; avd : AVD { print_desc(NULL, AVD); } ; mvds : MVDS { print_desc(NULL, MVDS); } ; rvds : RVDS { print_desc(NULL, RVDS); } ; ints : INTS { print_desc(NULL, INTS); } ; fsds : FSDS { print_desc(NULL, FSDS); } ; root : ROOT { print_desc(NULL, ROOT); } ; at : ATTZ '=' expr { set_file(ATTZ, i_number << l2b, $3); } | ATYE '=' expr { set_file(ATYE, i_number << l2b, $3); } | ATMO '=' expr { set_file(ATMO, i_number << l2b, $3); } | ATDA '=' expr { set_file(ATDA, i_number << l2b, $3); } | ATHO '=' expr { set_file(ATHO, i_number << l2b, $3); } | ATMI '=' expr { set_file(ATMI, i_number << l2b, $3); } | ATSE '=' expr { set_file(ATSE, i_number << l2b, $3); } | ATCE '=' expr { set_file(ATCE, i_number << l2b, $3); } | ATHU '=' expr { set_file(ATHU, i_number << l2b, $3); } | ATMIC '=' expr { set_file(ATMIC, i_number << l2b, $3); } ; ct : CTTZ '=' expr { set_file(CTTZ, i_number << l2b, $3); } | CTYE '=' expr { set_file(CTYE, i_number << l2b, $3); } | CTMO '=' expr { set_file(CTMO, i_number << l2b, $3); } | CTDA '=' expr { set_file(CTDA, i_number << l2b, $3); } | CTHO '=' expr { set_file(CTHO, i_number << l2b, $3); } | CTMI '=' expr { set_file(CTMI, i_number << l2b, $3); } | CTSE '=' expr { set_file(CTSE, i_number << l2b, $3); } | CTCE '=' expr { set_file(CTCE, i_number << l2b, $3); } | CTHU '=' expr { set_file(CTHU, i_number << l2b, $3); } | CTMIC '=' expr { set_file(CTMIC, i_number << l2b, $3); } ; mt : MTTZ '=' expr { set_file(MTTZ, i_number << l2b, $3); } | MTYE '=' expr { set_file(MTYE, i_number << l2b, $3); } | MTMO '=' expr { set_file(MTMO, i_number << l2b, $3); } | MTDA '=' expr { set_file(MTDA, i_number << l2b, $3); } | MTHO '=' expr { set_file(MTHO, i_number << l2b, $3); } | MTMI '=' expr { set_file(MTMI, i_number << l2b, $3); } | MTSE '=' expr { set_file(MTSE, i_number << l2b, $3); } | MTCE '=' expr { set_file(MTCE, i_number << l2b, $3); } | MTHU '=' expr { set_file(MTHU, i_number << l2b, $3); } | MTMIC '=' expr { set_file(MTMIC, i_number << l2b, $3); } ; gid : GID '=' expr { set_file(GID, i_number << l2b, $3); } ; ln : LN '=' expr { set_file(LN, i_number << l2b, $3); } ; md : MD '=' expr { set_file(MD, i_number << l2b, $3); } ; maj : MAJ '=' expr { set_file(MAJ, i_number << l2b, $3); } ; min : MIO '=' expr { set_file(MIO, i_number << l2b, $3); } ; nm : NM '=' expr { set_file(NM, i_number << l2b, $3); } ; sz : SZ '=' expr { set_file(SZ, i_number << l2b, $3); } ; uid : UID '=' expr { set_file(UID, i_number << l2b, $3); } ; uniq : UNIQ '=' expr { set_file(UNIQ, i_number << l2b, $3); } ; dump : '/' WORD { if (strlen((char *)$2) != 1) { fprintf(stdout, gettext("Invalid command\n")); } else { dump_disk(value, count, $2); } } | '?' WORD { if (strcmp((char *)$2, "i") == 0) { if (verify_inode(value << l2b, 0) != 0) { print_inode(value << l2b); i_number = value; last_op_type == TYPE_INODE; } } else if (strcmp((char *)$2, "d") == 0) { if (verify_dent(i_number << l2b, value) == 0) { print_dent(i_number << l2b, value); d_entry = value; last_op_type == TYPE_DIRENT; } } else { fprintf(stdout, gettext("Invalid command\n")); } } ; texpr : expr { value = $1; count = 0; } | expr ',' expr { value = $1; count = $3; } ; expr : '+' { if (last_op_type == TYPE_INODE) { if (verify_inode((i_number + 1) << l2b, 0) != 0) { i_number ++; print_inode(i_number << l2b); $$ = i_number << l2b; } } else if (last_op_type == TYPE_DIRENT) { if (verify_dent(i_number << l2b, d_entry + 1) == 0) { d_entry ++; print_dent(i_number << l2b, d_entry); } } else { count = 0; $$ = value++; } } | '-' { if (last_op_type == TYPE_INODE) { if (verify_inode((i_number - 1) << l2b, 0) != 0) { i_number --; print_inode(i_number << l2b); $$ = i_number << l2b; } } else if (last_op_type == TYPE_DIRENT) { if (verify_dent(i_number << l2b, d_entry - 1) == 0) { d_entry --; print_dent(i_number << l2b, d_entry); } } else { count = 0; $$ = value--; } } | '-' WORD { uint64_t number; if (check_and_get_int($2, &number) == 0) { count = 0; $$ = value - number; } } | '+' WORD { uint64_t number; if (check_and_get_int($2, &number) == 0) { count = 0; $$ = value + number; } } | '*' WORD { uint64_t number; if (check_and_get_int($2, &number) == 0) { count = 0; $$ = value * number; } } | '%' WORD { uint64_t number; if (check_and_get_int($2, &number) == 0) { if (number == 0) { fprintf(stdout, gettext("Divide by zero ?\n")); } else { count = 0; $$ = value / number; } } } | expr '-' expr { count = 0; $$ = $1 - $3; } | expr '+' expr { count = 0; $$ = $1 + $3; } | expr '*' expr { count = 0; $$ = $1 * $3; } | expr '%' expr { if ($3 == 0) { fprintf(stdout, gettext("Divide by zero ?\n")); } else { $$ = $1 / $3; } count = 0; } | WORD { uint64_t number; count = 0; if (check_and_get_int($1, &number) == 0) { $$ = number; } } ; %% int32_t check_and_get_int(uint8_t *str, uint64_t *value) { int32_t length, cbase, index, cvalue; *value = 0; length = strlen((caddr_t)str); /* * Decide on what base to be used * and strip off the base specifier */ if ((str[0] == '0') && (str[1] == 'x')) { cbase = 0x10; index = 2; } else if ((str[0] == '0') && (str[1] == 't')) { cbase = 0xa; index = 2; } else if (str[0] == '0') { cbase = 0x8; index = 1; } else { cbase = base; index = 0; } /* * Verify if the string is integer * and convert to a binary value */ for ( ; index < length; index++) { if (cbase == 0x8) { if ((str[index] < '0') || (str[index] > '7')) { fprintf(stdout, gettext("Invalid Octal Number %s\n"), str); return (1); } cvalue = str[index] - '0'; } else if (cbase == 0xa) { if ((str[index] < '0') || (str[index] > '9' )) { fprintf(stdout, gettext("Invalid Decimal Number %s\n"), str); return (1); } cvalue = str[index] - '0'; } else { if ((str[index] >= '0') && (str[index] <= '9')) { cvalue = str[index] - '0'; } else if ((str[index] >= 'a') && (str[index] <= 'f')) { cvalue = str[index] - 'a' + 10; } else if ((str[index] >= 'A') && (str[index] <= 'F')) { cvalue = str[index] - 'A' + 10; } else { fprintf(stdout, gettext("Invalid Hex Number %s\n"), str); return (1); } } *value = *value * cbase + cvalue; } return (0); } void print_prompt(); extern FILE *yyin; void print_prompt() { fprintf(stdout, gettext("%s"), prompt); } int32_t run_fsdb() { yyin = stdin; if (yyparse() != 0) return (-1); return 0; } # # 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 # fsdb uses the -e option of lex, which generates additional lex interfaces # that are not defined in the generic $(MAPFILE.LEX). These additional lex # interfaces are exported here. SYMBOL_SCOPE { global: yywinput; yywleng; yywtext; yywunput; }; # # 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 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # FSTYP_VERS=1 FSTYPE= udfs LIBPROG= fstyp.so.${FSTYP_VERS} include ../../../../lib/Makefile.lib include ../../Makefile.fstype # There should be a mapfile here MAPFILES = CFLAGS += $(C_PICFLAGS) DYNLIB= $(LIBPROG) CERRWARN += -Wno-unused-function # Hammerhead: Suppress pointer/int cast warnings in legacy UDFS code CERRWARN += -Wno-pointer-to-int-cast CERRWARN += -Wno-int-to-pointer-cast LDLIBS += -lnvpair -ladm -lc # # Override PMAP dependency # PMAP= # No msg catalog here. POFILE= OBJS= fstyp.o ud_lib.o SRCS= $(OBJS:%.o=%.c) CPPFLAGS += -I../common CPPFLAGS += -DFSTYP_VERS=${FSTYP_VERS} CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(LIBPROG): $(OBJS) $(LINK.c) $(CPPFLAGS) $(CFLAGS) $(DYNFLAGS) $(GSHARED) -o $@ $(OBJS) \ $(LDLIBS) $(POST_PROCESS_SO) %.o: %.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) %.o: ../common/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) .KEEP_STATE: all: $(LIBPROG) install: all $(RM) $(ROOTLIBFSTYPE)/fstyp $(LN) $(ROOTUSRSBIN)/fstyp $(ROOTLIBFSTYPE)/fstyp clean: $(RM) $(OBJS) /* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * libfstyp module for udfs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ud_lib.h" typedef struct fstyp_udfs { int fd; ud_handle_t udh; nvlist_t *attr; } fstyp_udfs_t; static int is_udfs(fstyp_udfs_t *h); static int print_vds(fstyp_udfs_t *h, struct vds *, FILE *fout, FILE *ferr); static int get_attr(fstyp_udfs_t *h); int fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle); void fstyp_mod_fini(fstyp_mod_handle_t handle); int fstyp_mod_ident(fstyp_mod_handle_t handle); int fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp); int fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr); int fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle) { fstyp_udfs_t *h = (fstyp_udfs_t *)handle; if (offset != 0) { return (FSTYP_ERR_OFFSET); } if ((h = calloc(1, sizeof (fstyp_udfs_t))) == NULL) { return (FSTYP_ERR_NOMEM); } h->fd = fd; if (ud_init(h->fd, &h->udh) != 0) { free(h); return (FSTYP_ERR_NOMEM); } *handle = (fstyp_mod_handle_t)h; return (0); } void fstyp_mod_fini(fstyp_mod_handle_t handle) { fstyp_udfs_t *h = (fstyp_udfs_t *)handle; if (h->attr == NULL) { nvlist_free(h->attr); h->attr = NULL; } ud_fini(h->udh); free(h); } int fstyp_mod_ident(fstyp_mod_handle_t handle) { fstyp_udfs_t *h = (fstyp_udfs_t *)handle; return (is_udfs(h)); } int fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp) { fstyp_udfs_t *h = (fstyp_udfs_t *)handle; int error; if (h->attr == NULL) { if (nvlist_alloc(&h->attr, NV_UNIQUE_NAME_TYPE, 0)) { return (FSTYP_ERR_NOMEM); } if ((error = get_attr(h)) != 0) { nvlist_free(h->attr); h->attr = NULL; return (error); } } *attrp = h->attr; return (0); } int fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr) { fstyp_udfs_t *h = (fstyp_udfs_t *)handle; struct udf *udfs = &h->udh->udfs; int ret; (void) fprintf(fout, "Standard Identifier %5s\n", udfs->ecma_id); if (udfs->flags & VALID_MVDS) { ret = print_vds(h, &udfs->mvds, fout, ferr); } else { ret = print_vds(h, &udfs->rvds, fout, ferr); } return (ret); } /* * Assumption is that we will confirm to level-1 */ int is_udfs(fstyp_udfs_t *h) { struct udf *udfs = &h->udh->udfs; int32_t ret; if ((ret = ud_fill_udfs_info(h->udh)) != 0) { return (ret); } if ((udfs->flags & VALID_UDFS) == 0) { return (FSTYP_ERR_NO_MATCH); } return (0); } /* * For now, only return generic attributes. * Will open an RFE to add native attributes. */ static int get_attr(fstyp_udfs_t *h) { struct udf *udfs = &h->udh->udfs; struct vds *v; struct pri_vol_desc *pvd; uint32_t len; uint64_t off; uint8_t *buf; int8_t str[64]; int ret = 0; v = (udfs->flags & VALID_MVDS) ? &udfs->mvds : &udfs->rvds; /* allocate buffer */ len = udfs->lbsize; if (v->pvd_len > len) { len = v->pvd_len; } if ((buf = (uint8_t *)malloc(len)) == NULL) { return (FSTYP_ERR_NOMEM); } (void) nvlist_add_boolean_value(h->attr, "gen_clean", B_TRUE); /* Primary Volume Descriptor */ if (v->pvd_len != 0) { off = v->pvd_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, v->pvd_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ pvd = (struct pri_vol_desc *)(uint32_t *)buf; ud_convert2local(pvd->pvd_vol_id, str, 32); str[32] = '\0'; (void) nvlist_add_string(h->attr, "gen_volume_label", str); } ret = 0; out: free(buf); return (ret); } /* ARGSUSED */ int print_vds(fstyp_udfs_t *h, struct vds *v, FILE *fout, FILE *ferr) { struct udf *udfs = &h->udh->udfs; int32_t i; uint32_t len; uint64_t off; uint8_t *buf; int ret = 0; /* * All descriptors are 512 bytes * except lvd, usd and lvid * findout the largest and allocate space */ len = udfs->lbsize; if (v->lvd_len > len) { len = v->lvd_len; } if (v->usd_len > len) { len = v->usd_len; } if (udfs->lvid_len > len) { len = udfs->lvid_len; } if ((buf = (uint8_t *)malloc(len)) == NULL) { return (FSTYP_ERR_NOMEM); } /* * Anchor Volume Descriptor */ if (udfs->avdp_len != 0) { off = udfs->avdp_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, udfs->avdp_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_avd(fout, (struct anch_vol_desc_ptr *)buf); } /* * Primary Volume Descriptor */ if (v->pvd_len != 0) { off = v->pvd_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, v->pvd_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_pvd(fout, (struct pri_vol_desc *)buf); } /* * Implementation Use descriptor */ if (v->iud_len != 0) { off = v->iud_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, v->iud_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_iuvd(fout, (struct iuvd_desc *)buf); } /* * Paritions */ for (i = 0; i < h->udh->n_parts; i++) { if (v->part_len[i] != 0) { off = v->part_loc[i] * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, v->part_len[i]) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_part(fout, (struct part_desc *)buf); } } /* * Logical Volume Descriptor */ if (v->lvd_len != 0) { off = v->lvd_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, v->lvd_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_lvd(fout, (struct log_vol_desc *)buf); } /* * Unallocated Space Descriptor */ if (v->usd_len != 0) { off = v->usd_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, v->usd_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_usd(fout, (struct unall_spc_desc *)buf); } /* * Logical Volume Integrity Descriptor */ if (udfs->lvid_len != 0) { off = udfs->lvid_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, udfs->lvid_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_lvid(fout, (struct log_vol_int_desc *)buf); } /* * File Set Descriptor */ if (udfs->fsd_len != 0) { off = udfs->fsd_loc * udfs->lbsize; if (ud_read_dev(h->udh, off, buf, udfs->fsd_len) != 0) { ret = FSTYP_ERR_IO; goto out; } /* LINTED */ print_fsd(fout, h->udh, (struct file_set_desc *)buf); } ret = 0; out: free(buf); return (ret); } # # 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 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2017 Joyent, Inc. # FSTYPE= udfs LIBPROG= labelit SRCS= labelit.c ATTMK= $(LIBPROG) include ../../Makefile.fstype LDLIBS += -ladm CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 CPPFLAGS += -I../common CERRWARN += -Wno-unused-function # Hammerhead: Suppress pointer/int cast warnings in legacy UDFS code CERRWARN += -Wno-pointer-to-int-cast CERRWARN += -Wno-int-to-pointer-cast labelit : labelit.o ud_lib.o $(LINK.c) -o $@ labelit.o ud_lib.o $(LDLIBS) $(POST_PROCESS) labelit.o : labelit.c ../common/ud_lib.h ud_lib.o : ../common/ud_lib.c ../common/ud_lib.h $(COMPILE.c) -o $@ ../common/ud_lib.c $(POST_PROCESS_O) # for messaging catalog # POFILE= labelit.po # for messaging catalog # catalog: $(POFILE) $(POFILE): $(SRCS) ../common/ud_lib.h $(RM) $@ $(COMPILE.cpp) $(SRCS) > $(POFILE).i $(XGETTEXT) $(XGETFLAGS) $(POFILE).i sed "/^domain/d" messages.po > $@ $(RM) $(POFILE).i messages.po clean : rm -f labelit.o ud_lib.o /* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Label a file system volume. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ud_lib.h" static uint8_t buf[MAXBSIZE]; static uint64_t off; #define BUF_LEN 0x200 static int8_t lvinfo1_buf[BUF_LEN]; static int8_t lvinfo2_buf[BUF_LEN]; static int8_t lvinfo3_buf[BUF_LEN]; static int8_t fsname[BUF_LEN]; static int8_t volname[BUF_LEN]; static int32_t fsname_len; #define SET_LVINFO1 0x01 #define SET_LVINFO2 0x02 #define SET_LVINFO3 0x04 #define SET_FSNAME 0x08 #define SET_VOLNAME 0x10 typedef unsigned short unicode_t; #define FSNAME_STR_LEN (8 + 2) #define VOLNAME_STR_LEN 32 #define INFO_STR_LEN 36 static void usage(); static void label(ud_handle_t, uint32_t); static void print_info(struct vds *, char *, ud_handle_t); static void label_vds(struct vds *, uint32_t, ud_handle_t); static int32_t convert_string(int8_t *, int8_t *, int32_t, int32_t, int8_t *); static int32_t ud_convert2unicode(int8_t *, int8_t *, int32_t); int8_t *labelit_subopts[] = { #define LVINFO1 0x00 "lvinfo1", #define LVINFO2 0x01 "lvinfo2", #define LVINFO3 0x02 "lvinfo3", NULL}; int main(int32_t argc, char *argv[]) { int opt = 0; int32_t flags = 0; int32_t ret = 0; int8_t *options = NULL; int8_t *value = NULL; uint32_t set_flags = 0; ud_handle_t udh; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); while ((opt = getopt(argc, argv, "F:o:")) != EOF) { switch (opt) { case 'F': if (strcmp(optarg, "udfs") != 0) { usage(); } break; case 'o': /* * UDFS specific options */ options = optarg; while (*options != '\0') { switch (getsubopt(&options, labelit_subopts, &value)) { case LVINFO1 : set_flags |= SET_LVINFO1; (void) convert_string(value, lvinfo1_buf, BUF_LEN, INFO_STR_LEN, gettext("udfs labelit: lvinfo1 should be less than " "36 bytes after converting to compressed unicode " "dstring\n")); break; case LVINFO2 : set_flags |= SET_LVINFO2; (void) convert_string(value, lvinfo2_buf, BUF_LEN, INFO_STR_LEN, gettext("udfs labelit: lvinfo2 should be less than " "36 bytes after converting to compressed unicode " "dstring\n")); break; case LVINFO3 : set_flags |= SET_LVINFO3; (void) convert_string(value, lvinfo3_buf, BUF_LEN, INFO_STR_LEN, gettext("udfs labelit: lvinfo3 should be less than " "36 bytes after converting to compressed unicode " "dstring\n")); break; default: (void) fprintf(stderr, gettext("udfs labelit: Unknown suboption %s\n"), value); usage(); break; } } break; case '?': usage(); } } if ((argc - optind) == 3) { /* * There are restrictions on the * length of the names * fsname is 8 characters * volume name is 32 characters * The extra byte is for compression id */ fsname_len = convert_string(argv[optind + 1], fsname, BUF_LEN, FSNAME_STR_LEN, gettext("udfs labelit: fsname can not be longer than 8 characters\n")); (void) convert_string(argv[optind + 2], volname, BUF_LEN, VOLNAME_STR_LEN, gettext("udfs labelit: volname can not be longer " "than 32 bytes after converting to " "compressed unicode dstring\n")); set_flags |= SET_FSNAME | SET_VOLNAME; } else { if ((argc - optind) != 1) { usage(); } } if (ud_init(-1, &udh) != 0) { (void) fprintf(stderr, gettext("udfs labelit: cannot initialize ud_lib\n")); exit(1); } /* * Open special device */ if (set_flags == 0) { flags = O_RDONLY; } else { flags = O_RDWR; } if (ud_open_dev(udh, argv[optind], flags) != 0) { (void) fprintf(stderr, gettext("udfs labelit: cannot open <%s> errorno <%d>\n"), argv[optind], errno); exit(1); } if ((ret = ud_fill_udfs_info(udh)) != 0) { goto close_dev; } if ((udh->udfs.flags & VALID_UDFS) == 0) { ret = 1; goto close_dev; } label(udh, set_flags); close_dev: ud_close_dev(udh); ud_fini(udh); return (ret); } static void usage() { (void) fprintf(stderr, gettext( "udfs usage: labelit [-F udfs] [generic options] " "[ -o specific_options ] special [fsname volume]\n")); (void) fprintf(stderr, gettext( " -o : specific_options : [lvinfo1=string]," "[lvinfo2=string],[lvinfo3=string]\n")); (void) fprintf(stderr, gettext("NOTE that all -o suboptions: must" " be separated only by commas.\n")); exit(1); } static void label(ud_handle_t udh, uint32_t set_flags) { if (set_flags == 0) { if (udh->udfs.flags & VALID_MVDS) { print_info(&udh->udfs.mvds, "mvds", udh); } if (udh->udfs.flags & VALID_RVDS) { print_info(&udh->udfs.rvds, "rvds", udh); } return; } else { if (udh->udfs.flags & VALID_MVDS) { label_vds(&udh->udfs.mvds, set_flags, udh); } if (udh->udfs.flags & VALID_RVDS) { label_vds(&udh->udfs.rvds, set_flags, udh); } if (((set_flags & (SET_FSNAME | SET_VOLNAME)) == (SET_FSNAME | SET_VOLNAME)) && (udh->udfs.fsd_len != 0)) { struct file_set_desc *fsd; off = udh->udfs.fsd_loc * udh->udfs.lbsize; if (ud_read_dev(udh, off, buf, udh->udfs.fsd_len) != 0) { return; } /* LINTED */ fsd = (struct file_set_desc *)buf; set_dstring(fsd->fsd_lvid, volname, sizeof (fsd->fsd_lvid)); set_dstring(fsd->fsd_fsi, volname, sizeof (fsd->fsd_fsi)); ud_make_tag(udh, &fsd->fsd_tag, UD_FILE_SET_DESC, SWAP_32(fsd->fsd_tag.tag_loc), SWAP_16(fsd->fsd_tag.tag_crc_len)); (void) ud_write_dev(udh, off, buf, udh->udfs.fsd_len); } } } static void print_info(struct vds *v, char *name, ud_handle_t udh) { uint8_t outbuf[BUF_LEN]; if (v->pvd_len != 0) { off = v->pvd_loc * udh->udfs.lbsize; if (ud_read_dev(udh, off, buf, sizeof (struct pri_vol_desc)) == 0) { struct pri_vol_desc *pvd; /* LINTED */ pvd = (struct pri_vol_desc *)buf; bzero(outbuf, BUF_LEN); (void) ud_convert2local( (int8_t *)pvd->pvd_vsi, (int8_t *)outbuf, strlen(pvd->pvd_vsi)); (void) fprintf(stdout, gettext("fsname in %s : %s\n"), name, outbuf); bzero(outbuf, BUF_LEN); pvd->pvd_vol_id[31] = '\0'; (void) ud_convert2local( (int8_t *)pvd->pvd_vol_id, (int8_t *)outbuf, strlen(pvd->pvd_vol_id)); (void) fprintf(stdout, gettext("volume label in %s : %s\n"), name, outbuf); } } if (v->iud_len != 0) { off = v->iud_loc * udh->udfs.lbsize; if (ud_read_dev(udh, off, buf, sizeof (struct iuvd_desc)) == 0) { struct iuvd_desc *iud; /* LINTED */ iud = (struct iuvd_desc *)buf; bzero(outbuf, BUF_LEN); iud->iuvd_ifo1[35] = '\0'; (void) ud_convert2local( (int8_t *)iud->iuvd_ifo1, (int8_t *)outbuf, strlen(iud->iuvd_ifo1)); (void) fprintf(stdout, gettext("LVInfo1 in %s : %s\n"), name, outbuf); bzero(outbuf, BUF_LEN); iud->iuvd_ifo2[35] = '\0'; (void) ud_convert2local( (int8_t *)iud->iuvd_ifo2, (int8_t *)outbuf, strlen(iud->iuvd_ifo2)); (void) fprintf(stdout, gettext("LVInfo2 in %s : %s\n"), name, outbuf); bzero(outbuf, BUF_LEN); iud->iuvd_ifo3[35] = '\0'; (void) ud_convert2local( (int8_t *)iud->iuvd_ifo3, (int8_t *)outbuf, strlen(iud->iuvd_ifo3)); (void) fprintf(stdout, gettext("LVInfo3 in %s : %s\n"), name, outbuf); } } } /* ARGSUSED */ static void label_vds(struct vds *v, uint32_t set_flags, ud_handle_t udh) { if (((set_flags & (SET_FSNAME | SET_VOLNAME)) == (SET_FSNAME | SET_VOLNAME)) && (v->pvd_len)) { off = v->pvd_loc * udh->udfs.lbsize; if (ud_read_dev(udh, off, buf, sizeof (struct pri_vol_desc)) == 0) { struct pri_vol_desc *pvd; /* LINTED */ pvd = (struct pri_vol_desc *)buf; bzero((int8_t *)&pvd->pvd_vsi[9], 119); (void) strncpy((int8_t *)&pvd->pvd_vsi[9], &fsname[1], fsname_len - 1); set_dstring(pvd->pvd_vol_id, volname, sizeof (pvd->pvd_vol_id)); ud_make_tag(udh, &pvd->pvd_tag, SWAP_16(pvd->pvd_tag.tag_id), SWAP_32(pvd->pvd_tag.tag_loc), SWAP_16(pvd->pvd_tag.tag_crc_len)); (void) ud_write_dev(udh, off, buf, sizeof (struct pri_vol_desc)); } } if (set_flags && v->iud_len) { off = v->iud_loc * udh->udfs.lbsize; if (ud_read_dev(udh, off, buf, sizeof (struct iuvd_desc)) == 0) { struct iuvd_desc *iuvd; /* LINTED */ iuvd = (struct iuvd_desc *)buf; if ((set_flags & SET_VOLNAME) == SET_VOLNAME) { set_dstring(iuvd->iuvd_lvi, volname, sizeof (iuvd->iuvd_lvi)); } if ((set_flags & SET_LVINFO1) == SET_LVINFO1) { set_dstring(iuvd->iuvd_ifo1, lvinfo1_buf, sizeof (iuvd->iuvd_ifo1)); } if ((set_flags & SET_LVINFO2) == SET_LVINFO2) { set_dstring(iuvd->iuvd_ifo2, lvinfo2_buf, sizeof (iuvd->iuvd_ifo2)); } if ((set_flags & SET_LVINFO3) == SET_LVINFO3) { set_dstring(iuvd->iuvd_ifo3, lvinfo3_buf, sizeof (iuvd->iuvd_ifo3)); } ud_make_tag(udh, &iuvd->iuvd_tag, SWAP_16(iuvd->iuvd_tag.tag_id), SWAP_32(iuvd->iuvd_tag.tag_loc), SWAP_16(iuvd->iuvd_tag.tag_crc_len)); (void) ud_write_dev(udh, off, buf, sizeof (struct iuvd_desc)); } } if (((set_flags & (SET_FSNAME | SET_VOLNAME)) == (SET_FSNAME | SET_VOLNAME)) && (v->lvd_len)) { off = v->lvd_loc * udh->udfs.lbsize; if (ud_read_dev(udh, off, buf, sizeof (struct log_vol_desc)) == 0) { struct log_vol_desc *lvd; /* LINTED */ lvd = (struct log_vol_desc *)buf; set_dstring(lvd->lvd_lvid, volname, sizeof (lvd->lvd_lvid)); ud_make_tag(udh, &lvd->lvd_tag, SWAP_16(lvd->lvd_tag.tag_id), SWAP_32(lvd->lvd_tag.tag_loc), SWAP_16(lvd->lvd_tag.tag_crc_len)); (void) ud_write_dev(udh, off, buf, sizeof (struct log_vol_desc)); } } } int32_t convert_string(int8_t *value, int8_t *out_buf, int32_t out_len, int32_t len, int8_t *error_string) { int32_t out_length = 0; out_length = ud_convert2unicode(value, out_buf, out_len); if (out_length > len - 1) { (void) fprintf(stderr, "%s", error_string); exit(1); } return (out_length); } static int32_t ud_convert2unicode(int8_t *mb, int8_t *comp, int32_t out_len) { wchar_t buf4c[128]; int32_t len = 0; int32_t i = 0; int32_t j = 0; uint8_t c = 8; len = mbstowcs(buf4c, mb, 127); buf4c[127] = '\0'; for (i = 0; i < len; i++) { if (buf4c[i] & 0xFFFFFF00) { c = 16; break; } } comp[0] = c; j = 1; for (i = 0; i < len && i < out_len; i++) { if (c == 16) { comp[j] = (buf4c[i] & 0xFF00) >> 8; } comp[j++] = buf4c[i] & 0xFF; } return (j); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 (c) 1999,2001 by Sun Microsystems, Inc. # All rights reserved. # # Copyright (c) 2018, Joyent, Inc. FSTYPE= udfs LIBPROG= mkfs ATTMK= $(LIBPROG) include ../../Makefile.fstype # for messaging catalog # POFILE= mkfs.po catalog: $(POFILE) LDLIBS += -ladm MKFSOBJS= mkfs.o udfslib.o UDFSDIR= ../../../../uts/common/fs/ufs #UDFSOBJS= ufs_subr.o ufs_tables.o UDFSOBJS= CERRWARN += -Wno-parentheses # not linted SMATCH=off OBJS= $(MKFSOBJS) $(UDFSOBJS) SRCS= $(OBJS:%.o=%.c) $(LIBPROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) %.o: $(UDFSDIR)/%.c $(COMPILE.c) $< clean: $(RM) $(OBJS) /* * 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; int 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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 (c) 1989 by Sun Microsystem, Inc. */ #ifndef _UDFS_H #define _UDFS_H #ifdef __cplusplus extern "C" { #endif /* * Tag structure errors */ #define TAGERR_CKSUM 1 /* Invalid checksum on tag */ #define TAGERR_ID 2 /* Unknown tag id */ #define TAGERR_VERSION 3 /* Version > ecma_version */ #define TAGERR_TOOBIG 4 /* CRC length is too large */ #define TAGERR_CRC 5 /* Bad CRC */ #define TAGERR_LOC 6 /* Location does not match tag location */ #ifdef __cplusplus } #endif #endif /* _UDFS_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * Library of support routines for UDFS data structures and conversions. */ #include #include #include #include #include #include #include #include "udfs.h" char *tagerrs[] = { "no error", "invalid checksum", /* TAGERR_CKSUM */ "unknown tag id", /* TAGERR_ID */ "invalid version", /* TAGERR_VERSION */ "CRC length too large", /* TAGERR_TOOBIG */ "invalid CRC", /* TAGERR_CRC */ "location mismatch" /* TAGERR_LOC */ }; #ifdef sparc #define SWAP16(x) (((x) & 0xff) << 8 | ((x) >> 8) & 0xff) #define SWAP32(x) (((x) & 0xff) << 24 | ((x) & 0xff00) << 8 | \ ((x) & 0xff0000) >> 8 | ((x) >> 24) & 0xff) #define SWAP64(x) (SWAP32((x) >> 32) & 0xffffffff | SWAP32(x) << 32) #else #define SWAP16(x) (x) #define SWAP32(x) (x) #define SWAP64(x) (x) #endif static void ud_swap_ext_ad(struct extent_ad *); static void ud_swap_tstamp(struct tstamp *); static void ud_swap_icb_tag(struct icb_tag *); void ud_swap_short_ad(struct short_ad *); void ud_swap_long_ad(struct long_ad *); static void ud_swap_pri_vol_desc(struct pri_vol_desc *); static void ud_swap_vdp(struct vol_desc_ptr *); static void ud_swap_iuvd(struct iuvd_desc *); static void ud_swap_avdp(struct anch_vol_desc_ptr *); static void ud_swap_part_desc(struct part_desc *); static void ud_swap_log_desc(struct log_vol_desc *); static void ud_swap_unall_desc(struct unall_spc_desc *); static void ud_swap_lvint(struct log_vol_int_desc *); static void ud_swap_fileset_desc(struct file_set_desc *); static void ud_swap_term_desc(struct term_desc *); static void ud_swap_file_id(struct file_id *); static void ud_swap_file_entry(struct file_entry *, int); static void ud_swap_alloc_ext(struct alloc_ext_desc *); static void ud_swap_tstamp(tstamp_t *); static void ud_swap_space_bitmap(struct space_bmap_desc *); static uint16_t crc16(uint8_t *, int32_t, int32_t); extern uint32_t ecma_version; void maketag(struct tag *itp, struct tag *otp) { int32_t sum, i; uint8_t *cp; if (itp != otp) { bcopy((unsigned char *)(itp + 1), (unsigned char *)(otp + 1), itp->tag_crc_len); } /* Swap fields */ switch (itp->tag_id) { case UD_PRI_VOL_DESC: ud_swap_pri_vol_desc((struct pri_vol_desc *)otp); break; case UD_ANCH_VOL_DESC: ud_swap_avdp((struct anch_vol_desc_ptr *)otp); break; case UD_VOL_DESC_PTR: ud_swap_vdp((struct vol_desc_ptr *)otp); break; case UD_IMPL_USE_DESC: ud_swap_iuvd((struct iuvd_desc *)otp); break; case UD_PART_DESC: ud_swap_part_desc((struct part_desc *)otp); break; case UD_LOG_VOL_DESC: ud_swap_log_desc((struct log_vol_desc *)otp); break; case UD_UNALL_SPA_DESC: ud_swap_unall_desc((struct unall_spc_desc *)otp); break; case UD_TERM_DESC: ud_swap_term_desc((struct term_desc *)otp); break; case UD_LOG_VOL_INT: /* LINTED */ ud_swap_lvint((struct log_vol_int_desc *)otp); break; case UD_FILE_SET_DESC: ud_swap_fileset_desc((struct file_set_desc *)otp); break; case UD_FILE_ID_DESC: ud_swap_file_id((struct file_id *)otp); break; case UD_ALLOC_EXT_DESC: break; case UD_INDIRECT_ENT: break; case UD_TERMINAL_ENT: break; case UD_FILE_ENTRY: /* LINTED */ ud_swap_file_entry((struct file_entry *)otp, 0); break; case UD_EXT_ATTR_HDR: break; case UD_UNALL_SPA_ENT: break; case UD_SPA_BMAP_DESC: ud_swap_space_bitmap((struct space_bmap_desc *)otp); break; case UD_PART_INT_DESC: break; } otp->tag_id = SWAP16(itp->tag_id); otp->tag_desc_ver = SWAP16(itp->tag_desc_ver); otp->tag_cksum = otp->tag_res = 0; otp->tag_sno = SWAP16(itp->tag_sno); otp->tag_crc = SWAP16(crc16((unsigned char *)(otp+1), itp->tag_crc_len, 0)); otp->tag_crc_len = SWAP16(itp->tag_crc_len); otp->tag_loc = SWAP32(itp->tag_loc); /* * Now do checksum on tag itself */ cp = (unsigned char *)otp; sum = 0; for (i = 0; i < sizeof (*otp); i++) sum += *cp++; otp->tag_cksum = sum; } int32_t verifytag(struct tag *tp, uint32_t loc, struct tag *otp, int expect) { uint8_t *cp; uint32_t id, vers, length, tloc; int sum, i; sum = -tp->tag_cksum; cp = (unsigned char *)tp; for (i = 0; i < sizeof (*tp); i++) sum += *cp++; if ((sum & 0xff) != tp->tag_cksum) return (TAGERR_CKSUM); id = SWAP16(tp->tag_id); if (id > 9 && id < 256 || id > 266 || (expect > 0 && id != expect)) return (TAGERR_ID); vers = SWAP16(tp->tag_desc_ver); if (vers > ecma_version) return (TAGERR_VERSION); length = SWAP16(tp->tag_crc_len); if (length > MAXBSIZE) return (TAGERR_TOOBIG); if (crc16((unsigned char *)(tp+1), length, SWAP16(tp->tag_crc)) != 0) return (TAGERR_CRC); tloc = SWAP32(tp->tag_loc); if ((int)loc != -1 && tloc != loc) return (TAGERR_LOC); if (!otp) return (0); otp->tag_id = id; otp->tag_desc_ver = vers; otp->tag_cksum = tp->tag_cksum; otp->tag_res = 0; otp->tag_sno = SWAP16(tp->tag_sno); otp->tag_crc = SWAP16(tp->tag_crc); otp->tag_crc_len = length; otp->tag_loc = tloc; if (tp != otp) bcopy((unsigned char *)(tp + 1), (unsigned char *)(otp + 1), otp->tag_crc_len); /* Swap fields */ switch (otp->tag_id) { case UD_PRI_VOL_DESC: ud_swap_pri_vol_desc((struct pri_vol_desc *)otp); break; case UD_ANCH_VOL_DESC: ud_swap_avdp((struct anch_vol_desc_ptr *)otp); break; case UD_VOL_DESC_PTR: ud_swap_vdp((struct vol_desc_ptr *)otp); break; case UD_IMPL_USE_DESC: ud_swap_iuvd((struct iuvd_desc *)otp); break; case UD_PART_DESC: ud_swap_part_desc((struct part_desc *)otp); break; case UD_LOG_VOL_DESC: ud_swap_log_desc((struct log_vol_desc *)otp); break; case UD_UNALL_SPA_DESC: ud_swap_unall_desc((struct unall_spc_desc *)otp); break; case UD_TERM_DESC: ud_swap_term_desc((struct term_desc *)otp); break; case UD_LOG_VOL_INT: /* LINTED */ ud_swap_lvint((struct log_vol_int_desc *)otp); break; case UD_FILE_SET_DESC: ud_swap_fileset_desc((struct file_set_desc *)otp); break; case UD_FILE_ID_DESC: ud_swap_file_id((struct file_id *)otp); break; case UD_ALLOC_EXT_DESC: ud_swap_alloc_ext((struct alloc_ext_desc *)otp); break; case UD_INDIRECT_ENT: break; case UD_TERMINAL_ENT: break; case UD_FILE_ENTRY: /* LINTED */ ud_swap_file_entry((struct file_entry *)otp, 1); break; case UD_EXT_ATTR_HDR: break; case UD_UNALL_SPA_ENT: break; case UD_SPA_BMAP_DESC: ud_swap_space_bitmap((struct space_bmap_desc *)otp); break; case UD_PART_INT_DESC: break; } return (0); } static void ud_swap_ext_ad(struct extent_ad *p) { p->ext_len = SWAP32(p->ext_len); p->ext_loc = SWAP32(p->ext_loc); } /* ARGSUSED */ static void ud_swap_regid(struct regid *p) { } static void ud_swap_icb_tag(struct icb_tag *p) { p->itag_prnde = SWAP32(p->itag_prnde); p->itag_strategy = SWAP16(p->itag_strategy); p->itag_param = SWAP16(p->itag_param); p->itag_max_ent = SWAP16(p->itag_max_ent); p->itag_lb_loc = SWAP32(p->itag_lb_loc); p->itag_lb_prn = SWAP16(p->itag_lb_prn); p->itag_flags = SWAP16(p->itag_flags); } void ud_swap_short_ad(struct short_ad *p) { p->sad_ext_len = SWAP32(p->sad_ext_len); p->sad_ext_loc = SWAP32(p->sad_ext_loc); } void ud_swap_long_ad(struct long_ad *p) { p->lad_ext_len = SWAP32(p->lad_ext_len); p->lad_ext_loc = SWAP32(p->lad_ext_loc); p->lad_ext_prn = SWAP16(p->lad_ext_prn); } static void ud_swap_pri_vol_desc(struct pri_vol_desc *p) { p->pvd_vdsn = SWAP32(p->pvd_vdsn); p->pvd_pvdn = SWAP32(p->pvd_pvdn); p->pvd_vsn = SWAP16(p->pvd_vsn); p->pvd_mvsn = SWAP16(p->pvd_mvsn); p->pvd_il = SWAP16(p->pvd_il); p->pvd_mil = SWAP16(p->pvd_mil); p->pvd_csl = SWAP32(p->pvd_csl); p->pvd_mcsl = SWAP32(p->pvd_mcsl); ud_swap_ext_ad(&p->pvd_vol_abs); ud_swap_ext_ad(&p->pvd_vcn); ud_swap_regid(&p->pvd_appl_id); ud_swap_tstamp(&p->pvd_time); ud_swap_regid(&p->pvd_ii); p->pvd_pvdsl = SWAP32(p->pvd_pvdsl); p->pvd_flags = SWAP16(p->pvd_flags); } static void ud_swap_iuvd(struct iuvd_desc *p) { p->iuvd_vdsn = SWAP32(p->iuvd_vdsn); ud_swap_regid(&p->iuvd_ii); ud_swap_regid(&p->iuvd_iid); } static void ud_swap_vdp(struct vol_desc_ptr *p) { p->vdp_vdsn = SWAP32(p->vdp_vdsn); ud_swap_ext_ad(&p->vdp_nvdse); } static void ud_swap_avdp(struct anch_vol_desc_ptr *p) { ud_swap_ext_ad(&p->avd_main_vdse); ud_swap_ext_ad(&p->avd_res_vdse); } static void ud_swap_part_desc(struct part_desc *p) { struct phdr_desc *php; p->pd_vdsn = SWAP32(p->pd_vdsn); p->pd_pflags = SWAP16(p->pd_pflags); p->pd_pnum = SWAP16(p->pd_pnum); ud_swap_regid(&p->pd_pcontents); p->pd_acc_type = SWAP32(p->pd_acc_type); p->pd_part_start = SWAP32(p->pd_part_start); p->pd_part_length = SWAP32(p->pd_part_length); ud_swap_regid(&p->pd_ii); if (strncmp(p->pd_pcontents.reg_id, "+NSR", 4) == 0) { /* LINTED */ php = (struct phdr_desc *)p->pd_pc_use; ud_swap_short_ad(&php->phdr_ust); ud_swap_short_ad(&php->phdr_usb); ud_swap_short_ad(&php->phdr_it); ud_swap_short_ad(&php->phdr_fst); ud_swap_short_ad(&php->phdr_fsb); } } static void ud_swap_log_desc(struct log_vol_desc *p) { p->lvd_vdsn = SWAP32(p->lvd_vdsn); p->lvd_log_bsize = SWAP32(p->lvd_log_bsize); ud_swap_regid(&p->lvd_dom_id); ud_swap_long_ad(&p->lvd_lvcu); p->lvd_mtbl_len = SWAP32(p->lvd_mtbl_len); p->lvd_num_pmaps = SWAP32(p->lvd_num_pmaps); ud_swap_regid(&p->lvd_ii); ud_swap_ext_ad(&p->lvd_int_seq_ext); } static void ud_swap_unall_desc(struct unall_spc_desc *p) { p->ua_vdsn = SWAP32(p->ua_vdsn); p->ua_nad = SWAP32(p->ua_nad); } static void ud_swap_lvint(struct log_vol_int_desc *p) { struct lvid_iu *lvup; ud_swap_tstamp(&p->lvid_tstamp); p->lvid_int_type = SWAP32(p->lvid_int_type); ud_swap_ext_ad(&p->lvid_nie); p->lvid_npart = SWAP32(p->lvid_npart); p->lvid_liu = SWAP32(p->lvid_liu); p->lvid_uniqid = SWAP64(p->lvid_uniqid); p->lvid_fst[0] = SWAP32(p->lvid_fst[0]); p->lvid_fst[1] = SWAP32(p->lvid_fst[1]); lvup = (struct lvid_iu *)&p->lvid_fst[2]; ud_swap_regid(&lvup->lvidiu_regid); lvup->lvidiu_nfiles = SWAP32(lvup->lvidiu_nfiles); lvup->lvidiu_ndirs = SWAP32(lvup->lvidiu_ndirs); lvup->lvidiu_mread = SWAP16(lvup->lvidiu_mread); lvup->lvidiu_mwrite = SWAP16(lvup->lvidiu_mwrite); lvup->lvidiu_maxwr = SWAP16(lvup->lvidiu_maxwr); } static void ud_swap_fileset_desc(struct file_set_desc *p) { ud_swap_tstamp(&p->fsd_time); p->fsd_ilevel = SWAP16(p->fsd_ilevel); p->fsd_mi_level = SWAP16(p->fsd_mi_level); p->fsd_cs_list = SWAP32(p->fsd_cs_list); p->fsd_mcs_list = SWAP32(p->fsd_mcs_list); p->fsd_fs_no = SWAP32(p->fsd_fs_no); p->fsd_fsd_no = SWAP32(p->fsd_fsd_no); ud_swap_long_ad(&p->fsd_root_icb); ud_swap_regid(&p->fsd_did); ud_swap_long_ad(&p->fsd_next); } /* ARGSUSED */ static void ud_swap_term_desc(struct term_desc *p) { } static void ud_swap_file_id(struct file_id *p) { p->fid_ver = SWAP16(p->fid_ver); ud_swap_long_ad(&p->fid_icb); p->fid_iulen = SWAP16(p->fid_iulen); } static void ud_swap_alloc_ext(struct alloc_ext_desc *p) { p->aed_rev_ael = SWAP32(p->aed_rev_ael); p->aed_len_aed = SWAP32(p->aed_len_aed); } static void ud_swap_space_bitmap(struct space_bmap_desc *p) { p->sbd_nbits = SWAP32(p->sbd_nbits); p->sbd_nbytes = SWAP32(p->sbd_nbytes); } static void ud_swap_file_entry(struct file_entry *p, int32_t rdflag) { int32_t i; short_ad_t *sap; long_ad_t *lap; /* Do Extended Attributes and Allocation Descriptors */ if (rdflag) { p->fe_len_adesc = SWAP32(p->fe_len_adesc); p->fe_len_ear = SWAP32(p->fe_len_ear); ud_swap_icb_tag(&p->fe_icb_tag); } switch (p->fe_icb_tag.itag_flags & 0x3) { case ICB_FLAG_SHORT_AD: /* LINTED */ sap = (short_ad_t *)(p->fe_spec + p->fe_len_ear); for (i = 0; i < p->fe_len_adesc / sizeof (short_ad_t); i++, sap++) ud_swap_short_ad(sap); break; case ICB_FLAG_LONG_AD: /* LINTED */ lap = (long_ad_t *)(p->fe_spec + p->fe_len_ear); for (i = 0; i < p->fe_len_adesc / sizeof (long_ad_t); i++, lap++) ud_swap_long_ad(lap); break; case ICB_FLAG_EXT_AD: break; case ICB_FLAG_ONE_AD: break; } p->fe_uid = SWAP32(p->fe_uid); p->fe_gid = SWAP32(p->fe_gid); p->fe_perms = SWAP32(p->fe_perms); p->fe_lcount = SWAP16(p->fe_lcount); p->fe_rec_len = SWAP32(p->fe_rec_len); p->fe_info_len = SWAP64(p->fe_info_len); p->fe_lbr = SWAP64(p->fe_lbr); ud_swap_tstamp(&p->fe_acc_time); ud_swap_tstamp(&p->fe_mod_time); ud_swap_tstamp(&p->fe_attr_time); p->fe_ckpoint = SWAP32(p->fe_ckpoint); ud_swap_long_ad(&p->fe_ea_icb); ud_swap_regid(&p->fe_impl_id); p->fe_uniq_id = SWAP64(p->fe_uniq_id); if (!rdflag) { p->fe_len_adesc = SWAP32(p->fe_len_adesc); p->fe_len_ear = SWAP32(p->fe_len_ear); ud_swap_icb_tag(&p->fe_icb_tag); } } static void ud_swap_tstamp(tstamp_t *tp) { tp->ts_tzone = SWAP16(tp->ts_tzone); tp->ts_year = SWAP16(tp->ts_year); } void setcharspec(struct charspec *cp, int32_t type, uint8_t *info) { cp->cs_type = type; bzero(cp->cs_info, sizeof (cp->cs_info)); (void) strncpy(cp->cs_info, (int8_t *)info, sizeof (cp->cs_info)); } static unsigned short crctab[] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; static uint16_t crc16(uint8_t *buf, int32_t size, int32_t rem) { uint16_t crc = 0; while (size-- > 0) crc = (crc << 8) ^ crctab[((crc >> 8) ^ *buf++) & 0xff]; return ((crc ^ rem) & 0xffff); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 2003 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # FSTYPE= udfs LIBPROG= mount include ../../Makefile.fstype include ../../Makefile.mount CPPFLAGS += -D_LARGEFILE64_SOURCE include ../../Makefile.mount.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include /* for getopt(3) */ #include #include #include #include #include #include #include #define FSTYPE "udfs" #define NAME_MAX 64 static int roflag = 0; static int mflag = 0; static int Oflag = 0; static int qflag = 0; static char optbuf[MAX_MNTOPT_STR] = { '\0', }; static int optsize = 0; static char fstype[] = FSTYPE; static char typename[NAME_MAX], *myname; static void do_mount(char *, char *, int); static void rpterr(char *, char *); static void usage(void); int main(int argc, char **argv) { char *special, *mountp; int flags = 0; int c; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); myname = strrchr(argv[0], '/'); if (myname) { myname++; } else { myname = argv[0]; } (void) snprintf(typename, sizeof (typename), "%s %s", fstype, myname); argv[0] = typename; /* check for proper arguments */ while ((c = getopt(argc, argv, "mo:rOq")) != EOF) { switch (c) { case 'm': mflag++; break; case 'o': if (strlcpy(optbuf, optarg, sizeof (optbuf)) >= sizeof (optbuf)) { (void) fprintf(stderr, gettext("%s: Invalid argument: %s\n"), myname, optarg); return (2); } optsize = strlen(optbuf); break; case 'r': roflag++; break; case 'O': Oflag++; break; case 'q': qflag = 1; break; default : break; } } if ((argc - optind) != 2) usage(); special = argv[optind++]; mountp = argv[optind++]; if (roflag) flags = MS_RDONLY; if (optsize > 0) { struct mnttab m; m.mnt_mntopts = optbuf; if (hasmntopt(&m, "m")) mflag++; } flags |= (Oflag ? MS_OVERLAY : 0); flags |= (mflag ? MS_NOMNTTAB : 0); /* * Perform the mount. * Only the low-order bit of "roflag" is used by the system * calls (to denote read-only or read-write). */ do_mount(special, mountp, flags); return (0); } static void rpterr(char *bs, char *mp) { switch (errno) { case EPERM: (void) fprintf(stderr, gettext("%s: insufficient privileges\n"), myname); break; case ENXIO: (void) fprintf(stderr, gettext("%s: %s no such device\n"), myname, bs); break; case ENOTDIR: (void) fprintf(stderr, gettext("%s: %s not a directory\n\t" "or a component of %s is not a directory\n"), myname, mp, bs); break; case ENOENT: (void) fprintf(stderr, gettext("%s: %s or %s, no such file or directory\n"), myname, bs, mp); break; case EINVAL: (void) fprintf(stderr, gettext("%s: %s is not an udfs file system.\n"), typename, bs); break; case EBUSY: (void) fprintf(stderr, gettext("%s: %s is already mounted or %s is busy\n"), myname, bs, mp); break; case ENOTBLK: (void) fprintf(stderr, gettext("%s: %s not a block device\n"), myname, bs); break; case EROFS: (void) fprintf(stderr, gettext("%s: %s write-protected\n"), myname, bs); break; case ENOSPC: (void) fprintf(stderr, gettext("%s: %s is corrupted. needs checking\n"), myname, bs); break; default: perror(myname); (void) fprintf(stderr, gettext("%s: cannot mount %s\n"), myname, bs); } } static void do_mount(char *special, char *mountp, int flag) { char *savedoptbuf; if ((savedoptbuf = strdup(optbuf)) == NULL) { (void) fprintf(stderr, gettext("%s: out of memory\n"), myname); exit(2); } if (mount(special, mountp, flag | MS_DATA | MS_OPTIONSTR, fstype, NULL, 0, optbuf, MAX_MNTOPT_STR) == -1) { rpterr(special, mountp); exit(31+2); } if (optsize && !qflag) cmp_requested_to_actual_options(savedoptbuf, optbuf, special, mountp); } static void usage(void) { (void) fprintf(stdout, gettext("udfs usage:\n" "mount [-F udfs] [generic options] " "[-o suboptions] {special | mount_point}\n")); (void) fprintf(stdout, gettext("\tsuboptions are: \n" "\t ro,rw,nosuid,remount,m\n")); (void) fprintf(stdout, gettext( "\t only one of ro, rw can be " "used at the same time\n")); (void) fprintf(stdout, gettext( "\t remount can be used only with rw\n")); exit(32); }