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