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