OpenSolaris_b135/cmd/fs.d/ff.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
/*	  All Rights Reserved  	*/


/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include	<stdio.h>
#include 	<limits.h>
#include	<string.h>
#include	<sys/fstyp.h>
#include	<errno.h>
#include	<sys/vfstab.h>
#include	<sys/wait.h>
#include	<sys/types.h>

#define	FSTYPE_MAX	8
#define	FULLPATH_MAX	64
#define	ARGV_MAX	1024
#define	VFS_PATH	"/usr/lib/fs"

extern char	*default_fstype();

char	*special = NULL;  /*  device special name  */
char	*fstype = NULL;	  /*  fstype name is filled in here  */
char	*cbasename;	  /* name of command */
char	*newargv[ARGV_MAX]; 	/* args for the fstype specific command  */
char	vfstab[] = VFSTAB;
	char	full_path[FULLPATH_MAX];
	char	*vfs_path = VFS_PATH;
int	newargc = 2;

struct commands {
	char *c_basename;
	char *c_optstr;
	char *c_usgstr;
} cmd_data[] = {
	"ff", "F:o:p:a:m:c:n:i:?IlsuV",
	"[-F FSType] [-V] [current_options] [-o specific_options] special ...",
	"ncheck", "F:o:?i:asV",
"[-F FSType] [-V] [current_options] [-o specific_options] [special ...]",
	NULL, "F:o:?V",
	"[-F FSType] [-V] [current_options] [-o specific_options] special ..."
	};
struct 	commands *c_ptr;

static void usage(char *cmd, char *usg);
static void exec_specific(void);
static void lookup(void);

int
main(int argc, char *argv[])
{
	FILE *fp;
	struct vfstab	vfsbuf;
	char *ptr;
	int	i;
	int	verbose = 0;		/* set if -V is specified */
	int	F_flg = 0;
	int	usgflag = 0;
	int	fs_flag = 0;
	int	arg;			/* argument from getopt() */
	extern	char *optarg;		/* getopt specific */
	extern	int optind;
	extern	int opterr;
	size_t	strlen();

	cbasename = ptr = argv[0];
	while (*ptr) {
		if (*ptr++ == '/')
			cbasename = ptr;
	}
	/*
	 * If there are no arguments and command is ncheck then the generic
	 * reads the VFSTAB and executes the specific module of
	 * each entry which has a numeric fsckpass field.
	 */

	if (argc == 1) {		/* no arguments or options */
		if (strcmp(cbasename, "ncheck") == 0) {
			/* open VFSTAB */
			if ((fp = fopen(VFSTAB, "r")) == NULL) {
				fprintf(stderr, "%s: cannot open vfstab\n",
				    cbasename);
				exit(2);
			}
			while ((i = getvfsent(fp, &vfsbuf)) == 0) {
				if (numbers(vfsbuf.vfs_fsckpass)) {
					fstype = vfsbuf.vfs_fstype;
					newargv[newargc]  = vfsbuf.vfs_special;
					exec_specific();
				}
			}
			exit(0);
		}
		fprintf(stderr, "Usage:\n");
		fprintf(stderr,
"%s [-F FSType] [-V] [current_options] [-o specific_options] special ...\n",
		    cbasename);
		exit(2);
	}

	for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) &&
	    (strcmp(c_ptr->c_basename, cbasename) != 0));  c_ptr++)
		;
	while ((arg = getopt(argc, argv, c_ptr->c_optstr)) != -1) {
			switch (arg) {
			case 'V':	/* echo complete command line */
				verbose = 1;
				break;
			case 'F':	/* FSType specified */
				F_flg++;
				fstype = optarg;
				break;
			case 'o':	/* FSType specific arguments */
				newargv[newargc++] = "-o";
				newargv[newargc++] = optarg;
				break;
			case '?':	/* print usage message */
				newargv[newargc++] = "-?";
				usgflag = 1;
				break;
			default:
				newargv[newargc] = (char *)malloc(3);
				sprintf(newargv[newargc++], "-%c", arg);
				if (optarg)
					newargv[newargc++] = optarg;
				break;
			}
			optarg = NULL;
	}
	if (F_flg > 1) {
		fprintf(stderr, "%s: more than one FSType specified\n",
			cbasename);
		usage(cbasename, c_ptr->c_usgstr);
	}
	if (F_flg && (strlen(fstype) > (size_t)FSTYPE_MAX)) {
		fprintf(stderr, "%s: FSType %s exceeds %d characters\n",
			cbasename, fstype, FSTYPE_MAX);
		exit(2);
	}
	if (optind == argc) {
		/* all commands except ncheck must exit now */
		if (strcmp(cbasename, "ncheck") != 0) {
			if ((F_flg) && (usgflag)) {
				exec_specific();
				exit(0);
			}
			usage(cbasename, c_ptr->c_usgstr);
		}
		if ((F_flg) && (usgflag)) {
			exec_specific();
			exit(0);
		}
		if (usgflag)
			usage(cbasename, c_ptr->c_usgstr);

		/* open VFSTAB */
		if ((fp = fopen(VFSTAB, "r")) == NULL) {
			fprintf(stderr, "%s: cannot open vfstab\n", cbasename);
			exit(2);
		}
		while ((i = getvfsent(fp, &vfsbuf)) == 0) {
			if (!numbers(vfsbuf.vfs_fsckpass))
				continue;
			if ((F_flg) && (strcmp(fstype, vfsbuf.vfs_fstype) != 0))
				continue;
			fs_flag++;
			fstype = vfsbuf.vfs_fstype;
			newargv[newargc] = vfsbuf.vfs_special;
			if (verbose) {
				printf("%s -F %s ", cbasename,
				    vfsbuf.vfs_fstype);
				for (i = 2; newargv[i]; i++)
					printf("%s\n", newargv[i]);
				continue;
			}
			exec_specific();
		}
		/*
		 * if (! fs_flag) {
		 *	if (sysfs(GETFSIND, fstype) == (-1)) {
		 *		fprintf(stderr,
		 *		"%s: FSType %s not installed in the kernel\n",
		 *			cbasename, fstype);
		 *		exit(1);
		 *	}
		 * }
		 */

		exit(0);
	}

	/* All other arguments must be specials */
	/*  perform a lookup if fstype is not specified  */

	for (; optind < argc; optind++)  {
		newargv[newargc] = argv[optind];
		special = newargv[newargc];
		if ((F_flg) && (usgflag)) {
			exec_specific();
			exit(0);
		}
		if (usgflag)
			usage(cbasename, c_ptr->c_usgstr);
		if (fstype == NULL)
			lookup();
		if (verbose) {
			printf("%s -F %s ", cbasename, fstype);
			for (i = 2; newargv[i]; i++)
				printf("%s ", newargv[i]);
			printf("\n");
			continue;
		}
		exec_specific();
		if (!F_flg)
			fstype = NULL;
	}
	return (0);
}

/* see if all numbers */
int
numbers(char *yp)
{
	if (yp == NULL)
		return (0);
	while ('0' <= *yp && *yp <= '9')
		yp++;
	if (*yp)
		return (0);
	return (1);
}

static void
usage(char *cmd, char *usg)
{
	fprintf(stderr, "Usage:\n");
	fprintf(stderr, "%s %s\n", cmd, usg);
	exit(2);
}


/*
 *  This looks up the /etc/vfstab entry given the device 'special'.
 *  It is called when the fstype is not specified on the command line.
 *
 *  The following global variables are used:
 *	special, fstype
 */

static void
lookup(void)
{
	FILE	*fd;
	int	ret;
	struct vfstab	vget, vref;

	if ((fd = fopen(vfstab, "r")) == NULL) {
		fprintf(stderr, "%s: cannot open vfstab\n", cbasename);
		exit(1);
	}
	vfsnull(&vref);
	vref.vfs_special = special;
	ret = getvfsany(fd, &vget, &vref);
	if (ret == -1) {
		rewind(fd);
		vfsnull(&vref);
		vref.vfs_fsckdev = special;
		ret = getvfsany(fd, &vget, &vref);
	}
	fclose(fd);

	switch (ret) {
	case -1:
		fstype = default_fstype(special);
		break;
	case 0:
		fstype = vget.vfs_fstype;
		break;
	case VFS_TOOLONG:
		fprintf(stderr, "%s: line in vfstab exceeds %d characters\n",
			cbasename, VFS_LINE_MAX-2);
		exit(1);
		break;
	case VFS_TOOFEW:
		fprintf(stderr, "%s: line in vfstab has too few entries\n",
			cbasename);
		exit(1);
		break;
	case VFS_TOOMANY:
		fprintf(stderr, "%s: line in vfstab has too many entries\n",
			cbasename);
		exit(1);
		break;
	}
}

static void
exec_specific(void)
{
int status, pid, ret;

	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, cbasename);
	newargv[1] = &full_path[FULLPATH_MAX];
	while (*newargv[1]-- != '/');
	newargv[1] += 2;
	switch (pid = fork()) {
	case 0:
		execv(full_path, &newargv[1]);
		if (errno == ENOEXEC) {
			newargv[0] = "sh";
			newargv[1] = full_path;
			execv("/sbin/sh", &newargv[0]);
		}
		if (errno != ENOENT) {
			perror(cbasename);
			fprintf(stderr, "%s: cannot execute %s\n", cbasename,
			    full_path);
			exit(1);
		}
		if (sysfs(GETFSIND, fstype) == (-1)) {
			fprintf(stderr,
				"%s: FSType %s not installed in the kernel\n",
				cbasename, fstype);
			exit(1);
		}
		fprintf(stderr, "%s: operation not applicable for FSType %s\n",
		    cbasename, fstype);
		exit(1);
	case -1:
		fprintf(stderr, "%s: cannot fork process\n", cbasename);
		exit(2);
	default:
		/*
		 * if cannot exec specific, or fstype is not installed, exit
		 * after first 'exec_specific' to avoid printing duplicate
		 * error messages
		 */

		if (wait(&status) == pid) {
			ret = WHIBYTE(status);
			if (ret > 0) {
				exit(ret);
			}
		}
	}
}