xref: /titanic_51/usr/src/cmd/fs.d/switchout.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 1996-2003 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include	<stdio.h>
34 #include 	<limits.h>
35 #include	<locale.h>
36 #include	<libintl.h>
37 #include	<sys/fstyp.h>
38 #include	<errno.h>
39 #include	<sys/vfstab.h>
40 #include	<sys/types.h>
41 #include	<sys/stat.h>
42 #include	<fcntl.h>
43 #include	<string.h>
44 
45 #define	FSTYPE_MAX	8
46 #define	ARGV_MAX	1024
47 #define	VFS_PATH	"/usr/lib/fs"
48 #define	ALT_PATH	"/etc/fs"
49 
50 extern char	*default_fstype();
51 void	stat_snap(char *, char *, char *);
52 char	*special = NULL;  /*  device special name  */
53 char	*fstype = NULL;	  /*  fstype name is filled in here  */
54 char	*cbasename;	  /* name of command */
55 char	*newargv[ARGV_MAX]; 	/* args for the fstype specific command  */
56 char	vfstab[] = VFSTAB;
57 int	newargc = 2;
58 
59 /*
60  * TRANSLATION_NOTE - the usage strings in the c_usgstr[] of the
61  * following structures should be given a translation; the call to gettext
62  * is in the usage() function. The strings are the ones containing
63  * "[-F FSType]".
64  */
65 
66 struct commands {
67 	char *c_basename;
68 	char *c_optstr;
69 	char *c_usgstr[4]; /* make sure as large as largest array size */
70 } cmd_data[] = {
71 	"clri", "F:o:?V",
72 	{
73 		"[-F FSType] [-V] special inumber ...",
74 		NULL
75 	},
76 	"mkfs", "F:o:mb:?V",
77 	{
78 		"[-F FSType] [-V] [-m] [-o specific_options] special ",
79 		"[operands]", NULL
80 	},
81 	"dcopy", "F:o:?V",
82 	{
83 		"[-F FSType] [-V] special inumber ...",
84 		NULL
85 	},
86 	"fsdb", "F:o:z:?V",
87 	{
88 		"[-F FSType] [-V] [-o specific_options] special",
89 		NULL
90 	},
91 	"fssnap", "F:dio:?V",
92 	{
93 		"[-F FSType] [-V] -o special_options  /mount/point",
94 		"-d [-F FSType] [-V] /mount/point | dev",
95 		"-i [-F FSType] [-V] [-o special-options] [/mount/point | dev]",
96 		NULL
97 	},
98 	"labelit", "F:o:?nV",
99 	{
100 		"[-F FSType] [-V] [-o specific_options] special [operands]",
101 		NULL
102 	},
103 	NULL, "F:o:?V",
104 	{
105 		"[-F FSType] [-V] [-o specific_options] special [operands]",
106 		NULL
107 	}
108 };
109 struct 	commands *c_ptr;
110 
111 main(argc, argv)
112 int	argc;
113 char	*argv[];
114 {
115 	register char *ptr;
116 	char	full_path[PATH_MAX];
117 	char	*vfs_path = VFS_PATH;
118 	char	*alt_path = ALT_PATH;
119 	int	i;
120 	int	verbose = 0;		/* set if -V is specified */
121 	int	F_flg = 0;
122 	int	mflag = 0;
123 	char	*oopts = NULL;
124 	int	iflag = 0;
125 	int	usgflag = 0;
126 	int	arg;			/* argument from getopt() */
127 	extern	char *optarg;		/* getopt specific */
128 	extern	int optind;
129 	extern	int opterr;
130 
131 	(void) setlocale(LC_ALL, "");
132 
133 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
134 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
135 #endif
136 
137 	(void) textdomain(TEXT_DOMAIN);
138 
139 	cbasename = ptr = argv[0];
140 	while (*ptr) {
141 		if (*ptr++ == '/')
142 			cbasename = ptr;
143 	}
144 
145 
146 	if (argc == 1) {
147 		for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) &&
148 		    (strcmp(c_ptr->c_basename, cbasename) != 0)); c_ptr++)
149 		;
150 		usage(cbasename, c_ptr->c_usgstr);
151 		exit(2);
152 	}
153 
154 	for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) &&
155 	    (strcmp(c_ptr->c_basename, cbasename) != 0));  c_ptr++)
156 		;
157 	while ((arg = getopt(argc, argv, c_ptr->c_optstr)) != -1) {
158 			switch (arg) {
159 			case 'V':	/* echo complete command line */
160 				verbose = 1;
161 				break;
162 			case 'F':	/* FSType specified */
163 				F_flg++;
164 				fstype = optarg;
165 				break;
166 			case 'o':	/* FSType specific arguments */
167 				newargv[newargc++] = "-o";
168 				newargv[newargc++] = optarg;
169 				oopts = optarg;
170 				break;
171 			case '?':	/* print usage message */
172 				newargv[newargc++] = "-?";
173 				usgflag = 1;
174 				break;
175 			case 'm':	/* FSType specific arguments */
176 				mflag = 1;
177 				newargv[newargc] = (char *)malloc(3);
178 				sprintf(newargv[newargc++], "-%c", arg);
179 				if (optarg)
180 					newargv[newargc++] = optarg;
181 				break;
182 			case 'i': /* fssnap only */
183 				iflag = 1;
184 				/*FALLTHROUGH*/
185 			default:
186 				newargv[newargc] = (char *)malloc(3);
187 				sprintf(newargv[newargc++], "-%c", arg);
188 				if (optarg)
189 					newargv[newargc++] = optarg;
190 				break;
191 			}
192 			optarg = NULL;
193 	}
194 	if (F_flg > 1) {
195 		fprintf(stderr, gettext("%s: more than one FSType specified\n"),
196 			cbasename);
197 		usage(cbasename, c_ptr->c_usgstr);
198 		exit(2);
199 	}
200 	if (fstype != NULL) {
201 		if (strlen(fstype) > FSTYPE_MAX) {
202 			fprintf(stderr,
203 			    gettext("%s: FSType %s exceeds %d characters\n"),
204 			    cbasename, fstype, FSTYPE_MAX);
205 			exit(2);
206 		}
207 	}
208 
209 	/*  perform a lookup if fstype is not specified  */
210 	special = argv[optind];
211 	optind++;
212 
213 	/* handle -i (fssnap command only) */
214 	if (iflag) {
215 		int diff = argc - optind;
216 		/*
217 		 * There is no reason to ever call a file system specific
218 		 * version since its all in kstats.
219 		 */
220 		if (diff > 0) /* gave more than one mountpoint or device */
221 			usage(cbasename, c_ptr->c_usgstr);
222 		stat_snap(cbasename, diff == 0 ? argv[argc-1] : NULL, oopts);
223 		exit(0);
224 	}
225 
226 	if ((special == NULL) && (!usgflag)) {
227 		fprintf(stderr, gettext("%s: special not specified\n"),
228 		    cbasename);
229 		usage(cbasename, c_ptr->c_usgstr);
230 		exit(2);
231 	}
232 	if ((fstype == NULL) && (usgflag))
233 		usage(cbasename, c_ptr->c_usgstr);
234 	if (fstype == NULL)
235 		lookup();
236 	if (fstype == NULL) {
237 		fprintf(stderr, gettext("%s: FSType cannot be identified\n"),
238 			cbasename);
239 		usage(cbasename, c_ptr->c_usgstr);
240 		exit(2);
241 	}
242 	newargv[newargc++] = special;
243 	for (; optind < argc; optind++)
244 		newargv[newargc++] = argv[optind];
245 
246 	/*  build the full pathname of the fstype dependent command  */
247 	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, cbasename);
248 
249 	newargv[1] = cbasename;
250 
251 	if (verbose) {
252 		printf("%s -F %s ", cbasename, fstype);
253 		for (i = 2; newargv[i]; i++)
254 			printf("%s ", newargv[i]);
255 		printf("\n");
256 		exit(0);
257 	}
258 
259 	/*
260 	 *  Execute the FSType specific command.
261 	 */
262 	execv(full_path, &newargv[1]);
263 	if ((errno == ENOENT) || (errno == EACCES)) {
264 		/*  build the alternate pathname */
265 		sprintf(full_path, "%s/%s/%s", alt_path, fstype, cbasename);
266 		if (verbose) {
267 			printf("%s -F %s ", cbasename, fstype);
268 			for (i = 2; newargv[i]; i++)
269 				printf("%s ", newargv[i]);
270 			printf("\n");
271 			exit(0);
272 		}
273 		execv(full_path, &newargv[1]);
274 	}
275 	if (errno == ENOEXEC) {
276 		newargv[0] = "sh";
277 		newargv[1] = full_path;
278 		execv("/sbin/sh", &newargv[0]);
279 	}
280 	if (errno != ENOENT) {
281 		perror(cbasename);
282 		fprintf(stderr, gettext("%s: cannot execute %s\n"), cbasename,
283 		    full_path);
284 		exit(2);
285 	}
286 
287 	if (sysfs(GETFSIND, fstype) == (-1)) {
288 		fprintf(stderr,
289 		    gettext("%s: FSType %s not installed in the kernel\n"),
290 		    cbasename, fstype);
291 		exit(2);
292 	}
293 	fprintf(stderr,
294 	    gettext("%s: Operation not applicable for FSType %s \n"),
295 	    cbasename, fstype);
296 	exit(2);
297 }
298 
299 usage(cmd, usg)
300 char *cmd;
301 char **usg;
302 {
303 	int i;
304 	fprintf(stderr, gettext("Usage:\n"));
305 	for (i = 0; usg[i] != NULL; i++)
306 		fprintf(stderr, "%s %s\n", gettext(cmd), gettext(usg[i]));
307 	exit(2);
308 }
309 
310 
311 /*
312  *  This looks up the /etc/vfstab entry given the device 'special'.
313  *  It is called when the fstype is not specified on the command line.
314  *
315  *  The following global variables are used:
316  *	special, fstype
317  */
318 
319 lookup()
320 {
321 	FILE	*fd;
322 	int	ret;
323 	struct vfstab	vget, vref;
324 
325 	if ((fd = fopen(vfstab, "r")) == NULL) {
326 		fprintf(stderr, gettext("%s: cannot open vfstab\n"), cbasename);
327 		exit(1);
328 	}
329 	vfsnull(&vref);
330 	vref.vfs_special = special;
331 	ret = getvfsany(fd, &vget, &vref);
332 	if (ret == -1) {
333 		rewind(fd);
334 		vfsnull(&vref);
335 		vref.vfs_fsckdev = special;
336 		ret = getvfsany(fd, &vget, &vref);
337 	}
338 	fclose(fd);
339 
340 	switch (ret) {
341 	case -1:
342 		fstype = default_fstype(special);
343 		break;
344 	case 0:
345 		fstype = vget.vfs_fstype;
346 		break;
347 	case VFS_TOOLONG:
348 		fprintf(stderr,
349 		    gettext("%s: line in vfstab exceeds %d characters\n"),
350 		    cbasename, VFS_LINE_MAX-2);
351 		exit(1);
352 		break;
353 	case VFS_TOOFEW:
354 		fprintf(stderr,
355 		    gettext("%s: line in vfstab has too few entries\n"),
356 		    cbasename);
357 		exit(1);
358 		break;
359 	}
360 }
361 
362 void
363 stat_snap(cmd, mountpoint, opts)
364 char *cmd;
365 char *mountpoint;
366 char *opts;
367 {
368 	int fd; /* check mount point if given */
369 	int en;
370 	char *errstr;
371 
372 	if (mountpoint) {
373 		if ((fd = open(mountpoint, O_RDONLY)) < 0) {
374 			en = errno;
375 			errstr = strerror(errno);
376 			if (errstr == NULL)
377 				errstr = gettext("Unknown error");
378 
379 			fprintf(stderr, gettext("%s: %s: error %d: %s\n"),
380 				cmd, mountpoint, en, errstr);
381 
382 			exit(2);
383 		}
384 		close(fd);
385 	}
386 	fssnap_show_status(mountpoint, opts, 1, (opts ? 0 : 1));
387 }
388