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