xref: /illumos-gate/usr/src/cmd/fs.d/udfs/labelit/labelit.c (revision 90221f9148b67fdc90178b67f9600b7bd4e3bc7c)
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
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
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
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
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
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
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
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