#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <malloc.h>
#include <ustat.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/mntent.h>
#include <sys/vnode.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mnttab.h>
#include <sys/signal.h>
#include <sys/vfstab.h>
#include <sys/fs/udf_volume.h>
#include "fsck.h"
#include <locale.h>
int debug;
char nflag;
char yflag;
int rflag;
static int wflag;
int fflag;
static int sflag;
int isdirty;
int fsmodified;
int iscorrupt;
int exitstat;
uint32_t part_len;
daddr_t n_blks;
daddr_t n_files;
daddr_t n_dirs;
char preen;
char mountpoint[100];
char mountedfs;
char *devname;
struct log_vol_int_desc *lvintp;
extern int32_t writable(char *);
extern void pfatal(char *, ...);
extern void printfree();
extern void pwarn(char *, ...);
extern void pass1();
extern void dofreemap();
extern void dolvint();
extern char *getfullblkname();
extern char *getfullrawname();
static int mflag = 0;
char *mntopt();
void catch(), catchquit(), voidquit();
int returntosingle;
static void checkfilesys();
static void check_sanity();
static void usage();
static char *subopts [] = {
#define PREEN 0
"p",
#define DEBUG 1
"d",
#define READ_ONLY 2
"r",
#define ONLY_WRITES 3
"w",
#define FORCE 4
"f",
#define STATS 5
"s",
NULL
};
uint32_t ecma_version = 2;
int
main(int argc, char *argv[])
{
int c;
char *suboptions, *value;
int suboption;
(void) setlocale(LC_ALL, "");
while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) {
switch (c) {
case 'm':
mflag++;
break;
case 'n':
case 'N':
nflag++;
yflag = 0;
break;
case 'o':
suboptions = optarg;
while (*suboptions != '\0') {
suboption = getsubopt(&suboptions,
subopts, &value);
switch (suboption) {
case PREEN:
preen++;
break;
case DEBUG:
debug++;
break;
case READ_ONLY:
break;
case ONLY_WRITES:
wflag++;
break;
case FORCE:
fflag++;
break;
case STATS:
sflag++;
break;
default:
usage();
}
}
break;
case 'V':
{
int opt_count;
char *opt_text;
(void) fprintf(stdout, "fsck -F udfs ");
for (opt_count = 1; opt_count < argc;
opt_count++) {
opt_text = argv[opt_count];
if (opt_text)
(void) fprintf(stdout, " %s ",
opt_text);
}
(void) fprintf(stdout, "\n");
}
break;
case 'y':
case 'Y':
yflag++;
nflag = 0;
break;
case '?':
usage();
}
}
argc -= optind;
argv = &argv[optind];
rflag++;
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
(void) signal(SIGINT, catch);
}
if (preen) {
(void) signal(SIGQUIT, catchquit);
}
if (argc) {
while (argc-- > 0) {
if (wflag && !writable(*argv)) {
(void) fprintf(stderr,
gettext("not writeable '%s'\n"), *argv);
argv++;
} else
checkfilesys(*argv++);
}
exit(exitstat);
}
return (0);
}
static void
checkfilesys(char *filesys)
{
char *devstr;
mountedfs = 0;
iscorrupt = 1;
if ((devstr = setup(filesys)) == 0) {
if (iscorrupt == 0)
return;
if (preen)
pfatal(gettext("CAN'T CHECK FILE SYSTEM."));
if ((exitstat == 0) && (mflag))
exitstat = 32;
exit(exitstat);
}
else
devname = devstr;
if (mflag)
check_sanity(filesys);
iscorrupt = 0;
if (preen == 0) {
if (mountedfs)
(void) printf(gettext("** Currently Mounted on %s\n"),
mountpoint);
if (mflag) {
(void) printf(
gettext("** Phase 1 - Sanity Check only\n"));
return;
} else
(void) printf(
gettext("** Phase 1 - Check Directories "
"and Blocks\n"));
}
pass1();
if (sflag) {
if (preen)
(void) printf("%s: ", devname);
else
(void) printf("** ");
}
if (debug)
(void) printf("pass1 isdirty %d\n", isdirty);
if (debug)
printfree();
dofreemap();
dolvint();
pwarn(gettext("%d files, %d dirs, %d used, %d free\n"), n_files, n_dirs,
n_blks, part_len - n_blks);
if (iscorrupt)
exitstat = 36;
if (!fsmodified)
return;
if (!preen)
(void) printf(
gettext("\n***** FILE SYSTEM WAS MODIFIED *****\n"));
if (mountedfs) {
exitstat = 40;
}
}
static void
check_sanity(char *filename)
{
struct stat stbd, stbr;
struct ustat usb;
char *devname;
struct vfstab vfsbuf;
FILE *vfstab;
int is_root = 0;
int is_usr = 0;
int is_block = 0;
if (stat(filename, &stbd) < 0) {
(void) fprintf(stderr,
gettext("udfs fsck: sanity check failed : cannot stat "
"%s\n"), filename);
exit(34);
}
if ((stbd.st_mode & S_IFMT) == S_IFBLK)
is_block = 1;
else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
is_block = 0;
else {
(void) fprintf(stderr,
gettext("udfs fsck: sanity check failed: %s not "
"block or character device\n"), filename);
exit(34);
}
if ((vfstab = fopen(VFSTAB, "r")) != 0) {
if (getvfsfile(vfstab, &vfsbuf, "/") == 0) {
if (is_block)
devname = vfsbuf.vfs_special;
else
devname = vfsbuf.vfs_fsckdev;
if (stat(devname, &stbr) == 0)
if (stbr.st_rdev == stbd.st_rdev)
is_root = 1;
}
if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) {
if (is_block)
devname = vfsbuf.vfs_special;
else
devname = vfsbuf.vfs_fsckdev;
if (stat(devname, &stbr) == 0)
if (stbr.st_rdev == stbd.st_rdev)
is_usr = 1;
}
}
if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
(void) fprintf(stderr,
gettext("udfs fsck: sanity check: %s "
"already mounted\n"), filename);
exit(33);
}
if (lvintp->lvid_int_type == LVI_CLOSE) {
(void) fprintf(stderr,
gettext("udfs fsck: sanity check: %s okay\n"),
filename);
} else {
(void) fprintf(stderr,
gettext("udfs fsck: sanity check: %s needs checking\n"),
filename);
exit(32);
}
exit(0);
}
char *
unrawname(char *name)
{
char *dp;
if ((dp = getfullblkname(name)) == NULL)
return ("");
return (dp);
}
char *
rawname(char *name)
{
char *dp;
if ((dp = getfullrawname(name)) == NULL)
return ("");
return (dp);
}
char *
hasvfsopt(struct vfstab *vfs, char *opt)
{
char *f, *opts;
static char *tmpopts;
if (vfs->vfs_mntopts == NULL)
return (NULL);
if (tmpopts == 0) {
tmpopts = (char *)calloc(256, sizeof (char));
if (tmpopts == 0)
return (0);
}
(void) strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1));
opts = tmpopts;
f = mntopt(&opts);
for (; *f; f = mntopt(&opts)) {
if (strncmp(opt, f, strlen(opt)) == 0)
return (f - tmpopts + vfs->vfs_mntopts);
}
return (NULL);
}
static void
usage()
{
(void) fprintf(stderr, gettext("udfs usage: fsck [-F udfs] "
"[generic options] [-o p,w,s] [special ....]\n"));
exit(31+1);
}