xref: /illumos-gate/usr/src/lib/libadm/common/getvol.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright (c) 1997, by Sun Microsystems, Inc.
28  * All rights reserved.
29  */
30 
31 /*LINTLIBRARY*/
32 
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <devmgmt.h>
37 #include "libadm.h"
38 #include <stdlib.h>
39 
40 #define	LABELSIZ	6
41 #define	BELL	"\007"
42 
43 #define	FORMFS_MSG ",\\n\\ \\ or [f] to format %s and place a filesystem on it"
44 #define	FORMAT_MSG ",\\n\\ \\ or [f] to format the %s"
45 #define	MAKEFS_MSG ",\\n\\ \\ or [m] to place a filesystem on %s"
46 #define	EJECT_MSG  ",\\n\\ \\ or [e] to eject the %s"
47 #define	UNLOAD_MSG ",\\n\\ \\ or [u] to unload/offline the %s"
48 #define	WLABEL_MSG ",\\n\\ \\ or [w] to write a new label on the %s"
49 #define	OLABEL_MSG ",\\n\\ \\ or [o] to use the current label anyway"
50 #define	QUIT_MSG   ",\\n\\ \\ or [q] to quit"
51 
52 #define	ERR_ACCESS	"\n%s (%s) cannot be accessed.\n"
53 #define	ERR_FMT		"\nAttempt to format %s failed.\n"
54 #define	ERR_MKFS	"\nAttempt to place filesystem on %s failed.\n"
55 #define	ERR_REMOVE	"\nExecution of \"removecmd\"[%s] failed.\n"
56 
57 static void	elabel(void);
58 static void	doformat(char *, char *, char *);
59 static void	labelerr(char *, char *);
60 static int	ckilabel(char *, int);
61 static int	insert(char *, char *, int, char *);
62 
63 static char	*cdevice; 	/* character device name */
64 static char	*pname; 	/* device presentation name */
65 static char	*volume; 	/* volume name */
66 static char	origfsname[LABELSIZ+1];
67 static char	origvolname[LABELSIZ+1];
68 
69 /*
70  * Return:
71  *	0 - okay, label matches
72  *	1 - device not accessable
73  *	2 - unknown device (devattr failed)
74  *	3 - user selected quit
75  *	4 - label does not match
76  */
77 
78 /*
79  * macros from labelit to behave correctly for tape
80  * is a kludge, should use devmgmt
81  */
82 #ifdef RT
83 #define	IFTAPE(s) ((strncmp(s, "/dev/mt", 7) == 0) || \
84 (strncmp(s, "mt", 2) == 0))
85 #define	TAPENAMES "'/dev/mt'"
86 #else
87 #define	IFTAPE(s) ((strncmp(s, "/dev/rmt", 8) == 0) || \
88 (strncmp(s, "rmt", 3) == 0) || (strncmp(s, "/dev/rtp", 8) == 0) || \
89 (strncmp(s, "rtp", 3) == 0))
90 #define	TAPENAMES "'/dev/rmt' or '/dev/rtp'"
91 #endif
92 
93 int
94 getvol(char *device, char *label, int options, char *prompt)
95 {
96 	return (_getvol(device, label, options, prompt, NULL));
97 }
98 
99 int
100 _getvol(char *device, char *label, int options, char *prompt, char *norewind)
101 {
102 	FILE	*tmp;
103 	char	*advice, *pt;
104 	int	n, override;
105 
106 	cdevice = devattr(device, "cdevice");
107 	if ((cdevice == NULL) || !cdevice[0]) {
108 		cdevice = devattr(device, "pathname");
109 		if ((cdevice == NULL) || !cdevice)
110 			return (2);	/* bad device */
111 	}
112 
113 	pname = devattr(device, "desc");
114 	if (pname == NULL) {
115 		pname = devattr(device, "alias");
116 		if (!pname)
117 			pname = device;
118 	}
119 
120 	volume = devattr(device, "volume");
121 
122 	if (label) {
123 		(void) strncpy(origfsname, label, LABELSIZ);
124 		origfsname[LABELSIZ] = '\0';
125 		if (pt = strchr(origfsname, ',')) {
126 			*pt = '\0';
127 		}
128 		if (pt = strchr(label, ',')) {
129 			(void) strncpy(origvolname, pt+1, LABELSIZ);
130 			origvolname[LABELSIZ] = '\0';
131 		} else
132 			origvolname[0] = '\0';
133 	}
134 
135 	override = 0;
136 	for (;;) {
137 		if (!(options & DM_BATCH) && volume) {
138 			n = insert(device, label, options, prompt);
139 			if (n < 0)
140 				override++;
141 			else if (n)
142 				return (n);	/* input function failed */
143 		}
144 
145 		if ((tmp = fopen(norewind ? norewind : cdevice, "r")) == NULL) {
146 			/* device was not accessible */
147 			if (options & DM_BATCH)
148 				return (1);
149 			(void) fprintf(stderr, ERR_ACCESS, pname, cdevice);
150 			if ((options & DM_BATCH) || (volume == NULL))
151 				return (1);
152 			/* display advice on how to ready device */
153 			if (advice = devattr(device, "advice"))
154 				(void) puttext(stderr, advice, 0, 0);
155 			continue;
156 		}
157 		(void) fclose(tmp);
158 
159 		/* check label on device */
160 		if (label) {
161 			if (options & DM_ELABEL)
162 				elabel();
163 			else {
164 				/* check internal label using /etc/labelit */
165 				if (ckilabel(label, override)) {
166 					if ((options & DM_BATCH) ||
167 					    volume == NULL)
168 						return (4);
169 					continue;
170 				}
171 			}
172 		}
173 		break;
174 	}
175 	return (0);
176 }
177 
178 static int
179 ckilabel(char *label, int flag)
180 {
181 	FILE	*pp;
182 	char	*pt, *look, buffer[512];
183 	char	fsname[LABELSIZ+1], volname[LABELSIZ+1];
184 	char	*pvolname, *pfsname;
185 	int	n, c;
186 
187 	(void) strncpy(fsname, label, LABELSIZ);
188 	fsname[LABELSIZ] = '\0';
189 	if (pt = strchr(fsname, ',')) {
190 		*pt = '\0';
191 	}
192 	if (pt = strchr(label, ',')) {
193 		(void) strncpy(volname, pt+1, LABELSIZ);
194 		volname[LABELSIZ] = '\0';
195 	} else
196 		volname[0] = '\0';
197 
198 	(void) snprintf(buffer, sizeof (buffer), "/etc/labelit %s", cdevice);
199 	pp = popen(buffer, "r");
200 	pt = buffer;
201 	while ((c = getc(pp)) != EOF)
202 		*pt++ = (char)c;
203 	*pt = '\0';
204 	(void) pclose(pp);
205 
206 	pt = buffer;
207 	pfsname = pvolname = NULL;
208 	look = "Current fsname: ";
209 	n = (int)strlen(look);
210 	while (*pt) {
211 		if (strncmp(pt, look, n) == 0) {
212 			*pt = '\0';
213 			pt += strlen(look);
214 			if (pfsname == NULL) {
215 				pfsname = pt;
216 				look = ", Current volname: ";
217 				n = (int)strlen(look);
218 			} else if (pvolname == NULL) {
219 				pvolname = pt;
220 				look = ", Blocks: ";
221 				n = (int)strlen(look);
222 			} else
223 				break;
224 		} else
225 			pt++;
226 	}
227 
228 	if (strcmp(fsname, pfsname) || strcmp(volname, pvolname)) {
229 		/* mismatched label */
230 		if (flag) {
231 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
232 			(void) sprintf(label, "%s,%s", pfsname, pvolname);
233 		} else {
234 			labelerr(pfsname, pvolname);
235 			return (1);
236 		}
237 	}
238 	return (0);
239 }
240 
241 static int
242 wilabel(char *label)
243 {
244 	char	buffer[512];
245 	char	fsname[LABELSIZ+1];
246 	char	volname[LABELSIZ+1];
247 	int	n;
248 
249 	if (!label || !strlen(origfsname)) {
250 		if (n = ckstr(fsname, NULL, LABELSIZ, NULL, NULL, NULL,
251 				"Enter text for fsname label:"))
252 			return (n);
253 	} else
254 		(void) strcpy(fsname, origfsname);
255 	if (!label || !strlen(origvolname)) {
256 		if (n = ckstr(volname, NULL, LABELSIZ, NULL, NULL, NULL,
257 				"Enter text for volume label:"))
258 			return (n);
259 	} else
260 		(void) strcpy(volname, origvolname);
261 
262 	if (IFTAPE(cdevice)) {
263 		(void) snprintf(buffer, sizeof (buffer),
264 		    "/etc/labelit %s \"%s\" \"%s\" -n 1>&2",
265 			cdevice, fsname, volname);
266 	} else {
267 		(void) snprintf(buffer, sizeof (buffer),
268 		    "/etc/labelit %s \"%s\" \"%s\" 1>&2",
269 		    cdevice, fsname, volname);
270 	}
271 	if (system(buffer)) {
272 		(void) fprintf(stderr, "\nWrite of label to %s failed.", pname);
273 		return (1);
274 	}
275 	if (label)
276 		/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
277 		(void) sprintf(label, "%s,%s", fsname, volname);
278 	return (0);
279 }
280 
281 static void
282 elabel(void)
283 {
284 }
285 
286 static int
287 insert(char *device, char *label, int options, char *prompt)
288 {
289 	int	n;
290 	char	strval[16], prmpt[BUFSIZ];
291 	char	*pt, *keyword[10];
292 	char 	*fmtcmd;
293 	char	*mkfscmd;
294 	char	*voltxt;
295 	char	*removecmd;
296 	char	*dev_type;
297 
298 	voltxt = (volume ? volume : "volume");
299 
300 	fmtcmd    = devattr(device, "fmtcmd");
301 	mkfscmd   = devattr(device, "mkfscmd");
302 	removecmd = devattr(device, "removecmd");
303 	dev_type  = devattr(device, "type");
304 
305 	if (prompt) {
306 		(void) strlcpy(prmpt, prompt, sizeof (prmpt));
307 		for (pt = prmpt; *prompt; ) {
308 			if ((*prompt == '\\') && (prompt[1] == '%'))
309 				prompt++;
310 			else if (*prompt == '%') {
311 				switch (prompt[1]) {
312 				    case 'v':
313 					(void) strcpy(pt, voltxt);
314 					break;
315 
316 				    case 'p':
317 					(void) strcpy(pt, pname);
318 					break;
319 
320 				    default:
321 					*pt = '\0';
322 					break;
323 				}
324 				pt = pt + strlen(pt);
325 				prompt += 2;
326 				continue;
327 			}
328 			*pt++ = *prompt++;
329 		}
330 		*pt = '\0';
331 	} else {
332 		/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
333 		(void) sprintf(prmpt, "Insert a %s into %s.", voltxt, pname);
334 		if (label && (options & DM_ELABEL)) {
335 			(void) strcat(prmpt, " The following external label ");
336 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
337 			(void) sprintf(prmpt+strlen(prmpt),
338 				" should appear on the %s:\\n\\t%s",
339 				voltxt, label);
340 		}
341 		if (label && !(options & DM_ELABEL)) {
342 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
343 			(void) sprintf(prmpt+strlen(prmpt),
344 			    "  The %s should be internally labeled as follows:",
345 			    voltxt);
346 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
347 			(void) sprintf(prmpt+strlen(prmpt),
348 				"\\n\\t%s\\n", label);
349 		}
350 	}
351 
352 	pt = prompt = prmpt + strlen(prmpt);
353 
354 	n = 0;
355 	pt += sprintf(pt, "\\nType [go] when ready");
356 	keyword[n++] = "go";
357 
358 	if (options & DM_FORMFS) {
359 		if (fmtcmd && *fmtcmd && mkfscmd && *mkfscmd) {
360 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
361 			pt += sprintf(pt, FORMFS_MSG, voltxt);
362 			keyword[n++] = "f";
363 		} else if (fmtcmd && *fmtcmd) {
364 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
365 			pt += sprintf(pt, FORMAT_MSG, voltxt);
366 			keyword[n++] = "f";
367 		}
368 		if (mkfscmd && *mkfscmd) {
369 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
370 			pt += sprintf(pt, MAKEFS_MSG, voltxt);
371 			keyword[n++] = "m";
372 		}
373 	} else if (options & DM_FORMAT) {
374 		if (fmtcmd && *fmtcmd) {
375 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
376 			pt += sprintf(pt, FORMAT_MSG, voltxt);
377 			keyword[n++] = "f";
378 		}
379 	}
380 	if (options & DM_WLABEL) {
381 		/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
382 		pt += sprintf(pt, WLABEL_MSG, voltxt);
383 		keyword[n++] = "w";
384 	}
385 	if (options & DM_OLABEL) {
386 		pt += sprintf(pt, OLABEL_MSG);
387 		keyword[n++] = "o";
388 	}
389 	if (removecmd && *removecmd && dev_type && *dev_type) {
390 		if (strcmp(dev_type, "diskette") == 0) {
391 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
392 			pt += sprintf(pt, EJECT_MSG, voltxt);
393 			keyword[n++] = "e";
394 		} else {
395 			/* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
396 			pt += sprintf(pt, UNLOAD_MSG, voltxt);
397 			keyword[n++] = "u";
398 		}
399 	}
400 	keyword[n] = NULL;
401 	if (ckquit)
402 		pt += sprintf(pt, QUIT_MSG);
403 	*pt++ = ':';
404 	*pt = '\0';
405 
406 	pt = prmpt;
407 	(void) fprintf(stderr, BELL);
408 	for (;;) {
409 		if (n = ckkeywd(strval, keyword, NULL, NULL, NULL, pt))
410 			return (n);
411 
412 		pt = prompt; /* next prompt is only partial */
413 		if (*strval == 'f') {
414 			if (options & DM_FORMFS)
415 				doformat(voltxt, fmtcmd, mkfscmd);
416 			else
417 				doformat(voltxt, fmtcmd, NULL);
418 			continue;
419 		} else if (*strval == 'm') {
420 			doformat(voltxt, NULL, mkfscmd);
421 			continue;
422 		} else if (*strval == 'e' || *strval == 'u') {
423 			(void) doremovecmd(device, 1);
424 			continue;
425 		} else if (*strval == 'w') {
426 			(void) wilabel(label);
427 			continue;
428 		} else if (*strval == 'o')
429 			return (-1);
430 		break;
431 	}
432 	return (0);
433 }
434 
435 static void
436 doformat(char *voltxt, char *fmtcmd, char *mkfscmd)
437 {
438 	char	buffer[512];
439 
440 	if (fmtcmd && *fmtcmd) {
441 		(void) fprintf(stderr, "\t[%s]\n", fmtcmd);
442 		(void) snprintf(buffer, sizeof (buffer), "(%s) 1>&2", fmtcmd);
443 		if (system(buffer)) {
444 			(void) fprintf(stderr, ERR_FMT, voltxt);
445 			return;
446 		}
447 	}
448 	if (mkfscmd && *mkfscmd) {
449 		(void) fprintf(stderr, "\t[%s]\n", mkfscmd);
450 		(void) snprintf(buffer, sizeof (buffer), "(%s) 1>&2", mkfscmd);
451 		if (system(buffer)) {
452 			(void) fprintf(stderr, ERR_MKFS, voltxt);
453 			return;
454 		}
455 	}
456 }
457 
458 void
459 doremovecmd(char *device, int echo)
460 {
461 	char 	*removecmd;
462 	char	buffer[512];
463 
464 	if (device && *device) {
465 		removecmd = devattr(device, "removecmd");
466 		if (removecmd && *removecmd) {
467 			if (echo)
468 				(void) fprintf(stderr, "\t[%s]\n", removecmd);
469 			(void) snprintf(buffer, sizeof (buffer),
470 			    "(%s) 1>&2", removecmd);
471 			if (system(buffer)) {
472 				if (echo)
473 					(void) fprintf(stderr, ERR_REMOVE,
474 					removecmd);
475 				return;
476 			}
477 		}
478 	}
479 }
480 
481 static void
482 labelerr(char *fsname, char *volname)
483 {
484 	(void) fprintf(stderr, "\nLabel incorrect.\n");
485 	if (volume)
486 		(void) fprintf(stderr,
487 			"The internal label on the inserted %s is\n", volume);
488 	else
489 		(void) fprintf(stderr, "The internal label for %s is", pname);
490 	(void) fprintf(stderr, "\t%s,%s\n", fsname, volname);
491 }
492