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
main(int32_t argc,char * argv[])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
usage()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
label(ud_handle_t udh,uint32_t set_flags)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
print_info(struct vds * v,char * name,ud_handle_t udh)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
label_vds(struct vds * v,uint32_t set_flags,ud_handle_t udh)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
convert_string(int8_t * value,int8_t * out_buf,int32_t out_len,int32_t len,int8_t * error_string)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
ud_convert2unicode(int8_t * mb,int8_t * comp,int32_t out_len)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