1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Label a file system volume. 30 */ 31 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <fcntl.h> 39 #include <locale.h> 40 #include <errno.h> 41 #include <sys/fcntl.h> 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/mntent.h> 45 46 #include <sys/fs/udf_volume.h> 47 #include "ud_lib.h" 48 49 static uint8_t buf[MAXBSIZE]; 50 static uint64_t off; 51 #define BUF_LEN 0x200 52 static int8_t lvinfo1_buf[BUF_LEN]; 53 static int8_t lvinfo2_buf[BUF_LEN]; 54 static int8_t lvinfo3_buf[BUF_LEN]; 55 static int8_t fsname[BUF_LEN]; 56 static int8_t volname[BUF_LEN]; 57 static int32_t fsname_len; 58 59 #define SET_LVINFO1 0x01 60 #define SET_LVINFO2 0x02 61 #define SET_LVINFO3 0x04 62 #define SET_FSNAME 0x08 63 #define SET_VOLNAME 0x10 64 65 typedef unsigned short unicode_t; 66 67 #define FSNAME_STR_LEN (8 + 2) 68 #define VOLNAME_STR_LEN 32 69 #define INFO_STR_LEN 36 70 71 static void usage(); 72 static void label(ud_handle_t, uint32_t); 73 static void print_info(struct vds *, char *, ud_handle_t); 74 static void label_vds(struct vds *, uint32_t, ud_handle_t); 75 static int32_t convert_string(int8_t *, int8_t *, int32_t, int32_t, int8_t *); 76 static int32_t ud_convert2unicode(int8_t *, int8_t *, int32_t); 77 78 79 int8_t *labelit_subopts[] = { 80 #define LVINFO1 0x00 81 "lvinfo1", 82 #define LVINFO2 0x01 83 "lvinfo2", 84 #define LVINFO3 0x02 85 "lvinfo3", 86 NULL}; 87 88 89 int 90 main(int32_t argc, char *argv[]) 91 { 92 int32_t opt = 0; 93 int32_t flags = 0; 94 int32_t ret = 0; 95 int8_t *options = NULL; 96 int8_t *value = NULL; 97 uint32_t set_flags = 0; 98 ud_handle_t udh; 99 100 (void) setlocale(LC_ALL, ""); 101 102 #if !defined(TEXT_DOMAIN) 103 #define TEXT_DOMAIN "SYS_TEST" 104 #endif 105 106 (void) textdomain(TEXT_DOMAIN); 107 108 109 while ((opt = getopt(argc, argv, "F:o:")) != EOF) { 110 switch (opt) { 111 case 'F': 112 if (strcmp(optarg, "udfs") != 0) { 113 usage(); 114 } 115 break; 116 117 case 'o': 118 /* 119 * UDFS specific options 120 */ 121 options = optarg; 122 while (*options != '\0') { 123 switch (getsubopt(&options, labelit_subopts, 124 &value)) { 125 case LVINFO1 : 126 set_flags |= SET_LVINFO1; 127 (void) convert_string(value, 128 lvinfo1_buf, BUF_LEN, 129 INFO_STR_LEN, 130 gettext("udfs labelit: lvinfo1 should be less than " 131 "36 bytes after converting to compressed unicode " 132 "dstring\n")); 133 break; 134 case LVINFO2 : 135 set_flags |= SET_LVINFO2; 136 (void) convert_string(value, 137 lvinfo2_buf, BUF_LEN, 138 INFO_STR_LEN, 139 gettext("udfs labelit: lvinfo2 should be less than " 140 "36 bytes after converting to compressed unicode " 141 "dstring\n")); 142 break; 143 case LVINFO3 : 144 set_flags |= SET_LVINFO3; 145 (void) convert_string(value, 146 lvinfo3_buf, BUF_LEN, 147 INFO_STR_LEN, 148 gettext("udfs labelit: lvinfo3 should be less than " 149 "36 bytes after converting to compressed unicode " 150 "dstring\n")); 151 break; 152 default: 153 (void) fprintf(stderr, 154 gettext("udfs labelit: Unknown suboption %s\n"), value); 155 usage(); 156 break; 157 } 158 } 159 break; 160 161 case '?': 162 usage(); 163 } 164 } 165 166 if ((argc - optind) == 3) { 167 168 /* 169 * There are restrictions on the 170 * length of the names 171 * fsname is 8 characters 172 * volume name is 32 characters 173 * The extra byte is for compression id 174 */ 175 fsname_len = convert_string(argv[optind + 1], 176 fsname, BUF_LEN, FSNAME_STR_LEN, 177 gettext("udfs labelit: fsname can not be longer than 8 characters\n")); 178 179 (void) convert_string(argv[optind + 2], 180 volname, BUF_LEN, VOLNAME_STR_LEN, 181 gettext("udfs labelit: volname can not be longer " 182 "than 32 bytes after converting to " 183 "compressed unicode dstring\n")); 184 set_flags |= SET_FSNAME | SET_VOLNAME; 185 } else { 186 if ((argc - optind) != 1) { 187 usage(); 188 } 189 } 190 191 if (ud_init(-1, &udh) != 0) { 192 (void) fprintf(stderr, 193 gettext("udfs labelit: cannot initialize ud_lib\n")); 194 exit(1); 195 } 196 197 /* 198 * Open special device 199 */ 200 if (set_flags == 0) { 201 flags = O_RDONLY; 202 } else { 203 flags = O_RDWR; 204 } 205 if (ud_open_dev(udh, argv[optind], flags) != 0) { 206 (void) fprintf(stderr, 207 gettext("udfs labelit: cannot open <%s> errorno <%d>\n"), 208 argv[optind], errno); 209 exit(1); 210 } 211 212 if ((ret = ud_fill_udfs_info(udh)) != 0) { 213 goto close_dev; 214 } 215 216 if ((udh->udfs.flags & VALID_UDFS) == 0) { 217 ret = 1; 218 goto close_dev; 219 } 220 221 label(udh, set_flags); 222 223 close_dev: 224 ud_close_dev(udh); 225 ud_fini(udh); 226 227 return (ret); 228 } 229 230 static void 231 usage() 232 { 233 (void) fprintf(stderr, gettext( 234 "udfs usage: labelit [-F udfs] [generic options] " 235 "[ -o specific_options ] special [fsname volume]\n")); 236 (void) fprintf(stderr, gettext( 237 " -o : specific_options : [lvinfo1=string]," 238 "[lvinfo2=string],[lvinfo3=string]\n")); 239 (void) fprintf(stderr, 240 gettext("NOTE that all -o suboptions: must" 241 " be separated only by commas.\n")); 242 exit(1); 243 } 244 245 static void 246 label(ud_handle_t udh, uint32_t set_flags) 247 { 248 if (set_flags == 0) { 249 if (udh->udfs.flags & VALID_MVDS) { 250 print_info(&udh->udfs.mvds, "mvds", udh); 251 } 252 if (udh->udfs.flags & VALID_RVDS) { 253 print_info(&udh->udfs.rvds, "rvds", udh); 254 } 255 return; 256 } else { 257 258 if (udh->udfs.flags & VALID_MVDS) { 259 label_vds(&udh->udfs.mvds, set_flags, udh); 260 } 261 if (udh->udfs.flags & VALID_RVDS) { 262 label_vds(&udh->udfs.rvds, set_flags, udh); 263 } 264 if (((set_flags & (SET_FSNAME | SET_VOLNAME)) == 265 (SET_FSNAME | SET_VOLNAME)) && 266 (udh->udfs.fsd_len != 0)) { 267 struct file_set_desc *fsd; 268 269 off = udh->udfs.fsd_loc * udh->udfs.lbsize; 270 if (ud_read_dev(udh, off, buf, 271 udh->udfs.fsd_len) != 0) { 272 return; 273 } 274 275 /* LINTED */ 276 fsd = (struct file_set_desc *)buf; 277 278 set_dstring(fsd->fsd_lvid, 279 volname, sizeof (fsd->fsd_lvid)); 280 set_dstring(fsd->fsd_fsi, 281 volname, sizeof (fsd->fsd_fsi)); 282 283 ud_make_tag(udh, &fsd->fsd_tag, UD_FILE_SET_DESC, 284 SWAP_32(fsd->fsd_tag.tag_loc), 285 SWAP_16(fsd->fsd_tag.tag_crc_len)); 286 287 (void) ud_write_dev(udh, off, buf, udh->udfs.fsd_len); 288 } 289 } 290 } 291 292 static void 293 print_info(struct vds *v, char *name, ud_handle_t udh) 294 { 295 uint8_t outbuf[BUF_LEN]; 296 297 if (v->pvd_len != 0) { 298 off = v->pvd_loc * udh->udfs.lbsize; 299 if (ud_read_dev(udh, off, buf, 300 sizeof (struct pri_vol_desc)) == 0) { 301 302 struct pri_vol_desc *pvd; 303 304 /* LINTED */ 305 pvd = (struct pri_vol_desc *)buf; 306 307 bzero(outbuf, BUF_LEN); 308 (void) ud_convert2local( 309 (int8_t *)pvd->pvd_vsi, 310 (int8_t *)outbuf, strlen(pvd->pvd_vsi)); 311 (void) fprintf(stdout, 312 gettext("fsname in %s : %s\n"), 313 name, outbuf); 314 315 bzero(outbuf, BUF_LEN); 316 pvd->pvd_vol_id[31] = '\0'; 317 (void) ud_convert2local( 318 (int8_t *)pvd->pvd_vol_id, 319 (int8_t *)outbuf, 320 strlen(pvd->pvd_vol_id)); 321 (void) fprintf(stdout, 322 gettext("volume label in %s : %s\n"), 323 name, outbuf); 324 } 325 } 326 327 if (v->iud_len != 0) { 328 off = v->iud_loc * udh->udfs.lbsize; 329 if (ud_read_dev(udh, off, buf, 330 sizeof (struct iuvd_desc)) == 0) { 331 332 struct iuvd_desc *iud; 333 334 /* LINTED */ 335 iud = (struct iuvd_desc *)buf; 336 bzero(outbuf, BUF_LEN); 337 iud->iuvd_ifo1[35] = '\0'; 338 (void) ud_convert2local( 339 (int8_t *)iud->iuvd_ifo1, 340 (int8_t *)outbuf, 341 strlen(iud->iuvd_ifo1)); 342 (void) fprintf(stdout, 343 gettext("LVInfo1 in %s : %s\n"), 344 name, outbuf); 345 346 bzero(outbuf, BUF_LEN); 347 iud->iuvd_ifo2[35] = '\0'; 348 (void) ud_convert2local( 349 (int8_t *)iud->iuvd_ifo2, 350 (int8_t *)outbuf, 351 strlen(iud->iuvd_ifo2)); 352 (void) fprintf(stdout, 353 gettext("LVInfo2 in %s : %s\n"), 354 name, outbuf); 355 356 bzero(outbuf, BUF_LEN); 357 iud->iuvd_ifo3[35] = '\0'; 358 (void) ud_convert2local( 359 (int8_t *)iud->iuvd_ifo3, 360 (int8_t *)outbuf, 361 strlen(iud->iuvd_ifo3)); 362 (void) fprintf(stdout, 363 gettext("LVInfo3 in %s : %s\n"), 364 name, outbuf); 365 } 366 } 367 } 368 369 /* ARGSUSED */ 370 static void 371 label_vds(struct vds *v, uint32_t set_flags, ud_handle_t udh) 372 { 373 374 if (((set_flags & (SET_FSNAME | SET_VOLNAME)) == 375 (SET_FSNAME | SET_VOLNAME)) && 376 (v->pvd_len)) { 377 378 off = v->pvd_loc * udh->udfs.lbsize; 379 if (ud_read_dev(udh, off, buf, 380 sizeof (struct pri_vol_desc)) == 0) { 381 382 struct pri_vol_desc *pvd; 383 384 /* LINTED */ 385 pvd = (struct pri_vol_desc *)buf; 386 bzero((int8_t *)&pvd->pvd_vsi[9], 119); 387 (void) strncpy((int8_t *)&pvd->pvd_vsi[9], 388 &fsname[1], fsname_len - 1); 389 390 set_dstring(pvd->pvd_vol_id, 391 volname, sizeof (pvd->pvd_vol_id)); 392 393 ud_make_tag(udh, &pvd->pvd_tag, 394 SWAP_16(pvd->pvd_tag.tag_id), 395 SWAP_32(pvd->pvd_tag.tag_loc), 396 SWAP_16(pvd->pvd_tag.tag_crc_len)); 397 398 (void) ud_write_dev(udh, off, buf, 399 sizeof (struct pri_vol_desc)); 400 } 401 } 402 403 if (set_flags && v->iud_len) { 404 405 off = v->iud_loc * udh->udfs.lbsize; 406 if (ud_read_dev(udh, off, buf, 407 sizeof (struct iuvd_desc)) == 0) { 408 409 struct iuvd_desc *iuvd; 410 411 /* LINTED */ 412 iuvd = (struct iuvd_desc *)buf; 413 414 if ((set_flags & SET_VOLNAME) == SET_VOLNAME) { 415 set_dstring(iuvd->iuvd_lvi, 416 volname, sizeof (iuvd->iuvd_lvi)); 417 } 418 if ((set_flags & SET_LVINFO1) == SET_LVINFO1) { 419 set_dstring(iuvd->iuvd_ifo1, 420 lvinfo1_buf, sizeof (iuvd->iuvd_ifo1)); 421 } 422 if ((set_flags & SET_LVINFO2) == SET_LVINFO2) { 423 set_dstring(iuvd->iuvd_ifo2, 424 lvinfo2_buf, sizeof (iuvd->iuvd_ifo2)); 425 } 426 if ((set_flags & SET_LVINFO3) == SET_LVINFO3) { 427 set_dstring(iuvd->iuvd_ifo3, 428 lvinfo3_buf, sizeof (iuvd->iuvd_ifo3)); 429 } 430 431 ud_make_tag(udh, &iuvd->iuvd_tag, 432 SWAP_16(iuvd->iuvd_tag.tag_id), 433 SWAP_32(iuvd->iuvd_tag.tag_loc), 434 SWAP_16(iuvd->iuvd_tag.tag_crc_len)); 435 436 (void) ud_write_dev(udh, off, buf, 437 sizeof (struct iuvd_desc)); 438 } 439 } 440 441 if (((set_flags & (SET_FSNAME | SET_VOLNAME)) == 442 (SET_FSNAME | SET_VOLNAME)) && 443 (v->lvd_len)) { 444 445 off = v->lvd_loc * udh->udfs.lbsize; 446 if (ud_read_dev(udh, off, buf, 447 sizeof (struct log_vol_desc)) == 0) { 448 449 struct log_vol_desc *lvd; 450 451 /* LINTED */ 452 lvd = (struct log_vol_desc *)buf; 453 set_dstring(lvd->lvd_lvid, 454 volname, sizeof (lvd->lvd_lvid)); 455 456 ud_make_tag(udh, &lvd->lvd_tag, 457 SWAP_16(lvd->lvd_tag.tag_id), 458 SWAP_32(lvd->lvd_tag.tag_loc), 459 SWAP_16(lvd->lvd_tag.tag_crc_len)); 460 461 (void) ud_write_dev(udh, off, buf, 462 sizeof (struct log_vol_desc)); 463 } 464 } 465 } 466 467 468 int32_t 469 convert_string(int8_t *value, int8_t *out_buf, int32_t out_len, 470 int32_t len, int8_t *error_string) 471 { 472 int32_t out_length = 0; 473 474 out_length = ud_convert2unicode(value, out_buf, out_len); 475 if (out_length > len - 1) { 476 (void) fprintf(stderr, "%s", error_string); 477 exit(1); 478 } 479 480 return (out_length); 481 } 482 483 static int32_t 484 ud_convert2unicode(int8_t *mb, int8_t *comp, int32_t out_len) 485 { 486 wchar_t buf4c[128]; 487 int32_t len = 0; 488 int32_t i = 0; 489 int32_t j = 0; 490 uint8_t c = 8; 491 492 len = mbstowcs(buf4c, mb, 127); 493 buf4c[127] = '\0'; 494 495 for (i = 0; i < len; i++) { 496 if (buf4c[i] & 0xFFFFFF00) { 497 c = 16; 498 break; 499 } 500 } 501 502 comp[0] = c; 503 j = 1; 504 for (i = 0; i < len && i < out_len; i++) { 505 if (c == 16) { 506 comp[j] = (buf4c[i] & 0xFF00) >> 8; 507 } 508 comp[j++] = buf4c[i] & 0xFF; 509 } 510 511 return (j); 512 } 513