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