/*
*/
/* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <libadm.h>
#include <note.h>
#define _KERNEL
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/efi_partition.h>
#include <fslib.h>
#include <inttypes.h>
#include "fsck.h"
static struct bufarea *alloc_bufarea(void);
static void debugclean(void);
static void freelogblk(daddr32_t);
static diskaddr_t brute_force_get_device_size(int);
int
{
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);
}
}
int
{
return (1);
if (debug)
(void) printf("bad file type for acl I=%d: 0%o\n",
return (0);
}
int
{
if (preen)
pfatal("INTERNAL ERROR: GOT TO reply() in preen mode");
if (mflag) {
/*
* We don't know what's going on, so don't potentially
* make things worse by having errexit() write stuff
* out to disk.
*/
(void) printf(
"\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
devname);
}
(void) putchar('\n');
(void) putchar('?');
(void) putchar(' ');
(void) printf(" no\n\n");
return (0);
}
if (yflag) {
(void) printf(" yes\n\n");
return (1);
}
errexit("\n");
(void) printf("\n");
return (1);
} else {
return (0);
}
}
int
{
int n;
p = loc;
if (n == EOF)
return (EOF);
*p++ = (char)n;
}
*p = '\0';
/* LINTED pointer difference won't overflow */
return (p - loc);
}
/*
* Malloc buffers and set up cache.
*/
void
bufinit(void)
{
int bufcnt, i;
goto nomem;
for (i = 0; i < bufcnt; i++) {
if (i >= MINBUFS)
goto noalloc;
goto nomem;
}
if (i >= MINBUFS)
goto noalloc;
goto nomem;
}
}
return;
errexit("cannot allocate buffer pool\n");
/* NOTREACHED */
}
/*
* Undo a bufinit().
*/
void
unbufinit(void)
{
int cnt;
cnt = 0;
cnt++;
/*
* We're discarding the entire chain, so this isn't
* technically necessary. However, it doesn't hurt
* and lint's data flow analysis is much happier
* (this prevents it from thinking there's a chance
* of our using memory elsewhere after it's been released).
*/
}
errexit("Panic: cache lost %d buffers\n",
}
/*
* Manage a cache of directory blocks.
*/
struct bufarea *
{
goto foundit;
}
break;
bp = alloc_bufarea();
errexit("deadlocked buffer pool\n");
/* NOTREACHED */
}
}
/*
* We're at the same logical level as getblk(), so if there
* are any errors, we'll let our caller handle them.
*/
diskreads++;
totalreads++;
/*
* Move the buffer to head of linked list if it isn't
* already there.
*/
}
return (bp);
}
void
{
}
}
struct bufarea *
{
return (bp);
return (bp);
}
void
{
int i, j;
long size;
return;
/*
* It's not our buf, so if there are errors, let whoever
* acquired it deal with the actual problem.
*/
return;
}
/*
* We're flushing the superblock, so make sure all the
* ancillary bits go out as well.
*/
size);
}
}
static void
{
if (!preen)
(void) printf("\n");
if (rval == -1)
pfatal("CANNOT %s: DISK BLOCK %lld: %s",
else
if (reply("CONTINUE") == 0) {
errexit("Program terminated\n");
}
}
void
ckfini(void)
{
if (fswritefd < 0)
return;
/*
* Were we using a backup superblock?
*/
sbdirty();
}
}
}
unbufinit();
if (debug) {
/*
* Note that we only count cache-related reads.
* Anything that called fsck_bread() or getblk()
* directly are explicitly not cached, so they're not
* included here.
*/
if (totalreads != 0)
else
percentage = 0;
(void) printf("cache missed %lld of %lld reads (%lld%%)\n",
}
fsreadfd = -1;
fswritefd = -1;
}
int
{
int i;
int errs;
/*
* In our universe, nothing exists before the superblock, so
* just pretend it's always zeros. This is the complement of
* bwrite()'s ignoring write requests into that space.
*/
if (debug)
(void) printf(
"WARNING: fsck_bread() passed blkno < %d (%lld)\n",
return (1);
}
}
return (0);
}
}
errs = 0;
pwarn("THE FOLLOWING SECTORS COULD NOT BE READ:");
iscorrupt = 1;
errs++;
}
}
(void) printf("\n");
return (errs);
}
void
{
int i;
int n;
if (fd < 0)
return;
if (debug)
(void) printf(
"WARNING: Attempt to write illegal blkno %lld on %s\n",
return;
}
}
fsmodified = 1;
return;
}
}
pwarn("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
n = 0;
iscorrupt = 1;
} else if (n > 0) {
fsmodified = 1;
}
}
(void) printf("\n");
}
/*
* Allocates the specified number of contiguous fragments.
*/
{
/*
* It's arguable whether we should just fail, or instead
* error out here. Since we should only ever be asked for
* a single fragment or an entire block (i.e., sblock.fs_frag),
* we'll fail out because anything else means somebody
* changed code without considering all of the ramifications.
*/
errexit("allocblk() asked for %d frags. "
"Legal range is 1 to %d",
}
/*
* For each filesystem block, look at every possible starting
* offset within the block such that we can get the number of
* contiguous fragments that we need. This is a drastically
* simplified version of the kernel's mapsearch() and alloc*().
* It's also correspondingly slower.
*/
leadfrag++) {
/*
* Is first fragment of candidate run available?
*/
continue;
/*
* Are the rest of them available?
*/
break;
if (tailfrag < wantedfrags) {
/*
* No, skip the known-unusable run.
*/
continue;
}
/*
* Found what we need, so claim them.
*/
n_blks += wantedfrags;
if (debug)
(void) printf(
"allocblk: selected %d (in block %d), frags %d, size %d\n",
wantedfrags, (int)size);
return (selected);
}
}
return (0);
}
/*
* Free a previously allocated block
*/
void
{
if (debug)
(void) printf("debug: freeing %d fragments starting at %d\n",
/*
* Nothing in the return status has any relevance to how
* we're using pass4check(), so just ignore it.
*/
(void) pass4check(&idesc);
}
/*
* Fill NAMEBUF with a path starting in CURDIR for INO. Assumes
* that the given buffer is at least MAXPATHLEN + 1 characters.
*/
void
{
int len;
if (debug)
(void) printf("debug: getpathname(curdir %d, ino %d)\n",
return;
}
return;
}
*cp = '\0';
/*
* In the case of extended attributes, our
* parent won't necessarily be a directory, so just
* return what we've found with a prefix indicating
* that it's an XATTR. Presumably our caller will
* know what's going on and do something useful, like
* work out the path of the parent and then combine
* the two names.
*
* Can't use strcpy(), etc, because we've probably
* already got some name information in the buffer and
* the usual trailing \0 would lose it.
*/
*cp-- = '?';
}
goto attrname;
}
/*
* If curdir == ino, need to get a handle on .. so we
* can search it for ino's name. Otherwise, just search
* the given directory for ino. Repeat until out of space
* or a full path has been built.
*/
goto namelookup;
}
break;
}
}
/*
* To get this far, id_parent must have the inode
* number for `..' in it. By definition, that's got
* to be a directory, so search it for the inode of
* interest.
*/
break;
}
/*
* Prepend to what we've accumulated so far. If
* there's not enough room for even one more path element
* (of the worst-case length), then bail out.
*/
break;
*--cp = '/';
/*
* Corner case for a looped-to-itself directory.
*/
break;
/*
* Climb one level of the hierarchy. In other words,
* the current .. becomes the inode to search for and
* its parent becomes the directory to search in.
*/
}
/*
* If we hit a discontinuity in the hierarchy, indicate it by
* prefixing the path so far with `?'. Otherwise, the first
* character will be `/' as a side-effect of the *--cp above.
*
* The special case is to handle the situation where we're
* trying to look something up in UFSROOTINO, but didn't find
* it.
*/
cp--;
*cp = '?';
}
/*
* The invariants being used for buffer integrity are:
* - namebuf[] is terminated with \0 before anything else
* - cp is always <= the last element of namebuf[]
* - the new path element is always stored at the
* beginning of namebuf[], and is no more than MAXNAMLEN-1
* characters
* - cp is is decremented by the number of characters in
* the new path element
* - if, after the above accounting for the new element's
* size, there is no longer enough room at the beginning of
* namebuf[] for a full-sized path element and a slash,
* terminate the loop. cp is in the range
* &namebuf[0]..&namebuf[MAXNAMLEN - 1]
*/
/* LINTED per the above discussion */
}
/* ARGSUSED */
void
{
ckfini();
}
/*
* When preening, allow a single quit to signal
* a special exit after filesystem checks complete
* so that reboot sequence may be interrupted.
*/
/* ARGSUSED */
void
{
(void) printf("returning to single-user after filesystem check\n");
interrupted = 1;
}
/*
* determine whether an inode should be fixed.
*/
int
{
int rval = 0;
case DONTKNOW:
else
if (preen) {
break;
}
if (reply("SALVAGE") == 0) {
break;
}
break;
case FIX:
break;
case NOFIX:
break;
default:
}
return (rval);
}
void
{
/* NOTREACHED */
}
static void
{
static int recursing = 0;
if (!recursing) {
recursing = 1;
if (errorlocked || iscorrupt) {
sbdirty();
}
}
ckfini();
recursing = 0;
}
(void) putchar('\n');
}
/*
* An unexpected inconsistency occured.
* Die if preening, otherwise just print message and continue.
*/
void
{
}
static void
{
if (preen) {
if (*fmt != '\0') {
(void) printf("\n");
}
(void) printf(
"%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
devname);
sbdirty();
}
/*
* We're exiting, it doesn't really matter that our
* caller doesn't get to call va_end().
*/
if (exitstat == 0)
}
if (*fmt != '\0') {
}
}
/*
* Pwarn just prints a message when not preening,
* or a warning (preceded by filename) when preening.
*/
void
{
}
static void
{
if (*fmt != '\0') {
if (preen)
}
}
/*
* Like sprintf(), except the buffer is dynamically allocated
* and returned, instead of being passed in. A pointer to the
* buffer is stored in *RET, and FMT is the usual format string.
* The number of characters in *RET (excluding the trailing \0,
* to be consistent with the other *printf() routines) is returned.
*
* Solaris doesn't have asprintf(3C) yet, unfortunately.
*/
int
{
int len;
errexit("Out of memory in asprintf\n");
/* NOTREACHED */
}
return (len);
}
/*
* So we can take advantage of kernel routines in ufs_subr.c.
*/
/* PRINTFLIKE2 */
void
{
(void) printf("INTERNAL INCONSISTENCY:");
} else {
}
}
/*
* Check to see if unraw version of name is already mounted.
* Updates devstr with the device name if devstr is not NULL
* and str_size is positive.
*/
int
{
int found;
return (M_NOMNT);
/*
* It's mounted. With or without write access?
*/
else
if (mount_point == NULL) {
if (mount_point == NULL) {
errexit("fsck: memory allocation failure: %s",
/* NOTREACHED */
}
}
return (found);
}
/*
* Check to see if name corresponds to an entry in vfstab, and that the entry
* does not have option ro.
*/
int
{
return (1);
}
rw = 0;
}
return (rw);
}
/*
* debugclean
*/
static void
debugclean(void)
{
if (!debug)
return;
return;
return;
(void) printf("WARNING: inconsistencies detected on %s filesystem %s\n",
devname);
}
/*
* updateclean
* Carefully and transparently update the clean flag.
*
* `iscorrupt' has to be in its final state before this is called.
*/
int
updateclean(void)
{
int freedlog = 0;
char fsclean;
int fsreclaim;
char fsflags;
time_t t;
/*
* debug stuff
*/
debugclean();
/*
* set fsclean to its appropriate value
*/
}
/*
* If ufs log is not okay, note that we need to 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) {
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;
/*
* There can be two discrepencies here. A) The superblock
* shows no largefiles but we found some while scanning.
* B) The superblock indicates the presence of largefiles,
* but none are present. Note that if preening, the superblock
* is silently corrected.
*/
flags_ok = 0;
if (debug)
(void) printf(
"** largefile count=%d, fs.fs_flags=%x, flags_ok %d\n",
/*
* If fs is unchanged, do nothing.
*/
if (errorlocked) {
if (!do_errorlock(LOCKFS_ULOCK))
"updateclean(unchanged): unlock(LOCKFS_ULOCK) failed\n");
}
return (freedlog);
}
/*
* if user allows, update superblock state
*/
if (debug) {
(void) printf(
"superblock: flags 0x%x logbno %d clean %d reclaim %d state 0x%x\n",
(void) printf(
"calculated: flags 0x%x logbno %d clean %d reclaim %d state 0x%x\n",
}
(reply("FILE SYSTEM STATE IN SUPERBLOCK IS WRONG; FIX") == 0))
return (freedlog);
(void) time(&t);
if (debug)
printclean();
freedlog++;
}
/*
* if superblock can't be written, return
*/
if (fswritefd < 0)
return (freedlog);
/*
* Read private copy of superblock, update clean flag, and write it.
*/
errexit("out of memory");
(void) printf("COULD NOT SEEK TO SUPERBLOCK AT %lld: %s\n",
goto out;
}
goto out;
}
(void) printf("COULD NOT SEEK TO SUPERBLOCK AT %lld: %s\n",
goto out;
}
goto out;
}
/*
* 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 != 0) {
}
if (errorlocked) {
if (!do_errorlock(LOCKFS_ULOCK))
"updateclean(changed): unlock(LOCKFS_ULOCK) failed\n");
}
out:
}
return (freedlog);
}
static void
{
if (failure < 0)
(void) printf("COULD NOT %s SUPERBLOCK AT %d: %s\n",
else if (failure == 0)
(void) printf("COULD NOT %s SUPERBLOCK AT %d: EOF\n",
else
(void) printf("SHORT %s SUPERBLOCK AT %d: %u out of %u bytes\n",
}
/*
* print out clean info
*/
void
printclean(void)
{
caddr_t 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
}
int
{
int retval;
retval = 0;
if (!fs)
return (0);
return (0);
return (0);
return (0);
} else {
return (0);
}
/*
* From here on, must `goto out' to avoid memory leakage.
*/
if (elock_combuf == NULL)
else
if (elock_combuf == NULL)
goto out;
if (elock_mountp != NULL) {
}
if (elock_mountp == NULL)
goto out;
if (mountfd < 0) {
goto out;
}
goto out;
}
goto out;
/*
* lint believes that the ioctl() (or any other function
* taking lfp as an arg) could free lfp. This is not the
* case, however.
*/
out:
return (retval);
}
/*
* Given a name which is known to be a directory, see if it appears
* in the vfstab. If so, return the entry's block (special) device
* field via devstr.
*/
int
{
}
/*
* Given a name which is known to be a directory, see if it appears
* in the mnttab. If so, return the entry's block (special) device
* field via devstr.
*/
int
{
}
/*
* The first matching entry is returned.
*
* If an entry is found and str_size is greater than zero, then
* up to size_str bytes of the special device name from the entry
* are copied to devstr.
*/
{ \
\
/* LINTED ``assigned value never used'' */ \
st_init; \
\
return (NULL); \
\
str_size); \
} \
} \
return (retval); \
}
static struct vfstab *
static struct mnttab *
int
{
int rc;
if (elock_combuf == NULL)
errexit("do_errorlock(%s, %d): unallocated elock_combuf\n",
NULL) {
errexit("Couldn't alloc memory for temp. lock status buffer\n");
}
errexit("do_errorlock(%s, %d): lockfs status unallocated\n",
}
switch (lock_type) {
case LOCKFS_ELOCK:
/*
* Note that if it is error-locked, we won't get an
* error back if we try to error-lock it again.
*/
"%s [pid:%d fsck start:%02d/%02d/%02d %02d:%02d:%02d",
elock_combuf, (int)pid,
else
} else {
}
break;
case LOCKFS_ULOCK:
"%s, done:%02d/%02d/%02d %02d:%02d:%02d]",
} else {
"%s]", elock_combuf);
}
} else {
"%s]", elock_combuf);
}
pwarn("do_errorlock: unlock failed: %s\n",
goto out;
}
break;
default:
break;
}
LOCKFS_MAXCOMMENTLEN - 1);
errno = 0;
pwarn("Another fsck active?\n");
iscorrupt = 0; /* don't go away mad, just go away */
} else {
pwarn("do_errorlock(lock_type:%d, %s) failed: %s\n",
}
}
out:
}
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.
*/
static struct shadowclients *
{
errexit("newshadowclient: cannot malloc shadow client");
errexit("newshadowclient: cannot malloc client array");
return (rc);
}
void
struct shadowclientinfo **info)
{
/*
* Already have a record for this shadow?
*/
break;
/*
* It's a new shadow, add it to the list
*/
errexit("registershadowclient: cannot malloc");
sci->totalClients = 0;
}
sci->totalClients++;
}
}
/*
* Locate and discard a shadow.
*/
void
{
/*
* Do we have a record for this shadow?
*/
break;
}
/*
* First, pull it off the list, since we know there
* shouldn't be any future references to this one.
*/
else
}
}
/*
* Discard all memory used to track clients of a shadow.
*/
void
{
int idx;
}
}
}
}
/*
* 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 its task.
*/
static struct bufarea *
alloc_bufarea(void)
{
return (NULL);
return (NULL);
}
return (newbp);
}
/*
* We length-limit in both unrawname() and rawname() to avoid
* overflowing our arrays or those of our naive, trusting callers.
*/
{
return ("");
/*
* Not reporting under debug, as the allocation isn't
* reported by getfullblkname. The idea is that we
*/
return (fullname);
}
{
return ("");
/*
* Not reporting under debug, as the allocation isn't
* reported by getfullblkname. The idea is that we
*/
return (fullname);
}
/*
* Make sure that a cg header looks at least moderately reasonable.
* We want to be able to trust the contents enough to be able to use
* the standard accessor macros. So, besides looking at the obvious
* such as the magic number, we verify that the offset field values
* are properly aligned and not too big or small.
*
* Returns a NULL pointer if the cg is sane enough for our needs, else
* a dynamically-allocated string describing all of its faults.
*/
full_len = addition_len; \
} else { \
/* lint doesn't think realloc() understands NULLs */ \
errexit("Out of memory in cg_sanity"); \
/* NOTREACHED */ \
} \
full_len += addition_len; \
}
{
full_len = 0;
if (!cg_chkmagic(cgp)) {
"BAD CG MAGIC NUMBER (0x%x should be 0x%x)\n",
}
"WRONG CG NUMBER (%d should be %d)\n",
}
"BLOCK TOTALS OFFSET %d NOT FOUR-BYTE ALIGNED\n",
cgp->cg_btotoff);
}
"FREE BLOCK POSITIONS TABLE OFFSET %d NOT TWO-BYTE ALIGNED\n",
}
"IMPOSSIBLE NUMBER OF CYLINDERS IN GROUP (%d is less than 1)\n",
} else {
"IMPOSSIBLE NUMBER OF CYLINDERS IN GROUP (%d is greater than %d)\n",
}
}
"INCORRECT NUMBER OF INODES IN GROUP (%d should be %d)\n",
}
"INCORRECT NUMBER OF DATA BLOCKS IN GROUP (%d should be %d)\n",
}
"IMPOSSIBLE BLOCK ALLOCATION ROTOR POSITION "
"(%d should be at least 0 and less than %d)\n",
}
"IMPOSSIBLE FRAGMENT ALLOCATION ROTOR POSITION "
"(%d should be at least 0 and less than %d)\n",
}
"IMPOSSIBLE INODE ALLOCATION ROTOR POSITION "
"(%d should be at least 0 and less than %d)\n",
}
"INCORRECT BLOCK TOTALS OFFSET (%d should be %d)\n",
}
"BAD FREE BLOCK POSITIONS TABLE OFFSET (%d should %d)\n",
}
"INCORRECT USED INODE MAP OFFSET (%d should be %d)\n",
}
"INCORRECT FREE FRAGMENT MAP OFFSET (%d should be %d)\n",
}
"END OF HEADER POSITION INCORRECT (%d should be %d)\n",
}
return (full_err);
}
/*
* This is taken from mkfs, and is what is used to come up with the
* original values for a struct cg. This implies that, since these
* are all constants, recalculating them now should give us the same
* thing as what's on disk.
*/
static void
{
/* LINTED pointer difference won't overflow */
*nextfreeoff = *freeoff +
}
/*
* Corrects all fields in the cg that can be done with the available
* redundant data.
*/
void
{
}
} else {
}
}
/*
* This is not used by the kernel, so it's pretty
* harmless if it's wrong.
*/
}
}
/*
* For the rotors, any position's valid, so pick the one we know
* will always exist.
*/
}
}
}
/*
* For btotoff and boff, if they're misaligned they won't
* match the expected values, so we're catching both cases
* here. Of course, if any of these are off, it seems likely
* that the tables really won't be where we calculate they
* should be anyway.
*/
}
}
}
}
}
/*
* Reset the magic, as we've recreated this cg, also
* update the cg_time, as we're writing out the cg
*/
/*
* We know there was at least one correctable problem,
* or else we wouldn't have been called. So instead of
* marking the buffer dirty N times above, just do it
* once here.
*/
cgdirty();
}
void
{
int i;
int j;
/*
* Since ufs stores fs_logbno as blocks and MTBufs stores it as frags
* we need to translate accordingly using logbtodb()
*/
if (debug) {
(void) printf("fs_logbno < SBLOCK: %ld < %ld\n" \
"Aborting log examination\n", \
}
return;
}
/*
* Read errors will return zeros, which will cause us
* to do nothing harmful, so don't need to handle it.
*/
/*
* Does it look like a log allocation table?
*/
/* LINTED pointer cast is aligned */
return;
return;
/*
* Invoke the callback first, so that pass1 can
* mark the log blocks in-use. Then, if any
* subsequent pass over the log shows us that a
* block got freed (say, it was also claimed by
* an inode that we cleared), we can safely declare
* the log bad.
*/
islogok = 0;
}
}
}
}
static void
{
}
{
return (lfname);
}
} else {
}
return (name);
}
/*
* Simple initializer for inodesc structures, so users of only a few
* fields don't have to worry about getting the right defaults for
* everything out.
*/
void
{
/*
* Most fields should be zero, just hit the special cases.
*/
}
/*
* Compare routine for tsearch(C) to use on ino_t instances.
*/
int
{
}
int
cgisdirty(void)
{
}
void
cgflush(void)
{
}
void
{
if (fswritefd < 0) {
/*
* No one should call dirty() in read only mode.
* But if one does, it's not fatal issue. Just warn him.
*/
pwarn("WON'T SET DIRTY FLAG IN READ_ONLY MODE\n");
} else {
isdirty = 1;
}
}
void
{
}
/*
* Needed because calcsb() needs to use mkfs to work out what the
* superblock should be, and mkfs insists on being told how many
* sectors to use.
*
* Error handling assumes we're never called while preening.
*
* XXX This should be extracted into a ../ufslib.{c,h},
* in the same spirit to ../../fslib.{c,h}. Once that is
* done, both fsck and newfs should be modified to link
* against it.
*/
static int label_type;
{
int rpm;
struct dk_geom g;
/*
* get_device_size() determines the actual size of the
* device, and also the disk's attributes, such as geometry.
*/
if (label_type == LABEL_TYPE_VTOC) {
return (0);
}
}
}
/*
* Adjust maxcontig by the device's maxtransfer. If maxtransfer
* information is not available, default to the min of a MB and
* maxphys.
*/
if (sblock.fs_maxcontig < 0) {
/*
* If we cannot get the maxphys value, default
* to ufs_maxmaxphys (MB).
*/
if (gotit) {
} else {
}
}
}
return (actual_size);
}
/*
* Figure out how big the partition we're dealing with is.
*/
static diskaddr_t
{
if (index >= 0) {
} else {
/* it might be an EFI label */
if (index >= 0)
}
}
if (index < 0) {
/*
* Since both attempts to read the label failed, we're
* going to fall back to a brute force approach to
* determining the device's size: see how far out we can
* perform reads on the device.
*/
if (slicesize == 0) {
switch (index) {
case VT_ERROR:
break;
case VT_EIO:
break;
case VT_EINVAL:
break;
default:
pwarn("%s: unknown error %d accessing VTOC",
break;
}
return (0);
} else {
}
}
if (label_type == LABEL_TYPE_EFI) {
} else if (label_type == LABEL_TYPE_VTOC) {
}
return (slicesize);
}
/*
* brute_force_get_device_size
*
* Determine the size of the device by seeing how far we can
* read. Doing an llseek( , , SEEK_END) would probably work
* in most cases, but we've seen at least one third-party driver
* which doesn't correctly support the SEEK_END option when the
* the device is greater than a terabyte.
*/
static diskaddr_t
{
/*
* First, see if we can read the device at all, just to
* eliminate errors that have nothing to do with the
* device's size.
*/
return (0); /* can't determine size */
/*
* Now, go sequentially through the multiples of 4TB
* to find the first read that fails (this isn't strictly
* the most efficient way to find the actual size if the
* size really could be anything between 0 and 2**64 bytes.
* We expect the sizes to be less than 16 TB for some time,
* so why do a bunch of reads that are larger than that?
* However, this algorithm *will* work for sizes of greater
* than 16 TB. We're just not optimizing for those sizes.)
*/
/*
* XXX lint uses 32-bit arithmetic for doing flow analysis.
* We're using > 32-bit constants here. Therefore, its flow
* analysis is wrong. For the time being, ignore complaints
* from it about the body of the for() being unreached.
*/
SEEK_SET) == -1) ||
else
}
/*
* XXX Same lint flow analysis problem as above.
*/
if (min_fail == 0)
return (0);
/*
* We now know that the size of the device is less than
* min_fail and greater than or equal to max_succeed. Now
* keep splitting the difference until the actual size in
* sectors in known. We also know that the difference
* between max_succeed and min_fail at this time is
* 4 * SECTORS_PER_TERABYTE, which is a power of two, which
* simplifies the math below.
*/
SEEK_SET)) == -1) ||
else
}
/* the size is the last successfully read sector offset plus one */
return (max_succeed + 1);
}
static void
{
(void) putchar(' ');
(void) printf("\n");
return;
}
else
}
void
{
}
static void
{
}
void
{
}
/*
* Adds the given inode to the orphaned-directories list, limbo_dirs.
* Assumes that the caller has set INCLEAR in the inode's statemap[]
* entry.
*
* With INCLEAR set, the inode will get ignored by passes 2 and 3,
* meaning it's effectively an orphan. It needs to be noted now, so
* it will be remembered in pass 4.
*/
void
{
errexit("add_orphan_dir: out of memory");
}
/*
* Remove an inode from the orphaned-directories list, presumably
* because it's been cleared.
*/
void
{
}
/*
* log_setsum() and log_checksum() are equivalent to lufs.c:setsum()
* and lufs.c:checksum().
*/
static void
{
*sp = 0;
while (nb--)
}
static int
{
return (0);
}
return (1);
}