1830 lines
54 KiB
C
1830 lines
54 KiB
C
static char sccsid[] = "@(#)93 1.43 src/bos/usr/bin/sysdumpdev/sysdumpdev.c, cmddump, bos41J, 9515B_all 4/13/95 13:43:06";
|
|
|
|
/*
|
|
* COMPONENT_NAME: CMDDUMP system dump control and formatting
|
|
*
|
|
* FUNCTIONS: sysdumpdev
|
|
*
|
|
* ORIGINS: 27
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 1988, 1993
|
|
* All Rights Reserved
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/param.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <sys/err_rec.h>
|
|
#include <sys/dump.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/cfgodm.h>
|
|
#include <sys/errids.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <locale.h>
|
|
#include <sys/access.h>
|
|
#include <sys/vmount.h>
|
|
#include <sys/vnode.h>
|
|
#include <cf.h>
|
|
#include <sys/cfgdb.h>
|
|
#include <ras.h>
|
|
#include <cmddump_msg.h>
|
|
#include <errlg/SWservAt.h>
|
|
#include <nl_types.h>
|
|
#include <sys/systemcfg.h>
|
|
#define MCS_CATALOG "cmddump.cat"
|
|
|
|
/* Network dump */
|
|
#include <sys/socket.h>
|
|
#include <sys/file.h>
|
|
|
|
#include <net/af.h>
|
|
#include <netdb.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/ip_icmp.h>
|
|
#include <netinet/in_netarp.h>
|
|
#include <sys/select.h>
|
|
#include <rpc/rpc.h>
|
|
#include <rpc/clnt.h>
|
|
#include <sys/vfs.h>
|
|
#include <sys/vmount.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/syspest.h>
|
|
#include <grp.h>
|
|
|
|
#define NFS_FHSIZE 32
|
|
#define MOUNTPROG 100005
|
|
#define MOUNTPROC_MNT 1
|
|
#define MOUNTVERS 1
|
|
#define ERPC (10000)
|
|
|
|
#define FAILED_COPY_MESSAGE "15"
|
|
#define ALLOWED_COPY_MESSAGE "18"
|
|
|
|
static bool_t xdr_path();
|
|
static bool_t xdr_fhstatus();
|
|
static bool_t xdr_fhandle();
|
|
/*
|
|
* Fake errno for RPC failures that don't map to real errno's
|
|
*/
|
|
|
|
struct fhstatus {
|
|
int fhs_status;
|
|
fhandle_t fhs_fh;
|
|
};
|
|
|
|
struct hostent *hp;
|
|
struct fhstatus fhs;
|
|
/* Network dump */
|
|
|
|
extern char *Progname;
|
|
|
|
#include <sys/devinfo.h>
|
|
|
|
#define VCPY(from,to_array) \
|
|
strncpy(to_array,from,sizeof(to_array)); \
|
|
to_array[sizeof(to_array)-1] = '\0';
|
|
|
|
extern int errno;
|
|
extern optind; /* set by getopt system call */
|
|
extern char *optarg; /* set by getopt system call */
|
|
|
|
static int Dmpfd = -1;
|
|
static char *Pdevname = NULL; /* pointer to the string that contains the current prim dump device */
|
|
static char *Sdevname = NULL; /* pointer to the string that contains the current sec dump device */
|
|
static char *Sdevname2 = NULL; /* pointer to the string that contains the current sec dump device */
|
|
static char *tPdevname = NULL; /* pointer to the string that contains the default prim dump device */
|
|
static char *tSdevname = NULL; /* pointer to the string that contains the default sec dump device */
|
|
static char *tSdevname2 = NULL; /* pointer to the string that contains the default sec dump device */
|
|
static char *nPdevname = NULL; /* temporary work pointer */
|
|
static char *nSdevname = NULL; /* temporary work pointer */
|
|
static char *Pdevarg = NULL; /* pointer to the string of the input primary dump device */
|
|
static char *remote_fn = NULL; /* pointer to the string of the remote filename*/
|
|
static char *Sdevarg = NULL; /* pointer to the string of the input secondary dump device */
|
|
static char *Copyfilename = NULL; /* pointer to the string of the file where the dump is copied */
|
|
static char *Forcecopyflag = NULL; /* pointer to the string of the forcecopy flag */
|
|
|
|
static char *Sysdump = "/dev/sysdump";
|
|
static char *SysNull = "/dev/sysdumpnull";
|
|
static char *SysFile = "/dev/sysdumpfile";
|
|
static char *DevNull = "/dev/null";
|
|
|
|
static int permflg = 0; /* -P make the dump device specified
|
|
by the -p or -s flags permanent */
|
|
static int odmflg = 0; /* this flag is used to see if permanent
|
|
setting should be used */
|
|
static int infoflg = 0; /* DMP_IOCINFO */
|
|
static int lineflg = 0; /* show info line containing size and device name */
|
|
static int showflg = 0; /* show current dump devices */
|
|
static int quietflg = 0; /* -q don't print values after init by odm */
|
|
static int sizeflg = 0; /* -e estimate the size of dump in bytes */
|
|
|
|
|
|
|
|
static struct CuAt *cuattr;
|
|
static char *Corearg = NULL; /* used with -D / -d flags to specify where
|
|
the dump is to be copied at the boot time */
|
|
static int Coreval = 0; /* value for forcecopydump system attribute */
|
|
|
|
/* This structure is used to access the attribute ODM data base */
|
|
struct od_data {
|
|
char *attr_name;
|
|
struct SWservAt *swservp;
|
|
};
|
|
|
|
struct od_data od_list[] = {
|
|
#define TPRIMARY 0
|
|
{ "tprimary", NULL },
|
|
#define TSECONDARY 1
|
|
{ "tsecondary", NULL },
|
|
#define PRIMARY 2
|
|
{ "primary", NULL },
|
|
#define SECONDARY 3
|
|
{ "secondary", NULL },
|
|
#define AUTOCOPY 4
|
|
{ "autocopydump", NULL },
|
|
#define FORCECOPY 5
|
|
{ "forcecopydump", NULL }
|
|
#define OD_LIST 6
|
|
};
|
|
|
|
#define INFO_DUMP 1
|
|
#define INFO_TYPE 2
|
|
#define INFO_LINE 3
|
|
#define CRITSIZE 256
|
|
|
|
static void dmpinfo();
|
|
static void odminit();
|
|
static void odmread();
|
|
static void odmwrite();
|
|
static long rdev();
|
|
static void usage_dev();
|
|
static int getfh();
|
|
static int check_remote_hostname();
|
|
static int reclaim_remote_file_space();
|
|
static void error_if_multiprocessor();
|
|
|
|
/*
|
|
* NAME: main
|
|
* FUNCTION:
|
|
* process the command line options
|
|
* invoke the specific function to do
|
|
* the specified tasks.
|
|
* the supported tasks are:
|
|
* -L list the information about the previous dump
|
|
* -e estimate the size of the system dump
|
|
* -r free the space used for remote dump on the server
|
|
* -z list the information about the most recent dump
|
|
* -d Directory specifies the directory where the
|
|
* dump is copied to at boot time. If the copy
|
|
* fails the system continues to boot.
|
|
* -D Directory specifies the directory where the
|
|
* dump is copied to at boot time. If the copy
|
|
* fails then a menu is displayed to allow user
|
|
* to copy the dump.
|
|
* -l list the dump device information
|
|
* -p configure the primary dump device
|
|
* -s configure the secondary dump devices
|
|
* -P make permanent the dump device specified by
|
|
* the -p or -s flags. Can only be used with -p or -s
|
|
* flags.
|
|
* INPUTS: argc, argv
|
|
* DEPENDENCIES:
|
|
* This function depends on the following commands:
|
|
* ping
|
|
* lslv
|
|
*
|
|
* RETURNS: 0 - successful
|
|
* -1 - unsuccessful
|
|
*
|
|
*/
|
|
main(argc,argv)
|
|
char *argv[];
|
|
{
|
|
int c;
|
|
struct dumpinfo dumpinfo;
|
|
struct devinfo devinfo;
|
|
dev_t nulldev = rdev(SysNull,TRUE);
|
|
dev_t pridev, secdev, pridevn, secdevn;
|
|
int usage_cnt = 0;
|
|
int len,rv;
|
|
char *next;
|
|
char *pathname;
|
|
char cmdline[80];
|
|
char location_code[NFS_FHSIZE];
|
|
int cnt;
|
|
|
|
setlocale(LC_ALL,""); /* set Locale */
|
|
catinit(MCS_CATALOG); /* init message catalog */
|
|
setprogname(); /* set the Progname */
|
|
while((c = getopt(argc,argv,"eqLzlPp:r:s:D:d:")) != EOF) {
|
|
switch(c) {
|
|
case 'q':
|
|
quietflg++;
|
|
break;
|
|
case 'e':
|
|
sizeflg++;
|
|
break;
|
|
case 'l':
|
|
showflg++;
|
|
break;
|
|
case 'L':
|
|
infoflg++;
|
|
break;
|
|
case 'z':
|
|
lineflg++;
|
|
break;
|
|
case 'P':
|
|
permflg++;
|
|
break;
|
|
case 'p':
|
|
Pdevarg = stracpy(optarg);
|
|
break;
|
|
case 'r':
|
|
remote_fn = stracpy(optarg);
|
|
break;
|
|
case 's':
|
|
Sdevarg = stracpy(optarg);
|
|
break;
|
|
case 'D':
|
|
Corearg = stracpy(optarg);
|
|
Coreval = 1; /* used to differencate between d and D */
|
|
break;
|
|
case 'd':
|
|
Corearg = stracpy(optarg);
|
|
Coreval = 0; /* used to differenciate between d and D */
|
|
break;
|
|
|
|
default:
|
|
usage_cnt++;
|
|
}
|
|
}
|
|
if ((optind < argc) || usage_cnt)
|
|
usage_dev();
|
|
|
|
if ((Dmpfd = open(Sysdump,0)) < 0)
|
|
cat_fatal(CAT_SYSDUMP,
|
|
"Cannot open dump device %s.\n\t%s",Sysdump,errstr());
|
|
|
|
if (infoflg) { /* sysdumpdev -L */
|
|
dmpinfo(Dmpfd, DMP_IOCSTAT, INFO_DUMP);
|
|
exit(0);
|
|
}
|
|
|
|
if (sizeflg) { /* sysdumpdev -e */
|
|
rv = calculate_size(Dmpfd);
|
|
exit(rv);
|
|
}
|
|
|
|
if (remote_fn) { /* sysdumpdev -r */
|
|
rv = reclaim_remote_file_space();
|
|
exit(rv);
|
|
}
|
|
|
|
if (lineflg) { /* sysdumpdev -z */
|
|
dmpinfo(Dmpfd,DMP_IOCSTAT2, INFO_LINE);
|
|
exit(0);
|
|
}
|
|
|
|
odminit(); /* Get ready to access ODM data base */
|
|
|
|
if (Corearg != NULL) /* sysdumpdev -D|-d */
|
|
{
|
|
rv = set_core_file(Corearg,Coreval);
|
|
exit(rv);
|
|
}
|
|
|
|
/* set dumpdevices their defaults */
|
|
odmread(); /* Pdevname, Sdevname, tPdevname, tSdevname are set here */
|
|
|
|
if (showflg) { /* sysdumpdev -l . Print out current assignments */
|
|
dmpinfo(Dmpfd, IOCINFO, INFO_TYPE);
|
|
exit(0);
|
|
}
|
|
|
|
if ( permflg && !(Pdevarg || Sdevarg)) { /* -P must be used with
|
|
-p or -s flag */
|
|
usage_dev();
|
|
|
|
}
|
|
|
|
|
|
|
|
dmp_cklog(Dmpfd); /* check if we should log a dump */
|
|
|
|
/* If no flag is specified, get the default settings */
|
|
if ( (!showflg & !infoflg & !Pdevarg & !Sdevarg) )
|
|
odmflg++;
|
|
|
|
if (!quietflg) /* -q is not specified then show the primary
|
|
and secondary dump devices after the
|
|
completion of the device configuration */
|
|
showflg++;
|
|
/* store the names of the current and permanent device for
|
|
duplication checking */
|
|
Sdevname2 = Sdevname;
|
|
tSdevname2 = tSdevname;
|
|
if (Sdevarg)
|
|
{
|
|
Sdevname2 = stracpy(Sdevarg);
|
|
if (permflg)
|
|
tSdevname2 = stracpy(Sdevarg);
|
|
}
|
|
/* Take care of the special case: /dev/null */
|
|
if ( (strcmp(Pdevarg,DevNull) == 0) || (strcmp(Sdevarg,DevNull) == 0) )
|
|
{
|
|
cat_eprint(CAT_INVALID_DEV,
|
|
"%s is not a valid dump device.\n",DevNull);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
if (Pdevarg) {
|
|
/* Check to see if new primary device conflicts with
|
|
** - the old secondary device. (if not being explicitly changed)
|
|
** - the new secondary device. (if one is being defined)
|
|
** - for default setting, also check the default secondary device.
|
|
*/
|
|
pridev = rdev(Pdevarg,FALSE);
|
|
|
|
if ( permflg ) /* for default setting */
|
|
{
|
|
if ( Sdevarg ) /* new sec. device is being defined */
|
|
{
|
|
if ( (strcmp(Pdevarg,SysNull) != 0) && (strcmp(Pdevarg,Sdevarg) == 0 ) ) {
|
|
cat_eprint(CAT_DUP_DEV,
|
|
"Primary and secondary dump devices cannot be the same.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((strcmp(Pdevarg,SysNull) != 0) && ((strcmp(Pdevarg,Sdevname2) == 0 ) || /* current secondary device */
|
|
(strcmp(Pdevarg,tSdevname2) == 0 ))) /* default secondary device */
|
|
{
|
|
cat_eprint(CAT_DUP_DEV,
|
|
"Primary and secondary dump devices cannot be the same.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
/* if permanent change, everything looks good
|
|
then setting the default setting to the new setting. */
|
|
tPdevname = stracpy(Pdevarg);
|
|
}
|
|
else
|
|
{
|
|
if ((strcmp(Pdevarg,SysNull) != 0 ) && (strcmp(Pdevarg,Sdevname2) == 0 )) { /* current secondary device */
|
|
cat_eprint(CAT_DUP_DEV,
|
|
"Primary and secondary dump devices cannot be the same.\n");
|
|
exit(1);
|
|
}
|
|
|
|
}
|
|
Pdevname = stracpy(Pdevarg);
|
|
}
|
|
else if ( odmflg )
|
|
Pdevname = stracpy(tPdevname);
|
|
|
|
if (Sdevarg) {
|
|
/* Check to see if the new secondary devices is the same as the
|
|
** primary device that we are about to set.
|
|
*/
|
|
if ( (strcmp(Sdevarg,SysNull) != 0 ) && (strcmp(Sdevarg, Pdevname) == 0 )) {
|
|
cat_eprint(CAT_DUP_DEV,
|
|
"Primary and secondary dump devices cannot be the same.\n");
|
|
exit(1);
|
|
}
|
|
if ( permflg )
|
|
if ((strcmp(Sdevarg,SysNull) != 0) && (strcmp(Sdevarg, tPdevname) == 0 ))
|
|
{
|
|
cat_eprint(CAT_DUP_DEV,
|
|
"Primary and secondary dump devices cannot be the same.\n");
|
|
exit(1);
|
|
}
|
|
else tSdevname = stracpy(Sdevarg);
|
|
Sdevname = stracpy(Sdevarg);
|
|
}
|
|
else if ( odmflg )
|
|
Sdevname = stracpy(tSdevname);
|
|
|
|
memset(&dumpinfo,0,sizeof(dumpinfo));
|
|
|
|
/* Now we are about to configure the primary dump device */
|
|
|
|
if (Pdevname) {
|
|
pridev = rdev(Pdevname,FALSE);
|
|
VCPY(Pdevname,dumpinfo.dm_devicename);
|
|
/* Check for network dump device by inspecting the input string */
|
|
/* of the form of hostname:pathname */
|
|
nPdevname = stracpy(Pdevname);
|
|
if ( (next = strchr(nPdevname, ':' )) != NULL )
|
|
{
|
|
|
|
/* Remote dump is not supported on multiprocessor machines. */
|
|
error_if_multiprocessor();
|
|
|
|
/* separate hostname(or host address) and pathname */
|
|
*next++ = '\0';
|
|
pathname = stracpy(next);
|
|
|
|
/* ping the remote name to refresh the arp table */
|
|
sprintf(cmdline,"ping -c 1 -s 1 %s 2>/dev/null 1>/dev/null",nPdevname);
|
|
if ( system(cmdline))
|
|
{
|
|
cat_eprint(CAT_HOSTUNREACH,
|
|
"%s does not respond or is not reachable.\n",nPdevname);
|
|
exit(1);
|
|
}
|
|
|
|
/* get the IP address of the server (remote host) */
|
|
hp = gethostbyname(nPdevname);
|
|
if (hp == NULL) {
|
|
cat_eprint(CAT_HOSTUNREACH,
|
|
"%s does not respond or is not reachable.\n",nPdevname);
|
|
exit(1);
|
|
}
|
|
|
|
bcopy(hp->h_addr,(caddr_t)&dumpinfo.dm_hostIP,hp->h_length);
|
|
|
|
/* Check to make sure the remote host name is not */
|
|
/* the same as the local hostname */
|
|
|
|
if (rv = check_remote_hostname(nPdevname))
|
|
{
|
|
exit(rv);
|
|
}
|
|
|
|
/* get the filehandle of the dumpfile on server */
|
|
|
|
if (rv = getfh(nPdevname,pathname))
|
|
{
|
|
exit(rv);
|
|
}
|
|
else /* save the filehandle for the device driver call */
|
|
bcopy(fhs.fhs_fh.x,&dumpinfo.dm_filehandle,NFS_FHSIZE);
|
|
}
|
|
/****************************************************************/
|
|
/* Get the location code if the dump device is a logical volume.*/
|
|
/* The location code is stored in dumpinfo.dm_filehandle field. */
|
|
/****************************************************************/
|
|
if ( (strcmp(Pdevname,SysNull) != 0) &&
|
|
(strcmp(Pdevname,SysFile) != 0) &&
|
|
(strncmp(Pdevname,"/dev/",5) == 0) )
|
|
{
|
|
/* Use the "lslv" command to determine if it's a logical volume */
|
|
next = Pdevname + 5;
|
|
sprintf(cmdline,"lslv %s 2>/dev/null 1>/dev/null",next);
|
|
if ( (system(cmdline)) == 0 )
|
|
{
|
|
if (rv = get_location_code(&location_code,Pdevname))
|
|
exit(rv);
|
|
else
|
|
VCPY(location_code,dumpinfo.dm_filehandle);
|
|
}
|
|
}
|
|
|
|
/* issue ioctl to device driver to set the primary dump device */
|
|
dumpinfo.dm_mmdev = pridev;
|
|
if (ioctl(Dmpfd,DMPSET_PRIM,&dumpinfo) < 0)
|
|
{
|
|
if (quietflg)
|
|
{
|
|
Pdevname = SysNull;
|
|
VCPY(SysNull,dumpinfo.dm_devicename);
|
|
dumpinfo.dm_mmdev = nulldev;
|
|
if (ioctl(Dmpfd,DMPSET_PRIM,&dumpinfo) < 0)
|
|
{
|
|
cat_eprint(CAT_DMPSET,
|
|
"Cannot set primary dump device %s.\n\t%s\n",
|
|
SysNull, errstr());
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cat_eprint(CAT_DMPSET,
|
|
"Cannot set primary dump device %s.\n\t%s\n",
|
|
Pdevname,errstr());
|
|
exit(1);
|
|
}
|
|
}
|
|
} else {
|
|
VCPY(SysNull,dumpinfo.dm_devicename);
|
|
dumpinfo.dm_mmdev = nulldev;
|
|
if (ioctl(Dmpfd,DMPSET_PRIM,&dumpinfo) < 0)
|
|
{
|
|
cat_eprint(CAT_DMPSET,
|
|
"Cannot set primary dump device %s.\n\t%s\n",
|
|
SysNull, errstr());
|
|
exit(1);
|
|
}
|
|
}
|
|
/* Now we are about to configure the secondary dump device */
|
|
if (Sdevname) {
|
|
VCPY(Sdevname,dumpinfo.dm_devicename);
|
|
secdev = rdev(Sdevname,FALSE);
|
|
dumpinfo.dm_mmdev = secdev;
|
|
/* Check for network dump device by inspecting the input string */
|
|
/* of the form of hostname:pathname */
|
|
nSdevname = stracpy(Sdevname);
|
|
if ( (next = strchr(nSdevname, ':' )) != NULL )
|
|
{
|
|
|
|
/* Remote dump is not supported on multiprocessor machines. */
|
|
error_if_multiprocessor();
|
|
|
|
/* separate hostname(or host address) and pathname */
|
|
*next++ = '\0';
|
|
pathname = stracpy(next);
|
|
|
|
/* ping the remote name to refresh the arp table */
|
|
/* dependency on the ping command */
|
|
sprintf(cmdline,"ping -c 1 -s 1 %s 2>/dev/null 1>/dev/null",nSdevname);
|
|
if ( system(cmdline))
|
|
{
|
|
cat_eprint(CAT_HOSTUNREACH,
|
|
"%s does not respond or is not reachable.\n",nSdevname);
|
|
exit(1);
|
|
}
|
|
|
|
/* get the IP address of the server (remote host) */
|
|
hp = gethostbyname(nSdevname);
|
|
if (hp == NULL) {
|
|
cat_eprint(CAT_HOSTUNREACH,
|
|
"%s does not respond or is not reachable.\n",nSdevname);
|
|
exit(1);
|
|
}
|
|
|
|
bcopy(hp->h_addr,(caddr_t)&dumpinfo.dm_hostIP,hp->h_length);
|
|
|
|
/* Check to make sure the remote host name is not */
|
|
/* the same as the local hostname */
|
|
|
|
if (rv = check_remote_hostname(nSdevname))
|
|
{
|
|
exit(rv);
|
|
}
|
|
|
|
/* get the filehandle of the dumpfile on server */
|
|
if (rv = getfh(nSdevname,pathname))
|
|
{
|
|
exit(rv);
|
|
}
|
|
else /* save the filehandle for the device driver call */
|
|
bcopy(fhs.fhs_fh.x,&dumpinfo.dm_filehandle,NFS_FHSIZE);
|
|
}
|
|
/****************************************************************/
|
|
/* Get the location code if the dump device is a logical volume.*/
|
|
/* The location code is stored in dumpinfo.dm_filehandle field. */
|
|
/****************************************************************/
|
|
if ( (strcmp(Sdevname,SysNull) != 0) &&
|
|
(strcmp(Sdevname,SysFile) != 0) &&
|
|
(strncmp(Sdevname,"/dev/",5) == 0) )
|
|
{
|
|
/* Use the "lslv" command to determine if it's a logical volume */
|
|
next = Sdevname + 5;
|
|
sprintf(cmdline,"lslv %s 2>/dev/null 1>/dev/null",next);
|
|
if ( (system(cmdline)) == 0 )
|
|
{
|
|
if (rv = get_location_code(&location_code,Sdevname))
|
|
exit(rv);
|
|
else
|
|
VCPY(location_code,dumpinfo.dm_filehandle);
|
|
}
|
|
}
|
|
/* issue ioctl to device driver to set the secondary dump device*/
|
|
if(ioctl(Dmpfd,DMPSET_SEC,&dumpinfo) < 0)
|
|
{
|
|
if (quietflg)
|
|
{
|
|
Sdevname = SysNull;
|
|
VCPY(SysNull,dumpinfo.dm_devicename);
|
|
dumpinfo.dm_mmdev = nulldev;
|
|
if (ioctl(Dmpfd,DMPSET_SEC,&dumpinfo) < 0)
|
|
{
|
|
cat_eprint(CAT_DMPSET,
|
|
"Cannot set secondary dump device %s.\n\t%s\n",
|
|
SysNull, errstr());
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cat_eprint(CAT_DMPSET,
|
|
"Cannot set secondary dump device %s.\n\t%s\n",
|
|
Sdevname,errstr());
|
|
exit(1);
|
|
}
|
|
}
|
|
} else {
|
|
VCPY(SysNull,dumpinfo.dm_devicename);
|
|
dumpinfo.dm_mmdev = nulldev;
|
|
if (ioctl(Dmpfd,DMPSET_SEC,&dumpinfo) < 0)
|
|
{
|
|
cat_eprint(CAT_DMPSET,
|
|
"Cannot set secondary dump device %s.\n\t%s\n",
|
|
SysNull, errstr());
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (permflg)
|
|
odmwrite(0);
|
|
else odmwrite(2);
|
|
if(showflg)
|
|
dmpinfo(Dmpfd, IOCINFO, INFO_TYPE);
|
|
exit(0);
|
|
}
|
|
|
|
static
|
|
void dmpinfo(dfd, iocval, info_type)
|
|
int dfd, iocval, info_type;
|
|
{
|
|
struct dumpinfo dumpinfo;
|
|
struct devinfo devinfo;
|
|
struct stat copyfilestat;
|
|
int invalid_devicename = 0;
|
|
int valid_copyfilename;
|
|
int fd;
|
|
char *Primary, *Secondary;
|
|
char *autocopy, *forcecopy;
|
|
char *s;
|
|
char t[100];
|
|
char buffer[MAXPATH];
|
|
char default_buffer[MAXPATH]; /* used to hold default message for catgets() */
|
|
char *allowed = FALSE;
|
|
char *token, *device, *file;
|
|
char *str;
|
|
char *failed_msg, *allowed_msg;
|
|
nl_catd savecr_catalog;
|
|
|
|
#define COPYFILENAME "/var/adm/ras/copyfilename"
|
|
|
|
bzero(buffer,MAXPATH);
|
|
bzero(default_buffer,MAXPATH);
|
|
|
|
switch(info_type) {
|
|
case INFO_DUMP:
|
|
if (0 > ioctl(dfd, iocval, &dumpinfo))
|
|
cat_fatal(CAT_IOCSTAT,
|
|
"Cannot read dump information from %s.\n\t%s", Sysdump, errstr());
|
|
|
|
/* Check if a number of the fields from the NVRAM are 0. If they
|
|
** are 0, report that there is no recorded dump.
|
|
*/
|
|
if ( (dumpinfo.dm_mmdev == 0) && (dumpinfo.dm_timestamp == 0) &&
|
|
(dumpinfo.dm_size == 0) ) {
|
|
cat_eprint(CAT_DMP_NOREC, "No previous dumps recorded.\n");
|
|
exit(2); /* used by SMIT for copying dump to diskette */
|
|
}
|
|
/* Check that the devicename has a "/" as the first character, or */
|
|
/* it has a colon in it to indicate that the dump device is remote. */
|
|
if ( (strcmp(dumpinfo.dm_devicename[0],'/') != 0) &&
|
|
(strchr(dumpinfo.dm_devicename,':') == NULL) )
|
|
invalid_devicename++;
|
|
|
|
/* This check is put in to make sure that we don't display garbage if */
|
|
/* nvram has become corrupted. We check that the size is not negative, */
|
|
/* the status is valid, and device name is good. If nvram is corrupt, */
|
|
/* we call ioctl with DMP_IOCINFO to write zeroes to our nvram block. */
|
|
if ( (dumpinfo.dm_size < 0) || (dumpinfo.dm_status > 0) ||
|
|
(dumpinfo.dm_status < -3) || (invalid_devicename) )
|
|
{
|
|
if (ioctl(dfd,DMP_IOCINFO,&dumpinfo) < 0)
|
|
perror("sysdumpdev: ioctl DMP_IOCINFO");
|
|
cat_eprint(CAT_DMP_NOREC, "No previous dumps recorded.\n");
|
|
exit(2);
|
|
}
|
|
strftime(t,100,"%c",localtime(&dumpinfo.dm_timestamp));
|
|
cat_print(CAT_DMP_DEVINFO2,
|
|
"\n\nDevice name: %s\nMajor device number: %d\nMinor device number: %d\nSize: %d bytes\nDate/Time: %s\nDump status: %d\n",
|
|
dumpinfo.dm_devicename,
|
|
major(dumpinfo.dm_mmdev),minor(dumpinfo.dm_mmdev),
|
|
dumpinfo.dm_size,
|
|
t,
|
|
dumpinfo.dm_status);
|
|
|
|
/* Put out information about where dump was copied.
|
|
This is kept in /var/adm/ras/copyfilename. */
|
|
if (stat(COPYFILENAME,©filestat) == 0)
|
|
if (copyfilestat.st_mtime > dumpinfo.dm_timestamp)
|
|
valid_copyfilename = TRUE;
|
|
else
|
|
valid_copyfilename = FALSE;
|
|
|
|
if ((access(COPYFILENAME, E_ACC) == 0) && valid_copyfilename)
|
|
{
|
|
if ( (fd = open(COPYFILENAME,O_RDONLY)) > 0 &&
|
|
(read(fd,&buffer,MAXPATH) > 0) )
|
|
{
|
|
str = stracpy(buffer);
|
|
if (strncmp(str,"/",1) == 0)
|
|
cat_print(CAT_COPY_FILENAME,
|
|
"Dump copy filename: %s\n",buffer);
|
|
else
|
|
{
|
|
/* The copycore command logs the message numbers of the messages */
|
|
/* that sysdumpdev should display. Parse the copyfilename, and */
|
|
/* print the correct messages. */
|
|
if ((token=strtok(str," ") != 0))
|
|
{
|
|
do
|
|
{
|
|
if (strcmp(token,FAILED_COPY_MESSAGE) == 0)
|
|
;
|
|
else if (strncmp(token,"DEVICE:",7) == 0)
|
|
{
|
|
device = strchr(token,':');
|
|
device = device + 1;
|
|
}
|
|
else if (strncmp(token,"FILE:",5) == 0)
|
|
{
|
|
file = strchr(token,':');
|
|
file = file + 1;
|
|
}
|
|
else if (strcmp(token,ALLOWED_COPY_MESSAGE) == 0)
|
|
{
|
|
allowed = TRUE;
|
|
}
|
|
}
|
|
while((token=strtok(NULL," ")) != NULL);
|
|
}
|
|
|
|
/* Open the savecr.cat catalog to get the messages. */
|
|
savecr_catalog = catopen("savecr.cat", NL_CAT_LOCALE);
|
|
|
|
sprintf(default_buffer,"Failed to copy the dump from %s to %s.\n",device,file);
|
|
|
|
/* Call catgets() to get message number 15 which is the "failed copy" message. */
|
|
failed_msg = stracpy(catgets(savecr_catalog,1,15,default_buffer));
|
|
|
|
/* If the default message and the message returned from catgets() */
|
|
/* are different, then print the message returned by catgets() */
|
|
/* with arguments. Otherwise, print the default message. */
|
|
if (strcmp(failed_msg,default_buffer) != 0)
|
|
fprintf(stderr,failed_msg,device,file);
|
|
else
|
|
fprintf(stderr,failed_msg);
|
|
|
|
/* The "allowed copy" message should be printed. */
|
|
if (allowed)
|
|
{
|
|
bzero(default_buffer,MAXPATH);
|
|
sprintf(default_buffer,"Allowed the customer to copy the dump to external media.\n");
|
|
allowed_msg = stracpy(catgets(savecr_catalog,1,18,default_buffer));
|
|
|
|
/* Print the message returned from catgets(). There are no arguments */
|
|
/* in this message, so we don't need to check the return from catgets(). */
|
|
fprintf(stderr,allowed_msg);
|
|
}
|
|
|
|
/* Close the savecr.cat message catalog. */
|
|
catclose(savecr_catalog);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case INFO_LINE:
|
|
/* If the NEEDCOPY flag is off, no data will be passed back
|
|
from the device driver but the return code is still zero.
|
|
In this case, dumpinfo should be filled with zero to indicate
|
|
there is no new dump recorded.
|
|
*/
|
|
bzero(&dumpinfo, sizeof(dumpinfo));
|
|
|
|
/* Cannot read dump info */
|
|
if (0 > ioctl(dfd, iocval, &dumpinfo))
|
|
exit(3);
|
|
|
|
/* Check if a number of the fields from the NVRAM are 0. If they
|
|
** are 0, return with the bad return coded */
|
|
if ( (dumpinfo.dm_mmdev == 0) && (dumpinfo.dm_timestamp == 0) &&
|
|
(dumpinfo.dm_size == 0) ) {
|
|
exit(2); /* used by SMIT for copying dump to diskette */
|
|
}
|
|
|
|
/* print size and device name */
|
|
printf("%d %s\n", dumpinfo.dm_size, dumpinfo.dm_devicename);
|
|
|
|
break;
|
|
|
|
case INFO_TYPE:
|
|
if (0 > ioctl(dfd, iocval, &devinfo))
|
|
cat_fatal(CAT_IOCINFO,"Cannot read dump device information from %s.\n\t%s", Sysdump, errstr());
|
|
/*
|
|
* fill in "primary" and "secondary" NLS strings
|
|
*/
|
|
|
|
if ( devinfo.un.dump.primary == -1 )
|
|
Pdevname = stracpy("-");
|
|
if ( devinfo.un.dump.secondary == -1 )
|
|
Sdevname = stracpy("-");
|
|
|
|
|
|
cat_string(CAT_PRIMARY,&s,"primary");
|
|
Primary = stracpy(s);
|
|
cat_string(CAT_SECONDARY,&s,"secondary");
|
|
Secondary = stracpy(s);
|
|
cat_string(CAT_AUTOCOPY,&s,"copy directory");
|
|
autocopy = stracpy(s);
|
|
cat_string(CAT_FORCECOPY,&s,"forced copy flag");
|
|
forcecopy = stracpy(s);
|
|
|
|
printf("%-20s %s\n", Primary, Pdevname);
|
|
printf("%-20s %s\n", Secondary, Sdevname);
|
|
printf("%-20s %s\n", autocopy, Copyfilename);
|
|
printf("%-20s %s\n", forcecopy,Forcecopyflag );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* end case */
|
|
}
|
|
|
|
static
|
|
void odminit()
|
|
{
|
|
if (0 > odm_initialize()) {
|
|
cat_fatal(CAT_ODMINIT, "Cannot initialize ODM.\n\t%s", errstr());
|
|
exit(-1);
|
|
}
|
|
|
|
odm_set_path("/etc/objrepos");
|
|
}
|
|
|
|
static
|
|
void odmread()
|
|
{
|
|
struct SWservAt *swservp;
|
|
int i, cnt, rv;
|
|
|
|
rv = 0;
|
|
for (i = 0; i < OD_LIST; i++) {
|
|
swservp = (struct SWservAt *)ras_getattr(od_list[i].attr_name, 0, &cnt);
|
|
Debug("odmread:[SWservAt] attr='%s' value='%s'\n", swservp->attribute,
|
|
swservp->value);
|
|
if (!cnt) continue;
|
|
if (PRIMARY == i)
|
|
{
|
|
Pdevname = stracpy(swservp->value);
|
|
}
|
|
else if (SECONDARY == i)
|
|
{
|
|
Sdevname = stracpy(swservp->value);
|
|
}
|
|
else if (TPRIMARY == i)
|
|
tPdevname = stracpy(swservp->value);
|
|
else if (TSECONDARY == i)
|
|
tSdevname = stracpy(swservp->value);
|
|
else if (AUTOCOPY == i)
|
|
Copyfilename = stracpy(swservp->value);
|
|
else if (FORCECOPY == i)
|
|
Forcecopyflag = stracpy(swservp->value);
|
|
od_list[i].swservp = swservp;
|
|
}
|
|
if ( (Pdevname == 0) && !quietflg)
|
|
{
|
|
cat_eprint(CAT_ODM_PRIM,
|
|
"Cannot read primary dump device from ODM object class SWservAt.\n");
|
|
rv = -1;
|
|
}
|
|
if ((Sdevname == 0) && !quietflg)
|
|
{
|
|
cat_eprint(CAT_ODM_SEC,
|
|
"Cannot read secondary dump device from ODM object class SWservAt.\n");
|
|
rv = -1;
|
|
}
|
|
if ((Copyfilename == 0) && !quietflg)
|
|
{
|
|
cat_eprint(CAT_GETATTR,
|
|
"Unable to get %s attribute from ODM object class SWservAt.\n","autocopydump");
|
|
rv = -1;
|
|
}
|
|
|
|
if ((Forcecopyflag == 0) && !quietflg)
|
|
{
|
|
cat_eprint(CAT_GETATTR,
|
|
"Unable to get %s attribute from ODM object class SWservAt.\n","forcecopydump");
|
|
rv = -1;
|
|
}
|
|
if ( rv != 0 )
|
|
exit(rv);
|
|
}
|
|
|
|
static
|
|
void odmwrite(start)
|
|
{
|
|
int i,j;
|
|
|
|
for (i = start; i < OD_LIST; i++) {
|
|
if ((TPRIMARY == i) && od_list[i].swservp)
|
|
od_list[i].swservp->value = tPdevname;
|
|
else if ((TSECONDARY == i) && od_list[i].swservp)
|
|
od_list[i].swservp->value = tSdevname;
|
|
else if ((PRIMARY == i) && od_list[i].swservp)
|
|
od_list[i].swservp->value = Pdevname;
|
|
else if ((SECONDARY == i) && od_list[i].swservp)
|
|
od_list[i].swservp->value = Sdevname;
|
|
j = ras_putattr(od_list[i].swservp);
|
|
}
|
|
|
|
savebase(); /* sync the putattr()'s */
|
|
|
|
/* Call the sync() routine to make sure the changes */
|
|
/* are written to disk. This is necessary if a dump */
|
|
/* happens before the syncd has had a chance to run. */
|
|
sync();
|
|
}
|
|
|
|
/*
|
|
* NAME: rdev
|
|
* FUNCTION: return the major/minor device number of the supplied filename
|
|
* INPUTS: devname filename to get major/minor of
|
|
* RETURNS: major/minor device number of 'devname'
|
|
*/
|
|
static
|
|
rdev(devname,msg)
|
|
char *devname;
|
|
int msg;
|
|
{
|
|
struct stat statbuf;
|
|
|
|
/* Check to see if the device is remote. If so, just */
|
|
/* return 0 for the major / minor number, because the */
|
|
/* network device drivers don't use /dev files and don't */
|
|
/* have major / minor numbers. */
|
|
if ( (strchr(devname, ':' )) != NULL )
|
|
return(0);
|
|
|
|
if(stat(devname,&statbuf)) {
|
|
if (msg) perror(devname);
|
|
return(-1);
|
|
}
|
|
return(statbuf.st_rdev);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* NAME: usage_dev
|
|
* FUNCTION: Output usage message for sysdumpdev and exit.
|
|
* INPUTS: None
|
|
* RETURNS: None (exits)
|
|
*/
|
|
static
|
|
void usage_dev()
|
|
{
|
|
|
|
cat_eprint(CAT_USAGEDEV,"\
|
|
Usage:\n\
|
|
%s [-P] [-p Device | -s Device]\n\
|
|
%s [-l | -q | -z | -r Host:Path | -p Device | -s Device | -L | -e]\n\
|
|
%s [-d | -D] Directory\n\
|
|
\n\
|
|
Change the primary and secondary dump device designations\n\
|
|
in a running system.\n\
|
|
\n\
|
|
-d Directory Specify the directory where the dump is copied to at\n\
|
|
boot time. If the copy fails the system continues to boot.\n\
|
|
-D Directory Specify the directory where the dump is copied to at\n\
|
|
boot time. If the copy fails then a menu is displayed\n\
|
|
to allow user to copy the dump.\n\
|
|
-e Estimate the size of the dump (in bytes) for the\n\
|
|
current running system.\n\
|
|
-l List the current dump device designations.\n\
|
|
-L Display statistical information about the previous dump.\n\
|
|
-p Device Change the primary dump device to the specified\n\
|
|
device temporarily.\n\
|
|
-P Make the dump device specified by -p or -s flags permanent.\n\
|
|
Can only be used with -p or -s flags.\n\
|
|
-q Suppress any error messages that are written\n\
|
|
to stdout.\n\
|
|
-r Host:Path Free the space used by the remote dump file.\n\
|
|
-s Device Change the secondary dump device to the specified\n\
|
|
device temporarily.\n\
|
|
-z Write out to stdout the string containing the size\n\
|
|
of the dump in bytes and the name of the dump device\n\
|
|
if a new dump is present.\n\
|
|
\n\
|
|
If no flag is specified, the permanent dump device designations are used.\n",
|
|
Progname,Progname,Progname);
|
|
exit(1);
|
|
}
|
|
|
|
#define MAX_DEVNAME 128
|
|
#define MAX_FNAME 52
|
|
#define COPYFILENAME "/var/adm/ras/copyfilename"
|
|
struct dmp_status {
|
|
struct err_rec0 err_rec;
|
|
struct {
|
|
char name[MAX_DEVNAME];
|
|
short maj;
|
|
short min;
|
|
off_t size;
|
|
char time[32];
|
|
int type;
|
|
int status;
|
|
char fname[MAX_FNAME];
|
|
} detail;
|
|
};
|
|
|
|
/* dmp_cklog:
|
|
** - does a DMP_IOCSTAT ioctl to get what nvram thinks is the most recent
|
|
** dump. If the DMPFL_NEEDLOG is set, then we dump the information from
|
|
** nvram to the errlog. The driver knows enough to set this flag off
|
|
** after this ioctl. It is our responsibility to errlog() it.
|
|
*/
|
|
|
|
dmp_cklog(fd)
|
|
int fd;
|
|
{
|
|
struct dumpinfo d;
|
|
char filename[MAXPATH];
|
|
|
|
if ((ioctl(fd,DMP_IOCSTAT,&d) >= 0) && (d.dm_flags & DMPFL_NEEDLOG)) {
|
|
struct dmp_status e;
|
|
char *t,*p;
|
|
|
|
e.err_rec.error_id = ERRID_DUMP_STATS;
|
|
strncpy(e.err_rec.resource_name,"SYSDUMP",ERR_NAMESIZE);
|
|
strncpy(e.detail.name,d.dm_devicename,MAX_DEVNAME);
|
|
e.detail.maj = major(d.dm_mmdev);
|
|
e.detail.min = minor(d.dm_mmdev);
|
|
e.detail.size = d.dm_size;
|
|
t = ctime(&d.dm_timestamp);
|
|
p = strrchr(t,'\n'); /* kill \n */
|
|
if (p != (char *)NULL) *p = '\0';
|
|
strncpy(e.detail.time,t,32);
|
|
e.detail.type = d.dm_type;
|
|
if (e.detail.type == DMPD_PRIM_HALT) e.detail.type = DMPD_PRIM;
|
|
if (e.detail.type == DMPD_SEC_HALT) e.detail.type = DMPD_SEC;
|
|
e.detail.status = d.dm_status;
|
|
/*****************************************************
|
|
if the dump is copied out to the filesystem,
|
|
/var/adm/ras/copyfilename
|
|
should exist and contains the full path name of file.
|
|
This file name should also be in the error log entry.
|
|
*****************************************************/
|
|
if ( access(COPYFILENAME, E_ACC) == 0 )
|
|
{
|
|
if ((fd = open(COPYFILENAME,O_RDONLY)) > 0 )
|
|
{
|
|
if ((lseek(fd,0,SEEK_SET) >= 0 ) &&
|
|
(read(fd,&filename,MAXPATH) > 0 ) )
|
|
{
|
|
/* put the file name in the detail record */
|
|
strncpy(e.detail.fname,filename,MAX_FNAME);
|
|
/* Now close COPYFILENAME */
|
|
close(fd);
|
|
}
|
|
else
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
/* log the entry */
|
|
errlog(&e, sizeof(struct dmp_status));
|
|
}
|
|
}
|
|
|
|
#define MAX_TRIES 3
|
|
|
|
/* NAME : getfh
|
|
FUNCTION : Get the file handle of the file on the server
|
|
from the server's mountd.
|
|
RETURN : zero - sucessful
|
|
non zero - error
|
|
*/
|
|
|
|
static int
|
|
getfh(host, object)
|
|
char *host;
|
|
char *object;
|
|
{
|
|
struct sockaddr_in sin;
|
|
struct hostent *hp;
|
|
int s,rv,num_tries ;
|
|
struct timeval timeout;
|
|
CLIENT *client;
|
|
enum clnt_stat rpc_stat;
|
|
|
|
rv = 0;
|
|
/*
|
|
* Get server's address
|
|
*/
|
|
|
|
if ((hp = gethostbyname(host)) == NULL) {
|
|
/*
|
|
* Failure may be due to yellow pages, try again
|
|
*/
|
|
if ((hp = gethostbyname(host)) == NULL) {
|
|
cat_eprint(CAT_HOSTUNREACH,
|
|
"Host %s does not respond or is not reachable.\n",
|
|
host);
|
|
rv = EHOSTUNREACH;
|
|
}
|
|
}
|
|
else {
|
|
|
|
/*
|
|
* get fhandle of remote path from server's mountd
|
|
*/
|
|
bzero(&sin, sizeof(sin));
|
|
bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
|
|
sin.sin_family = AF_INET;
|
|
timeout.tv_usec = 0;
|
|
timeout.tv_sec = 20;
|
|
s = RPC_ANYSOCK;
|
|
|
|
if ((client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS,
|
|
timeout, &s)) == NULL) {
|
|
rv = -1 ;
|
|
}
|
|
else {
|
|
client->cl_auth = authunix_create_default();
|
|
timeout.tv_usec = 0;
|
|
timeout.tv_sec = 20;
|
|
num_tries = 1;
|
|
while ( (num_tries == 1 ) || ((num_tries <= MAX_TRIES) && (rv == ETIMEDOUT )))
|
|
{
|
|
rpc_stat = clnt_call(client, MOUNTPROC_MNT, xdr_path, &object,
|
|
xdr_fhstatus, &fhs, timeout);
|
|
if (rpc_stat != RPC_SUCCESS) {
|
|
switch (rpc_stat) {
|
|
case RPC_TIMEDOUT:
|
|
rv = ETIMEDOUT;
|
|
case RPC_AUTHERROR:
|
|
rv = EACCES ;
|
|
case RPC_PMAPFAILURE:
|
|
case RPC_PROGNOTREGISTERED:
|
|
default:
|
|
rv = ERPC;
|
|
}
|
|
}
|
|
else
|
|
if (fhs.fhs_status != 0)
|
|
rv = fhs.fhs_status;
|
|
else rv = 0;
|
|
num_tries++;
|
|
}
|
|
clnt_destroy(client);
|
|
}
|
|
}
|
|
|
|
if (rv)
|
|
cat_eprint(CAT_UNABLE_TO_ACCESS,
|
|
"Unable to access file %s on host %s.\n",object,host);
|
|
return(rv);
|
|
}
|
|
|
|
static
|
|
xdr_fhstatus(xdrs, fhsp)
|
|
XDR *xdrs;
|
|
struct fhstatus *fhsp;
|
|
{
|
|
if (!xdr_int(xdrs, &fhsp->fhs_status))
|
|
return (FALSE);
|
|
if (fhsp->fhs_status == 0) {
|
|
if (!xdr_fhandle(xdrs, &fhsp->fhs_fh))
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
static bool_t
|
|
xdr_path(xdrs, pathp)
|
|
XDR *xdrs;
|
|
char **pathp;
|
|
{
|
|
if (xdr_string(xdrs, pathp, 1024)) {
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
static
|
|
xdr_fhandle(xdrs, fhp)
|
|
XDR *xdrs;
|
|
fhandle_t *fhp;
|
|
{
|
|
if (xdr_opaque(xdrs, (char *) fhp, NFS_FHSIZE)) {
|
|
return (TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
static
|
|
int reclaim_remote_file_space()
|
|
{
|
|
|
|
char *host_name;
|
|
char *dir_name;
|
|
char *path_name;
|
|
char *next;
|
|
char cmdline[256];
|
|
char *full_path;
|
|
char *file_name;
|
|
char *fn;
|
|
char local_dir[80];
|
|
int rv, pid, fd;
|
|
|
|
/* Pseudo:
|
|
** input: <hostname>:<pathname>
|
|
**
|
|
** Parse the input string to get hostname and pathname.
|
|
** Parse the pathname for dir_name and file_name.
|
|
** Mount the dir_name onto a known temporary dir,/usr/adm/ras/ddd_reclaim.
|
|
** If it is an unsuccessful mount, strip off the last part of the dir_name
|
|
** Mount the new dir_name until there is a sucessful mount or the
|
|
** dir_name is an empty string.
|
|
** Return an error message if the dirname is an empty string.
|
|
** Otherwise, open the file with O_TRUNC to set file pointer back to
|
|
** beginning of the file.
|
|
** Umount the file system.
|
|
*/
|
|
rv = 0;
|
|
|
|
/* Remote dump is not supported on multiprocessor machines. */
|
|
error_if_multiprocessor();
|
|
|
|
if ( ( path_name = strchr(remote_fn, ':')) == NULL )
|
|
cat_fatal(CAT_INV_INPUT,
|
|
"The input string should be in the form of <hostname>:<pathname>\n");
|
|
else
|
|
{
|
|
*path_name++ = '\0';
|
|
host_name = remote_fn;
|
|
|
|
/* ping the host name to see if we if the host name accessible */
|
|
sprintf(cmdline,"ping -c 1 -s 1 %s 2>/dev/null 1>/dev/null",host_name);
|
|
if ( system(cmdline) )
|
|
{
|
|
cat_fatal(CAT_HOSTUNREACH,
|
|
"%s does not respond or is not reachable.\n",host_name);
|
|
}
|
|
|
|
/* Parse the pathname for dir_name and file_name */
|
|
|
|
full_path = stracpy(path_name);
|
|
if ((fn = strrchr(path_name,'/')) == NULL)
|
|
cat_fatal(CAT_NO_PATH,
|
|
"Enter the full pathname to the file, %s, on the remote host %s.\n", path_name, host_name);
|
|
file_name = stracpy(fn);
|
|
*fn = '\0';
|
|
|
|
dir_name = path_name;
|
|
|
|
/* Create a temporary directory to mount the file system. */
|
|
pid = getpid();
|
|
sprintf(local_dir,"%s%d","/usr/adm/ras/r",pid);
|
|
if ( (rv = mkdir(local_dir,0755)) != 0)
|
|
cat_fatal(CAT_CANT_CREATE_TDIR,
|
|
"Unable to create the temporary directory %s.\n",local_dir);
|
|
|
|
/* mount the directory */
|
|
|
|
strcpy(cmdline,"mount ");
|
|
strcat(cmdline,host_name);
|
|
strcat(cmdline,":");
|
|
strcat(cmdline,dir_name);
|
|
strcat(cmdline," ");
|
|
strcat(cmdline,local_dir);
|
|
|
|
if ( rv = (system(cmdline)))
|
|
{ /* unable to mount */
|
|
cat_eprint(CAT_CANT_MOUNT,
|
|
"Unable to mount the directory %s from host %s\n",dir_name,host_name);
|
|
rv = -1;
|
|
}
|
|
else
|
|
{
|
|
/* Remove the file */
|
|
strcpy(cmdline,local_dir);
|
|
strcat(cmdline,file_name);
|
|
if ((fd = open(cmdline, O_WRONLY|O_TRUNC)) < 0)
|
|
{
|
|
/* Using perror here */
|
|
cat_eprint(CAT_UNABLE_TO_OPEN,
|
|
"Unable to open file %s on host %s.\n",full_path, host_name);
|
|
rv = -1;
|
|
}
|
|
else
|
|
close(fd);
|
|
|
|
/* Unmount the file system before exit */
|
|
strcpy(cmdline,"umount ");
|
|
strcat(cmdline,local_dir);
|
|
if (rv)
|
|
{
|
|
if (system(cmdline))
|
|
cat_eprint(CAT_CANT_UMOUNT,
|
|
"Unable to unmount %s.\n", local_dir);
|
|
}
|
|
else
|
|
{
|
|
if ( rv = (system(cmdline)))
|
|
{
|
|
cat_eprint(CAT_CANT_UMOUNT,
|
|
"Unable to unmount %s.\n", local_dir);
|
|
rv = -1;
|
|
}
|
|
}
|
|
}
|
|
/* Delete the temporary file */
|
|
rmdir(local_dir);
|
|
return(rv);
|
|
}
|
|
}
|
|
|
|
/*
|
|
NAME : check_remote_hostname
|
|
FUNCTION : Get the IP address of the remote hostname.
|
|
Compare this remote host address with each of the
|
|
addresses of the local host. If they are the same
|
|
as local host, return a non-zero return code,
|
|
otherwise return 0.
|
|
*/
|
|
|
|
static int
|
|
check_remote_hostname(host_name)
|
|
char *host_name;
|
|
{
|
|
int s;
|
|
char buf[BUFSIZ], *cp, *cplim;
|
|
struct ifconf ifc;
|
|
struct ifreq ifreq, *ifr;
|
|
struct hostent *hp; /* Pointer to host info */
|
|
struct sockaddr local;
|
|
struct sockaddr_in *local_host = (struct sockaddr_in *) &local;
|
|
struct sockaddr_in *sin;
|
|
int rv = 0;
|
|
|
|
bzero( (char *)&local, sizeof(struct sockaddr) );
|
|
hp = gethostbyname(host_name);
|
|
bcopy(hp->h_addr,(caddr_t)&local_host->sin_addr,hp->h_length);
|
|
|
|
|
|
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|
return(1);
|
|
|
|
ifc.ifc_len = sizeof (buf);
|
|
ifc.ifc_buf = buf;
|
|
if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
|
|
return(2);
|
|
|
|
ifr = ifc.ifc_req;
|
|
|
|
#define size(p) MAX((p).sa_len, sizeof(p))
|
|
|
|
cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
|
|
for (cp = buf; cp < cplim ;
|
|
cp += sizeof(ifr->ifr_name) + size(ifr->ifr_addr))
|
|
{
|
|
ifr = (struct ifreq *)cp;
|
|
|
|
if ( ifr->ifr_addr.sa_family == AF_INET)
|
|
{
|
|
sin = (struct sockaddr_in *)&ifr->ifr_addr;
|
|
if (local_host->sin_addr.s_addr == sin->sin_addr.s_addr )
|
|
{
|
|
cat_eprint(CAT_CANT_SAME,
|
|
"Remote host can not be the same as local host.\n");
|
|
rv = 3;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(rv);
|
|
}
|
|
|
|
|
|
/* NAME : calculate_size
|
|
FUNCTION : Issue an ioctl DMP_SIZE to the /dev/sysdump to get
|
|
the size of the memory allocated for kernel segment.
|
|
The estimation is size + 25 % of the size.
|
|
*/
|
|
|
|
static int
|
|
calculate_size(dfd)
|
|
int dfd;
|
|
{
|
|
struct devinfo devinfo;
|
|
int dump_size;
|
|
|
|
if (0 > ioctl(dfd, DMP_SIZE, &devinfo)) {
|
|
perror("sysdumpdev : ioctl (DMP_SIZE)");
|
|
exit (1);
|
|
}
|
|
dump_size = (devinfo.un.dump.mdt_size * 1.25 ) ;
|
|
cat_print(CAT_DUMP_SIZE,
|
|
"Estimated dump size in bytes: %d\n",dump_size);
|
|
exit(0);
|
|
}
|
|
|
|
/* NAME : get_location_code
|
|
FUNCTION :
|
|
The logical name is used to access the volume group id from ODM.
|
|
The volume group id is used to retrieve the physical volume id.
|
|
The physical volume id is used to access name of the physical volume.
|
|
The physical volume name is used to access the location code.
|
|
*/
|
|
|
|
static int
|
|
get_location_code(location_code,lv_name)
|
|
char *location_code;
|
|
char *lv_name;
|
|
{
|
|
int i;
|
|
char *bufptr;
|
|
struct CuAt *pcuat;
|
|
struct CuDv *pcudv;
|
|
struct listinfo stat_info;
|
|
char crit[CRITSIZE];
|
|
char buf[256];
|
|
FILE *fp;
|
|
int boot_type = 0;
|
|
|
|
/* get the LVID for the logical volume */
|
|
pcuat = (struct CuAt *)getattr(&lv_name[5],"lvserial_id" , 0, &i);
|
|
|
|
if (pcuat == NULL) {
|
|
cat_fatal(CAT_CANT_GETATTR,
|
|
"Unable to get attribute %s for %s in ODM.",
|
|
"lvserial_id",&lv_name[5]);
|
|
}
|
|
else
|
|
{
|
|
bufptr = strtok(pcuat->value,".");
|
|
sprintf(crit,"attribute = '%s' and value = '%s'","vgserial_id",bufptr);
|
|
pcuat = (struct CuAt *)odm_get_list(CuAt_CLASS,crit,&stat_info,1,1);
|
|
if (pcuat == NULL)
|
|
{
|
|
cat_fatal(CAT_CANT_GET_LIST,
|
|
"No attribute %s with the value of %s in ODM",
|
|
"vgserial_id",bufptr);
|
|
}
|
|
else if ( strcmp(pcuat->name,"rootvg") != 0)
|
|
{
|
|
/* This is for a dataless machine. It creates a local
|
|
volume group that's not called rootvg, and sets the
|
|
dump device to a logical volume on that device. We
|
|
call bootinfo -t. If it returns "5", then we know it's
|
|
a dataless machine and we don't care if it's in the
|
|
root volume group. */
|
|
sprintf(buf,"bootinfo -t");
|
|
if ((fp = popen(buf,"r")) == NULL)
|
|
{
|
|
perror("sysdumpdev: popen");
|
|
exit (1);
|
|
}
|
|
fscanf(fp,"%d",&boot_type);
|
|
pclose(fp);
|
|
if ((boot_type != 5) && (permflg))
|
|
cat_fatal(CAT_NOT_ROOTVG,
|
|
"%s is not in volume group rootvg.\n",lv_name);
|
|
}
|
|
sprintf(crit,"attribute = '%s' and name = '%s'","pv",pcuat->name);
|
|
pcuat = (struct CuAt *)odm_get_list(CuAt_CLASS,crit,&stat_info,1,1);
|
|
if ( (pcuat == NULL) )
|
|
{
|
|
cat_fatal(CAT_CANT_GET_PVID,
|
|
"Unable to get physical volume id for %s from ODM.\n",pcuat->name);
|
|
}
|
|
sprintf(crit,"attribute = '%s' and value = '%s'","pvid",pcuat->value);
|
|
pcuat = (struct CuAt *)odm_get_list(CuAt_CLASS,crit,&stat_info,1,1);
|
|
if ( (pcuat == NULL) )
|
|
{
|
|
cat_fatal(CAT_CANT_GET_PVNAME,
|
|
"Unable to get the physical volume name for %s from ODM.\n",pcuat->value);
|
|
}
|
|
sprintf(crit,"name = '%s'",pcuat->name);
|
|
pcudv = (struct CuDv *)odm_get_list(CuDv_CLASS,crit,&stat_info,1,1);
|
|
if ( pcudv == NULL )
|
|
{
|
|
cat_fatal(CAT_CANT_GET_LOC,
|
|
"Unable to get the location code for %s from ODM.\n",
|
|
pcuat->name);
|
|
}
|
|
else
|
|
{
|
|
strcpy(location_code,pcudv->location);
|
|
}
|
|
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
NAME : set_core_file
|
|
FUNCTION: Verify if the input file is a directory in the
|
|
local JFS.
|
|
Resolve the symbolic link to get the real filename.
|
|
Get the filesystem of the file
|
|
Get the mount point of the filesystem.
|
|
Check if the filesystem is on rootvg volume group
|
|
Save the filename, real filename, file system and
|
|
mount point, in ODM database.
|
|
*/
|
|
|
|
|
|
#define NEXT_VMT(vmtp) \
|
|
((vmtp) = (struct vmount *)((char *)(vmtp) + (vmtp)->vmt_length))
|
|
|
|
static set_core_file(dirname,Coreval)
|
|
char *dirname;
|
|
int Coreval;
|
|
{
|
|
struct SWservAt *swservp;
|
|
|
|
int cnt;
|
|
int size;
|
|
|
|
struct vmount *vmtp;
|
|
int i;
|
|
struct stat statbuf;
|
|
|
|
int nmounts;
|
|
struct vmount *vmountp;
|
|
char buff[BUFSIZ];
|
|
char mountpt[MAXPATH];
|
|
char lvname[MAXPATH];
|
|
char *bufptr;
|
|
struct CuAt *pcuat;
|
|
char crit[CRITSIZE];
|
|
struct listinfo stat_info;
|
|
|
|
|
|
/************************************/
|
|
/* /dev/null is special case. */
|
|
/************************************/
|
|
|
|
if ((strcmp(dirname,DevNull) == 0 ))
|
|
{
|
|
strcpy(lvname,dirname);
|
|
strcpy(mountpt,dirname);
|
|
}
|
|
else
|
|
{
|
|
/************************************/
|
|
/* get the status of the input file */
|
|
/************************************/
|
|
|
|
if (stat(dirname, &statbuf) < 0) {
|
|
perror(dirname);
|
|
return(-1);
|
|
}
|
|
|
|
/************************************/
|
|
/* Check if the input is a directory */
|
|
/************************************/
|
|
|
|
if (statbuf.st_type != VDIR)
|
|
{
|
|
cat_fatal(CAT_NOT_DIR,"%s is not a directory.\n",dirname);
|
|
}
|
|
|
|
/************************************/
|
|
/* Check if the input is in a local JFS */
|
|
/************************************/
|
|
|
|
if (statbuf.st_vfstype != MNT_JFS)
|
|
{
|
|
cat_fatal(CAT_NOT_JFS,"%s is not in a journaled filesystem.\n",dirname);
|
|
}
|
|
|
|
/************************************/
|
|
/* Resolve the symbolic link to get the real filename */
|
|
/************************************/
|
|
|
|
chdir(dirname);
|
|
getcwd(dirname,BUFSIZ); /* after the execution of this line
|
|
dirname should
|
|
contain the absolute pathname of the
|
|
that input file */
|
|
|
|
/************************************/
|
|
/* Get the file status structure of the real file */
|
|
/************************************/
|
|
/*
|
|
if (stat(dirname,&statbuf) < 0)
|
|
{
|
|
perror(dirname);
|
|
}
|
|
*/
|
|
size = BUFSIZ;
|
|
/* get the structure mount for all the filesystems */
|
|
/* try the operation until ok or a fatal error */
|
|
while (1) {
|
|
if ((vmountp = (struct vmount *)malloc((size_t)size)) == NULL)
|
|
{
|
|
cat_fatal(CAT_MALLOC,"Unable to allocate memory for mntctl call.\n");
|
|
}
|
|
|
|
/*
|
|
* perform the QUERY mntctl - if it returns > 0, that is the
|
|
* number of vmount structures in the buffer. If it returns
|
|
* -1, an error occured. If it returned 0, then look in
|
|
* first word of buffer for needed size.
|
|
*/
|
|
if ((nmounts = mntctl(MCTL_QUERY, size, (caddr_t)vmountp)) > 0)
|
|
{
|
|
/* OK, got it, now return */
|
|
break;
|
|
|
|
} else if (nmounts == 0) {
|
|
/* the buffer wasn't big enough .... */
|
|
/* .... get required buffer size */
|
|
size = *(int *)vmountp;
|
|
free((void *)vmountp);
|
|
|
|
} else {
|
|
/* some other kind of error occurred */
|
|
free((void *)vmountp);
|
|
cat_fatal(CAT_MOUNT_ERR,"Error in mntctl call. \n");
|
|
}
|
|
}
|
|
|
|
|
|
/************************************/
|
|
/* Find out what filesystem it's in by comparing vfs number from
|
|
statbuf and vmount struct
|
|
*/
|
|
/************************************/
|
|
for (vmtp = vmountp, i = 0; i < nmounts; NEXT_VMT(vmtp), ++i) {
|
|
if (statbuf.st_vfs == vmtp->vmt_vfsnumber)
|
|
break;
|
|
}
|
|
sprintf(lvname,"%s",vmt2dataptr(vmtp, VMT_OBJECT));
|
|
sprintf(mountpt,"%s",vmt2dataptr(vmtp, VMT_STUB));
|
|
|
|
/*************************************/
|
|
/* Make sure that the directory entered
|
|
is in one of the following filesystems:
|
|
/, /var, /usr, /tmp, /home */
|
|
/*************************************/
|
|
if (strcmp(mountpt,"/") && strcmp(mountpt, "/usr") &&
|
|
strcmp(mountpt,"/var") && strcmp(mountpt,"/tmp") &&
|
|
strcmp(mountpt,"/home"))
|
|
{
|
|
cat_fatal(CAT_BAD_MOUNTPT, "\
|
|
The specified directory %s must be in one of the \n\
|
|
following filesystems: /, /usr, /home, /tmp, /var\n", dirname);
|
|
}
|
|
/************************************/
|
|
/* Check to make sure the logical volume
|
|
is in the rootvg volume group
|
|
get the LVID for the logical volume.
|
|
LVID is made up from the volume group serial id. */
|
|
/************************************/
|
|
|
|
pcuat = (struct CuAt *)getattr(&lvname[5],"lvserial_id" , 0, &i);
|
|
|
|
if (pcuat != NULL) {
|
|
bufptr = strtok(pcuat->value,".");
|
|
|
|
sprintf(crit,"attribute = '%s' and value = '%s'","vgserial_id",
|
|
bufptr);
|
|
/************************************/
|
|
/* get the name of the volume group id
|
|
from the volume group serial id.
|
|
Compare the name with "rootvg" */
|
|
/************************************/
|
|
|
|
pcuat = (struct CuAt *)odm_get_list(CuAt_CLASS,crit,&stat_info,1
|
|
,1);
|
|
if ( (pcuat != NULL) && (strcmp(pcuat->name,"rootvg") != 0) )
|
|
{
|
|
|
|
cat_fatal(CAT_NOT_ROOTVG,
|
|
"%s is not in volume group rootvg.\n",dirname);
|
|
}
|
|
|
|
}
|
|
|
|
} /* end of else clause */
|
|
|
|
/************************************/
|
|
/* get current value of autocopydump */
|
|
/************************************/
|
|
|
|
swservp = (struct SWservAt *)ras_getattr("autocopydump", 0, &cnt);
|
|
if (swservp == NULL)
|
|
{
|
|
cat_fatal(CAT_GETATTR,
|
|
"Unable to get %s attribute from ODM object class SWservAt.\n","autocopydump");
|
|
}
|
|
|
|
/************************************/
|
|
/* save new value of autocopydump */
|
|
/************************************/
|
|
|
|
swservp->value = dirname;
|
|
if (ras_putattr(swservp) < 0)
|
|
{
|
|
cat_fatal(CAT_PUTATTR,
|
|
"Unable to put %s attribute into ODM object class SWservAt.\n","autocopydump");
|
|
}
|
|
|
|
/************************************/
|
|
/* get current value of copyfilesystem */
|
|
/************************************/
|
|
|
|
swservp = (struct SWservAt *)ras_getattr("copyfilesystem", 0, &cnt);
|
|
if (swservp == NULL)
|
|
{
|
|
cat_fatal(CAT_GETATTR,
|
|
"Unable to get %s attribute from ODM object class SWservAt.\n","copyfilesystem");
|
|
}
|
|
|
|
sprintf(buff,"%s,%s",lvname,mountpt);
|
|
|
|
/************************************/
|
|
/* save new value of copyfilesystem */
|
|
/************************************/
|
|
|
|
swservp->value = buff;
|
|
if (ras_putattr(swservp) < 0)
|
|
{
|
|
cat_fatal(CAT_PUTATTR,
|
|
"Unable to put %s attribute into ODM object class SWservAt.\n","copyfilesystem");
|
|
}
|
|
|
|
/************************************/
|
|
/* set forcecopydump attribute according to value of Coreval */
|
|
/************************************/
|
|
|
|
swservp = (struct SWservAt *)ras_getattr("forcecopydump", 0, &cnt);
|
|
if (swservp == NULL)
|
|
{
|
|
cat_fatal(CAT_GETATTR,
|
|
"Unable to get %s attribute from ODM object class SWservAt.\n","forcecopydump");
|
|
}
|
|
|
|
/************************************/
|
|
/* save new value of forcecopydump */
|
|
/************************************/
|
|
if (Coreval)
|
|
swservp->value = stracpy("TRUE");
|
|
else
|
|
swservp->value = stracpy("FALSE");
|
|
|
|
if (ras_putattr(swservp) < 0)
|
|
{
|
|
cat_fatal(CAT_PUTATTR,
|
|
"Unable to put %s attribute into ODM object class SWservAt.\n","forcecopydump");
|
|
}
|
|
|
|
savebase(); /* Call savebase to make sure these attributes persist across boots. */
|
|
|
|
/* Call the sync() routine to make sure the changes */
|
|
/* are written to disk. This is necessary if a dump */
|
|
/* happens before the syncd has had a chance to run. */
|
|
sync();
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* NAME: error_if_multiprocessor()
|
|
*
|
|
* FUNCTION: This function checks to see if we are running on
|
|
* a machine with multiple processors. If so, we give
|
|
* an error message that remote dump is not supported.
|
|
* This function is only called when someone tries to
|
|
* initialize a remote primary or secondary dump device,
|
|
* or clear a remote dump file with the -r flag.
|
|
*
|
|
* INPUTS: none
|
|
* RETURNS: none
|
|
* Exits if the machine we are running on has multiple
|
|
* processors.
|
|
*/
|
|
void error_if_multiprocessor()
|
|
{
|
|
if (_system_configuration.ncpus > 1)
|
|
cat_fatal(CAT_REMOTE_MP,
|
|
"Remote dump is not supported in a multiprocessor environment.\n");
|
|
}
|
|
|