utilities.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that: (1) source distributions retain this entire copyright
* notice and comment, and (2) distributions including binaries display
* the following acknowledgement: ``This product includes software
* developed by the University of California, Berkeley and its contributors''
* in the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of this
* software. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#define _KERNEL
#include <string.h>
#include <ctype.h>
#include "fsck.h"
#include <errno.h>
char *malloc();
char *mount_point = NULL;
extern int mflag;
extern uint_t largefile_count;
static struct bufarea *alloc_bufarea();
{
case IFDIR:
case IFREG:
case IFBLK:
case IFCHR:
case IFLNK:
case IFSOCK:
case IFIFO:
case IFSHAD:
case IFATTRDIR:
return (1);
default:
if (debug)
return (0);
}
}
{
return (1);
if (debug)
return (0);
}
char *question;
{
char line[80];
if (preen)
pfatal("INTERNAL ERROR: GOT TO reply()");
if (mflag) {
printf("\n");
printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
devname);
exit(39);
}
printf(" no\n\n");
return (0);
}
if (yflag) {
printf(" yes\n\n");
return (1);
}
errexit("\n");
printf("\n");
return (1);
else {
return (0);
}
}
char *loc;
{
int n;
char *p, *lastloc;
p = loc;
if (n == EOF)
return (EOF);
*p++ = n;
}
*p = 0;
return (p - loc);
}
/*
* Malloc buffers and set up cache.
*/
bufinit()
{
int bufcnt, i;
char *bufp;
if (bufp == 0)
errexit("cannot allocate buffer pool\n");
for (i = 0; i < bufcnt; i++) {
if (bp)
if (bufp)
if (i >= MINBUFS)
break;
errexit("cannot allocate buffer pool\n");
}
}
}
/*
* Manage a cache of directory blocks.
*/
struct bufarea *
int size;
{
goto foundit;
break;
bp = alloc_bufarea();
errexit("deadlocked buffer pool\n");
}
/* fall through */
totalreads++;
/*
* Move the buffer to head of link-list if it isn't
* already there.
*/
}
return (bp);
}
int
{
}
}
struct bufarea *
int size;
{
return (bp);
diskreads++;
return (bp);
}
int fd;
{
int i, j;
long size;
return;
return;
size);
}
}
char *mesg;
{
if (preen == 0)
printf("\n");
if (reply("CONTINUE") == 0)
errexit("Program terminated\n");
}
ckfini()
{
int cnt = 0;
/*
* Mark the filesystem bad if a re-check is required.
*/
sbdirty();
}
sbdirty();
}
}
cnt++;
}
if (debug)
printf("cache missed %d of %d (%d%%)\n",
}
int fd;
char *buf;
long size;
{
char *cp;
int i;
int errs;
char msg[256];
}
return (0);
}
errs = 0;
pwarn("THE FOLLOWING SECTORS COULD NOT BE READ:");
errs++;
}
}
printf("\n");
return (errs);
}
int fd;
char *buf;
long size;
{
int i;
int n;
char *cp;
if (fd < 0)
return;
char msg[256];
"WARNING: Attempt to write illegal blkno %lld on %s\n",
if (debug)
return;
}
fsmodified = 1;
return;
}
}
pwarn("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
n = 0;
} else if (n > 0) {
fsmodified = 1;
}
}
printf("\n");
}
/*
* allocate a data block with the specified number of fragments
*/
int frags;
{
int i, j, k;
return (0);
if (testbmap(i + j))
continue;
for (k = 1; k < frags; k++)
if (testbmap(i + j + k))
break;
if (k < frags) {
j += k;
continue;
}
for (k = 0; k < frags; k++)
setbmap(i + j + k);
return (i + j);
}
}
return (0);
}
/*
* Free a previously allocated block
*/
int frags;
{
pass4check(&idesc);
}
/*
* Find a pathname
*/
char *namebuf;
{
int len;
char *cp;
extern int findname();
return;
}
*cp = '\0';
goto namelookup;
}
while (ino != UFSROOTINO) {
break;
}
break;
break;
*--cp = '/';
}
if (ino != UFSROOTINO) {
return;
}
}
void
catch()
{
ckfini();
exit(37);
}
/*
* When preening, allow a single quit to signal
* a special exit after filesystem checks complete
* so that reboot sequence may be interrupted.
*/
void
{
extern returntosingle;
printf("returning to single-user after filesystem check\n");
returntosingle = 1;
}
/*
* Ignore a single quit signal; wait and flush just in case.
* Used by child processes in preen.
*/
void
voidquit()
{
sleep(1);
}
/*
* determine whether an inode should be fixed.
*/
char *msg;
{
case DONTKNOW:
else
if (preen) {
printf(" (SALVAGED)\n");
return (ALTERED);
}
if (reply("SALVAGE") == 0) {
return (0);
}
return (ALTERED);
case FIX:
return (ALTERED);
case NOFIX:
return (0);
default:
}
/* NOTREACHED */
}
/* VARARGS1 */
char *s1;
{
extern void write_altsb(int);
if (errorlocked) {
if (havesb) {
sbdirty();
}
}
exit(39);
}
/*
* An unexpected inconsistency occured.
* Die if preening, otherwise just print message and continue.
*/
/* VARARGS1 */
char *s;
{
if (preen) {
printf("\n");
printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
devname);
if (havesb) {
sbdirty();
}
exit(36);
}
}
/*
* Pwarn just prints a message when not preening,
* or a warning (preceded by filename) when preening.
*/
/* VARARGS1 */
char *s;
{
if (preen)
}
#ifndef lint
/*
* Stub for routines from kernel.
*/
panic(s)
char *s;
{
pfatal("INTERNAL INCONSISTENCY:");
errexit(s);
}
#define CE_PANIC 3
void
int level;
char *s;
{
pfatal("INTERNAL INCONSISTENCY:");
errexit(s);
}
else
printf(s);
}
#endif
/*
* Check to see if unraw version of name is already mounted.
* to see if it is really looks mounted.
*/
char *name;
{
int found = 0;
return (0);
}
continue;
}
else
}
if (mount_point == NULL) {
if (mount_point == NULL) {
printf("fsck: memory allocation"
" failure\n");
exit(39);
}
}
break;
}
}
return (found);
}
/*
* Check to see if name corresponds to an entry in vfstab, and that the entry
* does not have option ro.
*/
char *name;
{
int rw = 1;
return (1);
}
rw = 0;
}
return (rw);
}
/*
* debugclean
*/
{
char s[256];
if (debug == 0)
return;
return;
return;
return;
sprintf(s,
"WARNING: inconsistencies detected on `%s' filesystem %s",
printf("%s\n", s);
}
/*
* updateclean
* Carefully and transparently update the clean flag.
*/
{
int size;
int fsclean;
int fsreclaim;
int fsflags;
int r;
time_t t;
/*
* debug stuff
*/
debugclean();
/*
* set fsclean to its appropriate value
*/
/* if ufs log is not okay, clear it */
fslogbno = 0;
}
/*
* if necessary, update fs_clean and fs_state
*/
switch (fsclean) {
case FSACTIVE:
if (!iscorrupt) {
fsreclaim = 0;
}
break;
case FSCLEAN:
case FSSTABLE:
if (iscorrupt)
else
fsreclaim = 0;
break;
case FSLOG:
if (iscorrupt)
else if (!islog) {
fsreclaim = 0;
} else if (fflag)
fsreclaim = 0;
break;
case FSFIX:
if (errorlocked && !iscorrupt) {
}
break;
default:
if (iscorrupt)
else {
fsreclaim = 0;
}
}
if (largefile_count > 0)
fsflags |= FSLARGEFILES;
else
fsflags &= ~FSLARGEFILES;
/*
* fs is unchanged, do nothing
*/
if (debug)
printf("** largefile count=%d, fs.fs_flags=%x\n",
if (errorlocked) {
if (!do_errorlock(LOCKFS_ULOCK))
"updateclean(unchanged): unlock(LOCKFS_ULOCK) failed\n");
}
return;
}
/*
* if user allows, update superblock state
*/
(reply("FILE SYSTEM STATE IN SUPERBLOCK IS WRONG; FIX") == 0))
return;
(void) time(&t);
if (debug)
printclean();
/*
* if superblock can't be written, return
*/
if (fswritefd < 0)
return;
/*
* read private copy of superblock, update clean flag, and write it
*/
errexit("out of memory");
return;
return;
return;
return;
/*
* 1208040
* If we had to use -b to grab an alternate superblock, then we
* likely had to do so because of unacceptable differences between
* the main and alternate superblocks. SO, we had better update
* the alternate superblock as well, or we'll just fail again
* the next time we attempt to run fsck!
*/
if (bflag) {
return;
return;
}
if (errorlocked) {
if (!do_errorlock(LOCKFS_ULOCK))
"updateclean(changed): unlock(LOCKFS_ULOCK) failed\n");
}
}
/*
* print out clean info
*/
{
char *s;
s = "unknown";
else
case FSACTIVE:
s = "active";
break;
case FSCLEAN:
s = "clean";
break;
case FSSTABLE:
s = "stable";
break;
case FSLOG:
s = "logging";
break;
case FSBAD:
s = "is bad";
break;
case FSFIX:
s = "being fixed";
break;
default:
s = "unknown";
}
if (preen)
pwarn("is %s.\n", s);
else
}
/* see if all numbers */
char *yp;
{
return (0);
yp++;
if (*yp)
return (0);
return (1);
}
is_errorlocked(char *fs)
{
char *mountp;
static char *getmountp(char *);
char *unrawname(char *);
if (!fs)
return (0);
return (0);
if (!mountp) {
return (0);
}
} else {
return (0);
}
if (elock_combuf == NULL) {
(char *)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char));
} else {
}
if (elock_combuf == NULL)
return (0);
if (mountfd < 0) {
return (0);
}
if (!lfp) {
if (!lfp)
return (0);
}
return (0);
return (LOCKFS_IS_ELOCK(lfp));
}
static char *
char *mountp;
int rc;
return (NULL);
}
return (NULL);
} else if (rc == -1) {
return (NULL);
}
return (mountp);
}
do_errorlock(int lock_type)
{
char *buf;
int rc = 0;
if (!elock_combuf)
errexit("do_errorlock(%s, %d): unallocated elock_combuf\n",
errexit("Couldn't alloc memory for temp. lock status buffer\n");
if (!lfp) {
errexit("do_errorlock(%s, %d): lockfs status unallocated\n",
}
switch (lock_type) {
case LOCKFS_ELOCK:
"%s [pid:%d fsck start:%02d/%02d/%02d %02d:%02d:%02d",
else
elock_combuf, pid);
} else {
}
break;
case LOCKFS_ULOCK:
"%s, done:%02d/%02d/%02d %02d:%02d:%02d]",
} else {
}
} else {
}
goto out;
}
break;
default:
break;
}
errno = 0;
pwarn("Another fsck active?\n");
iscorrupt = 0; /* don't go away mad, just go away */
} else {
"do_errorlock(lock_type:%d, %s) failed: errno:%d\n",
}
}
out:
if (buf)
return (rc != -1);
}
/*
* Shadow inode support. To `register' a shadow with a client is to note
* that an inode (the `client') refers to the shadow. See fsck.h for more
* on how the shadowclientinfo and shadowclients structures are used.
*/
static struct shadowclients *
{
struct shadowclients *rc;
errexit("newshadowclient: cannot malloc (1)");
errexit("newshadowclient: cannot malloc (2)");
return (rc);
}
void
{
struct shadowclientinfo *sci;
struct shadowclients *scc;
break;
errexit("registershadowclient: cannot malloc");
sci->totalClients = 0;
}
sci->totalClients++;
}
}
/*
* Allocate more buffer as need arises but allocate one at a time.
* This is done to make sure that fsck does not exit with error if it
* needs more buffer to complete it's task.
*/
static struct bufarea *
{
char *bufp;
if (bp)
if (bufp)
return (NULL);
}
return (bp);
}