/*
* 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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Label a file system volume.
*/
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <locale.h>
#include <errno.h>
#include <sys/fcntl.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mntent.h>
#include <sys/fs/udf_volume.h>
#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[])
{
int32_t 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);
}