blob: 018a538491507756679f92b3e15b34c0559dadfd [file] [log] [blame]
/*
* fs-util A simple generic frontend for the for the fsck and mkfs
* programs under Linux. See the manual pages for details.
*
* Usage: fsck [-AV] [-t fstype] [fs-options] device
* mkfs [-V] [-t fstype] [fs-options] device< [size]
*
* Authors: David Engel, <david@ods.com>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mntent.h>
#include <unistd.h>
#include <getopt.h>
#ifndef DEFAULT_FSTYPE
# define DEFAULT_FSTYPE "minix"
#endif
#define _PATH_PROG "%s.%s"
#define _PROG_FSCK "fsck"
#define EXIT_OK 0
#define EXIT_NONDESTRUCT 1
#define EXIT_DESTRUCT 2
#define EXIT_UNCORRECTED 4
#define EXIT_ERROR 8
#define EXIT_USAGE 16
#define EXIT_LIBRARY 128
static char *Version = "1.8";
static char *ignored_types[] = {
"ignore",
"iso9660",
"msdos",
"nfs",
"proc",
"sw",
"swap",
NULL
};
/* Execute a program. */
int do_exec(char *prog, char **argv, int verbose)
{
char *args[33];
register int i;
int pid, status;
/* Build the vector. */
i = 0;
args[i++] = prog;
while(*argv != NULL && i < 32)
args[i++] = *argv++;
args[i] = NULL;
if (verbose) {
i = 0;
while(args[i] != NULL) {
printf("%s ", args[i]);
i++;
}
printf("\n");
if (verbose > 1)
return EXIT_OK;
}
/* Fork and execute the correct program. */
if ((pid = fork()) < 0) {
perror("fork");
status = EXIT_ERROR;
} else if (pid == 0) {
(void) execvp(args[0], args);
perror(args[0]);
exit(EXIT_ERROR);
} else {
while(wait(&status) != pid)
;
status = WEXITSTATUS(status);
}
return status;
}
/* Check if we have to ignore a file system type. */
int ignore(char *type, char *opts)
{
char *cp;
char **ip;
ip = ignored_types;
while (*ip != NULL) {
if (!strcmp(type, *ip))
return 1;
ip++;
}
for (cp = strtok(opts, ","); cp != NULL; cp = strtok(NULL, ",")) {
if (!strcmp(cp, "noauto"))
return 1;
}
return 0;
}
/* Check all file systems, using the /etc/fstab table. */
int check_all(int verbose, char **argv)
{
char path[PATH_MAX];
char *args[33];
FILE *mntfile;
struct mntent *mp;
register int i;
int status = EXIT_OK;
if (verbose)
printf("Checking all file systems.\n");
/* Create an array of arguments. */
i = 0;
while (*argv != NULL && i < 32)
args[i++] = *argv++;
args[i] = NULL;
args[i + 1] = NULL;
/* Open the mount table. */
if ((mntfile = setmntent(MNTTAB, "r")) == NULL) {
perror(MNTTAB);
exit(EXIT_ERROR);
}
/* Walk through the /etc/fstab file. */
while ((mp = getmntent(mntfile)) != NULL) {
if (verbose)
printf("%-7s %-15s %-15s ", mp->mnt_type,
mp->mnt_fsname, mp->mnt_dir);
if (ignore(mp->mnt_type, mp->mnt_opts)) {
if (verbose)
printf("(ignored)\n");
continue;
}
/* Build program name. */
sprintf(path, _PATH_PROG, _PROG_FSCK, mp->mnt_type);
args[i] = mp->mnt_fsname;
status |= do_exec(path, args, verbose);
}
(void) endmntent(mntfile);
return status;
}
/* Lookup filesys in /etc/fstab and return the corresponding entry. */
struct mntent *lookup(char *filesys)
{
FILE *mntfile;
struct mntent *mp;
/* No filesys name given. */
if (filesys == NULL)
return NULL;
/* Open the mount table. */
if ((mntfile = setmntent(MNTTAB, "r")) == NULL) {
perror(MNTTAB);
exit(EXIT_ERROR);
}
while ((mp = getmntent(mntfile)) != NULL) {
if (!strcmp(filesys, mp->mnt_fsname) ||
!strcmp(filesys, mp->mnt_dir))
break;
}
(void) endmntent(mntfile);
return mp;
}
void usage(int fsck, char *prog)
{
if (fsck) {
fprintf(stderr, "Usage: fsck [-AV] [-t fstype] [fs-options] filesys\n");
} else {
fprintf(stderr, "Usage: mkfs [-V] [-t fstype] [fs-options] filesys [size]\n");
}
exit(EXIT_USAGE);
}
void main(int argc, char *argv[])
{
char path[PATH_MAX];
char *oldpath, newpath[PATH_MAX];
register char *sp;
struct mntent *fsent;
char *fstype = NULL;
int verbose = 0;
int doall = 0;
int i, fsck, more;
/* Must be 1 for "fsck" and 0 for "mkfs". */
if ((sp = strrchr(argv[0], '/')) != NULL)
sp++;
else
sp = argv[0];
if (!strcmp(sp, _PROG_FSCK))
fsck = 1;
else
fsck = 0;
/* Check commandline options. */
opterr = 0;
more = 0;
while ((more == 0) && ((i = getopt(argc, argv, "AVt:")) != EOF))
switch(i) {
case 'A':
doall++;
break;
case 'V':
verbose++;
break;
case 't':
if (optarg == NULL)
usage(fsck, sp);
fstype = optarg;
break;
default:
more = 1;
break; /* start of specific arguments */
}
/* Did we get any specific arguments? */
if (more)
optind--;
/* Print our version number if requested. */
if (verbose)
printf("%s (fsutil) version %s (%s)\n", argv[0],
Version, __DATE__);
/* Update our PATH to include /etc/fs and /etc. */
strcpy(newpath, "PATH=/etc/fs:/etc:");
if ((oldpath = getenv("PATH")) != NULL)
strcat(newpath, oldpath);
putenv(newpath);
/* If -A was specified ("check all"), double-check. */
if (doall) {
if (!fsck || (fstype != NULL))
usage(fsck, sp);
exit(check_all(verbose, &argv[optind]));
} else {
/* If -t wasn't specified, we must deduce fstype. */
if (fstype == NULL) {
/* make sure that "filesys" was specified */
if (optind >= argc)
usage(fsck, sp);
/* then try looking for it in /etc/fstab */
if ((fsent = lookup(argv[argc - 1])) != NULL) {
argv[argc - 1] = fsent->mnt_fsname;
fstype = fsent->mnt_type;
} else {
if (!fsck && optind < argc-1) {
if ((fsent = lookup(argv[argc - 2])) != NULL) {
argv[argc - 2] = fsent->mnt_fsname;
fstype = fsent->mnt_type;
}
}
}
/* if we still don't know, use the default */
if (fstype == NULL) fstype = DEFAULT_FSTYPE;
}
/* Build program name. */
sprintf(path, _PATH_PROG, sp, fstype);
exit(do_exec(path, &argv[optind], verbose));
}
/*NOTREACHED*/
}