#include <stdio.h>
#include <stdlib.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;
char *fstype = NULL;
char *cbasename;
char *newargv[ARGV_MAX];
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;
int F_flg = 0;
int usgflag = 0;
int fs_flag = 0;
int arg;
extern char *optarg;
extern int optind;
extern int opterr;
size_t strlen();
cbasename = ptr = argv[0];
while (*ptr) {
if (*ptr++ == '/')
cbasename = ptr;
}
if (argc == 1) {
if (strcmp(cbasename, "ncheck") == 0) {
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':
verbose = 1;
break;
case 'F':
F_flg++;
fstype = optarg;
break;
case 'o':
newargv[newargc++] = "-o";
newargv[newargc++] = optarg;
break;
case '?':
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) {
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);
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();
}
exit(0);
}
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);
}
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);
}
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 (wait(&status) == pid) {
ret = WHIBYTE(status);
if (ret > 0) {
exit(ret);
}
}
}
}