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