/*
* Copyright (c) International Business Machines Corp., 2000-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* COMPONENT_NAME: jfs_fscklog (formerly xchklog)
*
* The jfs_fscklog tool provides 2 basic functions - fsck.jfs
* service log extraction and display. The code here extracts
* the log.
*
*/
#include <config.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include "devices.h"
#include "diskmap.h"
#include "fsckwsp.h"
#include "fsck_message.h"
#include "jfs_endian.h"
#include "jfs_fscklog.h"
#include "super.h"
#include "utilsubs.h"
#include "xfsck.h"
#define fsck_READ 1
#define fsck_WRITE 2
extern char file_name[128];
FILE *outfp;
extern struct fscklog_record fscklog_record;
extern struct fscklog_record *local_recptr;
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
*
* superblock I/O buffer and pointer
*
*/
struct superblock aggr_superblock;
struct superblock *sb_ptr;
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
*
* input: fsck service log I/O buffer
* output: fsck extracted service log I/O buffer
*
*/
char fscklog_buffer[FSCKLOG_BUFSIZE];
extern char xchklog_buffer[];
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
*
* For message processing
*
* values are assigned by the main jfs_fscklog routine
*/
extern char *Vol_Label;
/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
*
* Device information.
*
* values are assigned when (if) the device is opened.
*/
FILE *Dev_IOPort;
unsigned Dev_blksize;
int Dev_SectorSize;
/* VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*
* The following are internal to this file
*
*/
void extract_service_log(void);
int xchklog_final_processing(void);
int xchklog_fscklog_fill_buffer(void);
int xchklog_initial_processing(struct fscklog_record *);
int open_device_read(const char *);
int open_outfile(void);
int readwrite_device(int64_t, unsigned, unsigned *, void *, int);
void record_msg(char *);
int validate_super(int);
int validate_superblock(void);
/*****************************************************************************
* NAME: xchklog
*
* FUNCTION: Entry point for jfs read aggregate fsck service log
*
* PARAMETERS:
* local_recptr - fscklog record
*
* RETURNS:
* success: 0
* failure: something else
*/
int xchklog(struct fscklog_record *local_recptr)
{
int rc = 0;
/*
* some basic initializations
*/
sb_ptr = &aggr_superblock;
rc = xchklog_initial_processing(local_recptr);
if (rc == 0) {
/* we have a buffer and the device is open */
extract_service_log();
}
if (rc == 0) {
rc = xchklog_final_processing();
} else {
xchklog_final_processing();
}
return (rc);
}
/***************************************************************************
* NAME: extract_service_log
*
* FUNCTION:
*
* PARAMETERS: none
*
* RETURNS:
* success: 0
* failure: something else
*/
void extract_service_log()
{
char *msg_txt;
int dsl_rc = 0;
char *log_entry;
int log_entry_pos;
int bytes_left;
struct fscklog_entry_hdr *hdptr;
local_recptr->fscklog_last_read = 0;
while ((!local_recptr->fscklog_last_read) && (dsl_rc == 0)) {
dsl_rc = xchklog_fscklog_fill_buffer();
local_recptr->this_buffer_last_message = 0;
while ((!local_recptr->this_buffer_last_message)
&& (dsl_rc == 0)) {
hdptr = (struct fscklog_entry_hdr *)
(local_recptr->infile_buf_ptr +
local_recptr->infile_buf_data_len);
if (hdptr->entry_length == 0) {
/* no more entries in this buffer */
local_recptr->this_buffer_last_message = -1;
} else {
/* this entry_length != 0 */
/* swap if on big endian machine */
ujfs_swap_fscklog_entry_hdr(hdptr);
log_entry = (char *) hdptr;
log_entry_pos =
sizeof (struct fscklog_entry_hdr);
/*
* Each FSCKLOG_BUFSIZE boundary starts a new
* log record. Otherwise, we depend on a valid
* entry_length to locate the next message.
*/
bytes_left = local_recptr->infile_buf_length -
local_recptr->infile_buf_data_len;
if ((bytes_left < 0)
|| (hdptr->entry_length < 0)
|| (hdptr->entry_length > bytes_left)) {
/* this isn't a valid log record length */
send_msg(fsck_CHKLOGINVALRCD);
local_recptr->this_buffer_last_message =
-1;
} else {
/* the log record length looks ok */
msg_txt = &log_entry[log_entry_pos];
/*
* record the message in the output file
*/
record_msg(msg_txt);
/*
* set up for the next record
*/
local_recptr->infile_buf_data_len +=
hdptr->entry_length;
/*if (hdptr->msg_num == fsck_SESSEND) {
local_recptr->
this_buffer_last_message =
-1;
}*/
if (local_recptr->infile_buf_data_len >=
local_recptr->infile_buf_length) {
local_recptr->
this_buffer_last_message =
-1;
}
}
}
}
}
return;
}
/***************************************************************************
* NAME: xchklog_final_processing
*
* FUNCTION: If processing read/write, replicate the superblock and the
* aggregate inode structures (i.e., the Aggregate Inode Map
* and the Aggregate Inode Table).
*
* Notify the user about various things.
*
* PARAMETERS: none
*
* RETURNS:
* success: 0
* failure: something else
*/
int xchklog_final_processing()
{
int pf_rc = 0;
/*
* Close the device
*/
if (local_recptr->device_is_open) {
pf_rc = fclose(Dev_IOPort);
}
/*
* Close the output file
*/
if (local_recptr->outfile_is_open) {
/*
* flush the buffer if necessary
*/
if (local_recptr->outfile_buf_data_len != 0) {
fwrite((const void *) (local_recptr->outfile_buf_ptr),
sizeof (char), local_recptr->outfile_buf_length,
outfp);
}
fclose(outfp);
}
return (pf_rc);
}
/*****************************************************************************
* NAME: fscklog_fill_buffer
*
* FUNCTION: If the current fsck session has write access to the aggregate,
* and if the in-aggregate fsck log is not full, write the
* contents of the current fscklog buffer into the in-aggregate
* fsck log.
*
* PARAMETERS: none
*
* NOTES: o Unlike most _put_ routines in this module, fscklog_put_buffer
* actually writes to the device. This is done because the fsck
* log contains information which provides crucial serviceability
* should the fsck session be interrupted.
*
* o Errors here are recorded in the control page of the fsck
* in-aggregate workspace but never affect other fsck processing.
*
* RETURNS:
* success: 0
* failure: something else
*/
int xchklog_fscklog_fill_buffer()
{
int flfb_rc = 0;
int io_rc = 0;
unsigned bytes_read = 0;
unsigned log_bytes_left;
io_rc = readwrite_device(local_recptr->infile_agg_offset,
local_recptr->infile_buf_length,
&bytes_read,
(void *) local_recptr->infile_buf_ptr,
fsck_READ);
if ((io_rc != 0)
|| (bytes_read != (unsigned) local_recptr->infile_buf_length)) {
/*
* write failed or didn't read
* correct number of bytes
*/
send_msg(fsck_URCVWRT, fsck_ref_msg(fsck_metadata), Vol_Label);
send_msg(fsck_ERRONLOG, FSCK_BADREAD_FSCKLOG, io_rc, fsck_READ,
(long long) local_recptr->infile_agg_offset,
(long int) local_recptr->infile_buf_length,
(long int) bytes_read);
}
/*
* We want to reset the buffer no matter what. If is useful
* to keep going because the next section may be readable.
*/
local_recptr->infile_agg_offset += local_recptr->infile_buf_length;
local_recptr->infile_log_offset += local_recptr->infile_buf_length;
local_recptr->infile_buf_data_len = 0;
log_bytes_left = (local_recptr->ondev_fscklog_byte_length / 2) -
local_recptr->infile_log_offset;
if (log_bytes_left < local_recptr->infile_buf_length) {
/* this is the last one */
local_recptr->fscklog_last_read = -1;
}
return (flfb_rc);
}
/*****************************************************************************
* NAME: xchklog_initial_processing
*
* FUNCTION: Parse and verify invocation parameters.
* Open the device and verify that it contains a JFS file system.
* Read the chkdsk workspace control page.
* Calculate interesting aggregate offsets.
*
*
* PARAMETERS: as specified to main()
*
* NOTES:
*
* RETURNS:
* success: 0
* failure: something else
*/
int xchklog_initial_processing(struct fscklog_record *local_recptr)
{
int pi_rc = 0;
/*
* Initialize the fscklog control block
*/
local_recptr->infile_buf_length = FSCKLOG_BUFSIZE;
local_recptr->infile_buf_ptr = fscklog_buffer;
local_recptr->outfile_buf_length = XCHKLOG_BUFSIZE;
local_recptr->outfile_buf_ptr = xchklog_buffer;
/*
* Open the device and verify that it contains a valid JFS aggregate
* If it does, check/repair the superblock.
*/
pi_rc = open_device_read(Vol_Label);
if (pi_rc != 0) {
/*device open failed */
send_msg(fsck_CNTRESUPB);
} else {
/* device is open */
local_recptr->device_is_open = 1;
pi_rc = validate_superblock();
if (pi_rc == 0) {
/* a valid superblock */
/*
* add some stuff to the local record which is based on
* superblock fields
*/
/* length of the on-device fsck service log */
local_recptr->ondev_fscklog_byte_length =
sb_ptr->s_fsckloglen * sb_ptr->s_bsize;
/* length of the on-device fsck service log */
local_recptr->ondev_fscklog_fsblk_length =
sb_ptr->s_fsckloglen;
/* length of the on-device fsck workspace */
local_recptr->ondev_wsp_fsblk_length =
lengthPXD(&(sb_ptr->s_fsckpxd)) -
local_recptr->ondev_fscklog_fsblk_length;
/* length of the on-device fsck workspace */
local_recptr->ondev_wsp_byte_length =
local_recptr->ondev_wsp_fsblk_length *
sb_ptr->s_bsize;
/* aggregate block offset of the on-device fsck workspace */
local_recptr->ondev_wsp_fsblk_offset =
addressPXD(&(sb_ptr->s_fsckpxd));
/* byte offset of the on-device fsck workspace */
local_recptr->ondev_wsp_byte_offset =
local_recptr->ondev_wsp_fsblk_offset *
sb_ptr->s_bsize;
/* aggregate block offset of the on-device fsck workspace */
local_recptr->ondev_fscklog_fsblk_offset =
local_recptr->ondev_wsp_fsblk_offset +
local_recptr->ondev_wsp_fsblk_length;
/* byte offset of the on-device fsck workspace */
local_recptr->ondev_fscklog_byte_offset =
local_recptr->ondev_wsp_byte_offset +
local_recptr->ondev_wsp_byte_length;
/*
* The offsets now assume the most recent log is 1st in the
* aggregate fsck service log space. Adjust if needed.
*/
if (local_recptr->which_log == NEWLOG) {
/* most recent wanted */
if (sb_ptr->s_fscklog == 2) {
/* the 2nd is most recent */
local_recptr->
ondev_fscklog_fsblk_offset +=
local_recptr->
ondev_fscklog_fsblk_length / 2;
local_recptr->
ondev_fscklog_byte_offset +=
local_recptr->
ondev_fscklog_byte_length / 2;
}
} else {
/* previous log wanted */
if (sb_ptr->s_fscklog != 2) {
/* the 2nd is not most recent */
local_recptr->
ondev_fscklog_fsblk_offset +=
local_recptr->
ondev_fscklog_fsblk_length / 2;
local_recptr->
ondev_fscklog_byte_offset +=
local_recptr->
ondev_fscklog_byte_length / 2;
}
}
local_recptr->infile_agg_offset =
local_recptr->ondev_fscklog_byte_offset;
pi_rc = open_outfile();
}
}
if (local_recptr->which_log == NEWLOG) {
send_msg(fsck_CHKLOGNEW);
} else {
send_msg(fsck_CHKLOGOLD);
}
return (pi_rc);
}
/*****************************************************************************
* NAME: open_device_read
*
* FUNCTION: Open the specified device for read access.
*
* PARAMETERS:
* Device - input - the device specification
*
* NOTES:
*
* RETURNS:
* success: 0
* failure: something else
*/
int open_device_read(const char *Device)
{
Dev_IOPort = fopen(Device, "r");
if (Dev_IOPort == NULL) {
send_msg(fsck_DEVOPENRDRC, ERROR_FILE_NOT_FOUND);
return ERROR_FILE_NOT_FOUND;
}
Dev_blksize = Dev_SectorSize = PBSIZE;
return 0;
}
/*****************************************************************************
* NAME: open_outfile
*
* FUNCTION: Open the output file.
*
* PARAMETERS:
* Device - input - the device specification
*
* RETURNS:
* success: 0
* failure: something else
*/
int open_outfile()
{
int openof_rc = 0;
if (!local_recptr->file_name_specified) {
/* no output file name given */
if (local_recptr->which_log == NEWLOG) {
/* most recent wanted */
memcpy((void *) file_name, (void *) default_logfile_new,
default_logfile_name_len);
} else {
/* prior log wanted */
memcpy((void *) file_name, (void *) default_logfile_old,
default_logfile_name_len);
}
}
outfp = fopen(file_name, "w");
if (outfp == NULL) {
/* output file open failed */
openof_rc = XCHKLOG_CANTOPENOUTFILE;
send_msg(fsck_XCHKLOGOPNFAIL, file_name);
} else {
/* output file is open */
local_recptr->outfile_is_open = -1;
/*
* write the eyecatcher into the output buffer
*/
memcpy((void *) (local_recptr->outfile_buf_ptr),
(void *) jfs_chklog_eyecatcher, 16);
local_recptr->outfile_buf_data_len = 16;
/*
* announce the output file name
*/
if (local_recptr->which_log == NEWLOG) {
/* most recent */
send_msg(fsck_XCHKLOGNEW, file_name);
} else {
/* previous */
send_msg(fsck_XCHKLOGOLD, file_name);
}
}
return (openof_rc);
}
/*****************************************************************************
* NAME: readwrite_device
*
* FUNCTION: Read data from or write data to the device on which the
* aggregate resides.
*
* PARAMETERS:
* dev_offset - input - the offset, in bytes, into the aggregate
* of the data to read or to which to write
* the data.
* requested_data_size - input - the number of bytes requested
* actual_data_size - input - pointer to a variable in which to return
* the number of bytes actually read or
* written
* data_buffer - input - the address of the buffer in which to
* put the data or from which to write
* the data
* mode - input - { fsck_READ | fsck_WRITE }
*
* NOTES: This routine also exists in fsck code. When there is time,
* examine both copies for differences and put the combined
* copy in libfs to eliminate extra code.
*
* RETURNS:
* success: 0
* failure: something else
*/
int readwrite_device(int64_t dev_offset,
unsigned requested_data_size,
unsigned *actual_data_size, void *data_buffer, int mode)
{
int rwdb_rc = 0;
if ((dev_offset % Dev_SectorSize)
|| (requested_data_size % Dev_SectorSize)) {
rwdb_rc = FSCK_FAILED_SEEK;
} else {
switch (mode) {
case fsck_READ:
rwdb_rc =
ujfs_rw_diskblocks(Dev_IOPort, dev_offset,
requested_data_size, data_buffer,
GET);
break;
case fsck_WRITE:
rwdb_rc =
ujfs_rw_diskblocks(Dev_IOPort, dev_offset,
requested_data_size, data_buffer,
PUT);
break;
default:
rwdb_rc = FSCK_INTERNAL_ERROR_3;
break;
}
}
if (rwdb_rc == 0)
*actual_data_size = requested_data_size;
else
*actual_data_size = 0;
return (rwdb_rc);
}
/*****************************************************************************
* NAME: record_msg
*
* FUNCTION: Record an fsck service log message in the output file,
* formatted for the common fsck service log display tool.
*
* PARAMETERS:
* ? - input -
* ? - returned -
*
* NOTES: Any message designated fsck_debug is english-only, and
* is issued in english, even if it is sent to stdout.
*
* All other messages are local-language (in the nls context)
* and, when sent to stdout or stderr, are issued in the
* local language.
*
* Regardless of the language used to send a message to
* stdout and stderr, messages are ALWAYS LOGGED IN ENGLISH.
*
* RETURNS:
* nothing
*/
void record_msg(char *msg_txt)
{
char *msg;
char log_entry[4096];
int entry_length = sizeof (struct chklog_entry_hdr);
struct chklog_entry_hdr *hdptr;
int buffer_bytes_left;
hdptr = (struct chklog_entry_hdr *) log_entry;
msg = &log_entry[entry_length];
strcpy(msg, msg_txt);
entry_length += strlen(msg_txt);
/* add null terminator to string */
log_entry[entry_length++] = '\0';
/*
* round the length up so the next entry will
* start on a doubleword (4 byte) boundary
*/
entry_length = ((entry_length + 3) / 4) * 4;
hdptr->entry_length = entry_length;
buffer_bytes_left =
local_recptr->outfile_buf_length -
local_recptr->outfile_buf_data_len;
if (buffer_bytes_left < entry_length) {
/* won't fit */
local_recptr->last_msghdr->entry_length += buffer_bytes_left;
fwrite((const void *) (local_recptr->outfile_buf_ptr),
sizeof (char), local_recptr->outfile_buf_length, outfp);
/* clear the buffer */
memset((void *) (local_recptr->outfile_buf_ptr), 0,
local_recptr->outfile_buf_length);
local_recptr->outfile_buf_data_len = 0;
}
local_recptr->last_msghdr = (struct fscklog_entry_hdr *)
(local_recptr->outfile_buf_ptr +
local_recptr->outfile_buf_data_len);
memcpy((void *) local_recptr->last_msghdr, (void *) hdptr,
entry_length);
local_recptr->outfile_buf_data_len += entry_length;
return;
}
/*****************************************************************************
* NAME: validate_super
*
* FUNCTION: This routine validates the JFS superblock currently in the
* buffer. If any problem is detected, the which_superblock
* input parm is used to tailor the message issued to notify
* the user.
*
* PARAMETERS:
* which_super - input - specifies the superblock on which is in the
* buffer { fsck_primary | fsck_secondary }
*
* NOTES: This routine also exists in fsck code. When there is time,
* examine both copies for differences and put the combined
* copy in libfs to eliminate extra code.
*
* RETURNS:
* success: 0
* failure: something else
*/
int validate_super(int which_super)
{
int vs_rc = 0; /* assume the superblock is ok */
int64_t bytes_on_device;
int64_t agg_blks_in_aggreg = 0, agg_blks_on_device =
0, dev_blks_on_device;
int64_t fsck_start_from_pxd, fsck_blkmap_start_blks;
uint32_t fsck_length_from_pxd, fsck_blkmap_size_blks,
fsck_blkmap_size_pages;
int64_t jlog_start_from_pxd;
uint32_t jlog_length_from_pxd;
int agl2size;
unsigned expected_flag = JFS_GROUPCOMMIT;
unsigned agsize;
int bad_bsize = 0;
if (memcmp(sb_ptr->s_magic, JFS_MAGIC, sizeof (sb_ptr->s_magic)) != 0) {
vs_rc = FSCK_BADSBMGC;
send_msg(fsck_BADSBMGC, fsck_ref_msg(which_super));
} else if (sb_ptr->s_version > JFS_VERSION) {
vs_rc = FSCK_BADSBVRSN;
send_msg(fsck_BADSBVRSN, fsck_ref_msg(which_super));
} else {
/* the magic number and version number are correct so it
* probably is a JFS superblock with the format we are expecting
*/
/* get physical device size */
ujfs_get_dev_size(Dev_IOPort, &bytes_on_device);
dev_blks_on_device = bytes_on_device / Dev_blksize;
if (sb_ptr->s_pbsize != Dev_blksize) {
vs_rc = FSCK_BADSBOTHR1;
send_msg(fsck_BADSBOTHR, "1", fsck_ref_msg(which_super));
}
if (sb_ptr->s_l2pbsize != log2shift(Dev_blksize)) {
vs_rc = FSCK_BADSBOTHR2;
send_msg(fsck_BADSBOTHR, "2", fsck_ref_msg(which_super));
}
if (!inrange(sb_ptr->s_bsize, 512, 4096)) {
bad_bsize = -1;
vs_rc = FSCK_BADSBOTHR3;
send_msg(fsck_BADSBBLSIZ, fsck_ref_msg(which_super));
} else {
/* else the filesystem block size is a legal value */
if (sb_ptr->s_l2bsize != log2shift(sb_ptr->s_bsize)) {
vs_rc = FSCK_BADSBOTHR4;
send_msg(fsck_BADSBOTHR, "4",
fsck_ref_msg(which_super));
}
if (sb_ptr->s_l2bfactor !=
log2shift(sb_ptr->s_bsize / Dev_blksize)) {
vs_rc = FSCK_BADSBOTHR5;
send_msg(fsck_BADSBOTHR, "5",
fsck_ref_msg(which_super));
}
if (sb_ptr->s_bsize < Dev_blksize) {
bad_bsize = -1;
vs_rc = FSCK_BLSIZLTLVBLSIZ;
send_msg(fsck_BLSIZLTLVBLSIZ,
fsck_ref_msg(which_super));
}
}
if (!bad_bsize) {
agg_blks_on_device = bytes_on_device / sb_ptr->s_bsize;
}
if (sb_ptr->s_size > dev_blks_on_device) {
vs_rc = FSCK_BADSBFSSIZ;
send_msg(fsck_BADSBFSSIZ, fsck_ref_msg(which_super));
}
#ifdef _JFS_DFS_LFS
s_size_inbytes = sb_ptr->s_size * Dev_blksize;
sum_inbytes = (int64_t) (sb_ptr->totalUsable * 1024) +
(int64_t) (sb_ptr->minFree * 1024);
if ((sum_inbytes > s_size_inbytes)
|| ((s_size_inbytes - sum_inbytes) >= 1024)) {
/* the sum is greater or the difference is at least 1K */
vs_rc = FSCK_BADBLKCTTTL;
send_msg(fsck_BADBLKCTTTL, fsck_ref_msg(which_super));
}
#endif
/* must have JFS_OS2 or JFS_LINUX */
if (!(((sb_ptr->s_flag & JFS_OS2) == JFS_OS2)
|| ((sb_ptr->s_flag & JFS_LINUX) == JFS_LINUX))) {
vs_rc = FSCK_BADSBOTHR6;
send_msg(fsck_BADSBOTHR, "6", fsck_ref_msg(which_super));
}
if ((sb_ptr->s_flag & expected_flag) != expected_flag) {
vs_rc = FSCK_BADSBOTHR6;
send_msg(fsck_BADSBOTHR, "6", fsck_ref_msg(which_super));
}
if (sb_ptr->s_agsize < (1 << L2BPERDMAP)) {
vs_rc = FSCK_BADSBAGSIZ;
send_msg(fsck_BADSBAGSIZ, fsck_ref_msg(which_super));
} else {
/* else the alloc group size is possibly correct */
agg_blks_in_aggreg =
sb_ptr->s_size * sb_ptr->s_pbsize / sb_ptr->s_bsize;
agl2size =
ujfs_getagl2size(agg_blks_in_aggreg,
sb_ptr->s_bsize);
/* get the allocation group size */
agsize = (int64_t) 1 << agl2size;
if (sb_ptr->s_agsize != agsize) {
vs_rc = FSCK_BADAGFSSIZ;
send_msg(fsck_BADSBAGSIZ, fsck_ref_msg(which_super));
}
}
if (!vs_rc) {
/*
* check out the fsck in-aggregate workspace
*/
fsck_length_from_pxd = lengthPXD(&(sb_ptr->s_fsckpxd));
fsck_start_from_pxd = addressPXD(&(sb_ptr->s_fsckpxd));
agg_blks_in_aggreg = fsck_length_from_pxd +
(sb_ptr->s_size * sb_ptr->s_pbsize /
sb_ptr->s_bsize);
if (agg_blks_in_aggreg > agg_blks_on_device) {
/* wsp length is bad */
vs_rc = FSCK_BADSBFWSL1;
send_msg(fsck_BADSBFWSL1, fsck_ref_msg(which_super));
} else {
fsck_blkmap_size_pages =
((agg_blks_in_aggreg +
(BITSPERPAGE - 1)) / BITSPERPAGE) + 1 +
50;
/* size in aggregate blocks */
fsck_blkmap_size_blks =
(fsck_blkmap_size_pages << L2PSIZE) /
sb_ptr->s_bsize;
/*
* aggregate block offset of the
* fsck workspace in the aggregate.
*/
fsck_blkmap_start_blks =
agg_blks_in_aggreg - fsck_blkmap_size_blks;
if (fsck_length_from_pxd !=
fsck_blkmap_size_blks) {
/*
* length of fsck in-aggregate
* workspace is incorrect
*/
vs_rc = FSCK_BADSBFWSL;
send_msg(fsck_BADSBFWSL,
fsck_ref_msg(which_super));
}
if (fsck_start_from_pxd !=
fsck_blkmap_start_blks) {
/*
* address of fsck in-aggregate
* workspace is incorrect
*/
vs_rc = FSCK_BADSBFWSA;
send_msg(fsck_BADSBFWSA,
fsck_ref_msg(which_super));
}
}
}
if (!vs_rc) {
/*
* check out the in-aggregate journal log
*
* if there is one it starts at the end of the fsck
* in-aggregate workspace.
*/
jlog_length_from_pxd = lengthPXD(&(sb_ptr->s_logpxd));
jlog_start_from_pxd = addressPXD(&(sb_ptr->s_logpxd));
if (jlog_start_from_pxd != 0) {
/* there's one in there */
if (jlog_start_from_pxd != agg_blks_in_aggreg) {
/*
* address of in-aggregate
* journal log is incorrect
*/
vs_rc = FSCK_BADSBFJLA;
send_msg(fsck_BADSBFJLA,
fsck_ref_msg(which_super));
}
agg_blks_in_aggreg += jlog_length_from_pxd;
if (agg_blks_in_aggreg > agg_blks_on_device) {
/* log length is bad */
vs_rc = FSCK_BADSBFJLL;
send_msg(fsck_BADSBFJLL,
fsck_ref_msg(which_super));
}
}
}
}
return (vs_rc);
}
/*****************************************************************************
* NAME: validate_superblock
*
* FUNCTION: Verify that the primary superblock is valid.
* If not, verify that the secondary superblock is valid.
*
* PARAMETERS: none
*
* NOTES: If this routine returns 0 then the superblock
* I/O buffer contains a valid superblock.
*
* This routine also exists in fsck code. When there is time,
* examine both copies for differences and put the combined
* copy in libfs to eliminate extra code.
*
* RETURNS:
* success: 0
* failure: something else
*/
int validate_superblock()
{
int vsb_rc = 0;
int primary_sb_bad = 1;
int secondary_sb_bad = 1;
int which_sb = 0;
/* get primary */
vsb_rc = ujfs_get_superblk(Dev_IOPort, sb_ptr, 1);
if (vsb_rc != 0) {
/* if read primary fails */
send_msg(fsck_CNTRESUPP);
} else {
/* got primary superblock */
which_sb = fsck_primary;
primary_sb_bad = validate_super(fsck_primary);
}
if (primary_sb_bad) {
/* can't use the primary superblock */
send_msg(fsck_SBBADP);
/* get 2ndary */
vsb_rc = ujfs_get_superblk(Dev_IOPort, sb_ptr, 0);
if (vsb_rc != 0) {
send_msg(fsck_CNTRESUPS);
} else {
/* got secondary superblock */
which_sb = fsck_secondary;
secondary_sb_bad = validate_super(fsck_secondary);
}
if (!secondary_sb_bad) {
/* secondary is ok */
vsb_rc = 0;
} else {
send_msg(fsck_SBBADS);
}
}
if ((!primary_sb_bad) || (!secondary_sb_bad)) {
/* the buffer holds a valid superblock */
/* aggregate block size */
local_recptr->ag_blk_size = sb_ptr->s_bsize;
send_msg(fsck_XCHKLOGSBOK, fsck_ref_msg(which_sb));
}
return (vsb_rc);
}