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