blob: be15af12a251805caef503331c2c665ec3eb4522 [file] [log] [blame]
/*
* LTlib.c -- the lsof test library
*
* V. Abell
* Purdue University
*/
/*
* Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
* 47907. All rights reserved.
*
* Written by V. Abell.
*
* This software is not subject to any license of the American Telephone
* and Telegraph Company or the Regents of the University of California.
*
* Permission is granted to anyone to use this software for any purpose on
* any computer system, and to alter it and redistribute it freely, subject
* to the following restrictions:
*
* 1. Neither the authors nor Purdue University are responsible for any
* consequences of the use of this software.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Credit to the authors and Purdue
* University must appear in documentation and sources.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 4. This notice may not be removed or altered.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n";
#endif
#include "LsofTest.h"
/*
* Pre-defintions that may be changed by a specific dialect
*/
#define X2DEV_T unsigned int /* cast for result of x2dev() */
#define XDINDEV 8 /* number of hex digits in an lsof
* device field -- should be
* 2 X sizeof(X2DEV_T) */
#if defined(LT_DIAL_aix)
/*
* AIX-specific items
*/
#include <sys/sysmacros.h>
# if defined(LT_AIXA) && LT_AIXA>=1
/*
* Note: the DEVNO64 and ISDEVNO54 #define's come from <sys/sysmacros.h>, but
* only when _KERNEL is #define'd.
*/
#undef DEVNO64
#define DEVNO64 0x8000000000000000LL
#undef ISDEVNO64
#define ISDEVNO64(d) (((ulong)(d) & DEVNO64) ? 1 : 0)
/*
* Define major and minor extraction macros that work on 64 bit AIX
* architectures.
*/
#define major_S(d) (ISDEVNO64(d) ? major64(d) : minor(d & ~SDEV_REMOTE))
#define minor_S(d) (ISDEVNO64(d) ? (minor64(d) & ~SDEV_REMOTE) : minor(d))
#undef X2DEV_T
#define X2DEV_T unsigned long long
#undef XDINDEV
#define XDINDEV 16
#define major_X(dp, em) major_S(x2dev(dp, em))
#define minor_X(dp, em) minor_S(x2dev(dp, em))
# endif /* defined(LT_AIXA) && LT_AIXA>=1 */
#endif /* defined(LT_DIAL_aix) */
#if defined(LT_DIAL_bsdi)
/*
* BSDI-specific items
*/
#define minor_S(dev) dv_subunit(dev)
#define unit_S(dev) dv_unit(dev)
#define minor_X(dp, em) dv_subunit(x2dev(dp, em))
#define unit_X(dp, em) dv_unit(x2dev(dp, em))
#endif /* defined(LT_DIAL_bsdi) */
#if defined(LT_DIAL_osr)
/*
* OpenUNIX-specific items
*/
#include <sys/sysmacros.h>
#endif /* defined(LT_DIAL_osr) */
#if defined(LT_DIAL_ou)
/*
* OpenUNIX-specific items
*/
#include <sys/mkdev.h>
#endif /* defined(LT_DIAL_ou) */
#if defined(LT_DIAL_solaris)
/*
* Solaris-specific items
*/
#include <sys/sysmacros.h>
/*
* Define maximum major device number in a stat(2) dev_t
*/
# if LT_VERS>=20501
#define LT_MJX L_MAXMAJ /* Get maximum major device number from
* <sys/sysmacros.h>. */
# else /* LT_VERS<20501 */
#define LT_MJX 0x3fff /* Avoid <sys/sysmacros.h> when
* Solaris < 2.5.1. */
# endif /* LT_VERS>=20501 */
#define major_S(dev) ((int)((dev >> L_BITSMINOR) & LT_MJX))
#define minor_S(dev) ((int)(dev & L_MAXMIN))
# if defined(LT_K64)
/*
* Solaris 64 bit kernel
*/
#undef X2DEV_T
#define X2DEV_T unsigned long long
#undef XDINDEV
#define XDINDEV 16
#define major_X(dp, em) ((int)((x2dev(dp, em) >> 32) & 0xffffffff))
#define minor_X(dp, em) ((int)(x2dev(dp, em) & 0xffffffff))
# else /* !defined(LT_K64) */
/*
* Solaris 32 bit kernel
*/
#define major_X(dp, em) ((int)((x2dev(dp, em) >> L_BITSMINOR) & LT_MJX))
#define minor_X(dp, em) ((int)(x2dev(dp, em) & L_MAXMIN))
# endif /* LT_K64 */
#endif /* defined(LT_DIAL_solaris) */
#if defined(LT_DIAL_uw)
/*
* UnixWare-specific items
*/
#include <sys/mkdev.h>
#endif /* defined(LT_DIAL_uw) */
/*
* Global variables
*/
int LsofFd = -1; /* lsof pipe FD */
FILE *LsofFs = (FILE *)NULL; /* stream for lsof pipe FD */
char *LsofPath = (char *)NULL; /* path to lsof executable */
pid_t LsofPid = (pid_t)0; /* PID of lsof child process */
int LTopt_h = 0; /* "-h" option's switch value */
char *LTopt_p = (char *)NULL; /* "-p path" option's path value */
int MsgStat = 0; /* message status: 1 means prefix needs
* to be issued */
/*
* Local static variables
*/
static int Afo = 0; /* Fo[] structures allocated */
static char *GOv = (char *)NULL; /* option `:' value pointer */
static int GOx1 = 1; /* first opt[][] index */
static int GOx2 = 0; /* second opt[][] index */
static LTfldo_t *Fo = (LTfldo_t *)NULL; /* allocated LTfldo_t structures */
static int Ufo = 0; /* Fo[] structures used */
/*
* Local function prototypes
*/
_PROTOTYPE(static void closepipe,(void));
_PROTOTYPE(static void getlsofpath,(void));
_PROTOTYPE(static int GetOpt,(int ct, char *opt[], char *rules, char **em,
char *pn));
_PROTOTYPE(static X2DEV_T x2dev,(char *x, char **em));
/*
* Default major, minor, and unit macros.
*/
#if !defined(major_S)
#define major_S major
#endif /* defined(major_S) */
#if !defined(minor_S)
#define minor_S minor
#endif /* defined(minor_S) */
#if !defined(unit_S)
#define unit_S(x) 0
#endif /* defined(unit_S) */
#if !defined(major_X)
#define major_X(dp, em) major(x2dev(dp, em))
#endif /* defined(major_X) */
#if !defined(minor_X)
#define minor_X(dp, em) minor(x2dev(dp, em))
#endif /* defined(minor_X) */
#if !defined(unit_X)
#define unit_X(dp, em) 0
#endif /* defined(unit_X) */
/*
* CanRdKmem() -- can lsof read kernel memory devices?
*/
char *
CanRdKmem()
{
#if defined(LT_KMEM)
char buf[2048]; /* temporary buffer */
char *dn; /* memory device name */
char *em; /* error message pointer */
int fd; /* temporary file descriptor */
struct stat sb; /* memory device stat(2) buffer */
int ti; /* temporary integer */
/*
* Get the lsof path. If it is not the default, check no further.
*/
(void) getlsofpath();
if (!strcmp(LsofPath, LT_DEF_LSOF_PATH))
return((char *)NULL);
/*
* Check /dev/kmem access.
*/
dn = "/dev/kmem";
if (stat(dn, &sb)) {
em = "stat";
kmem_error:
(void) snprintf(buf, sizeof(buf) - 1,
"ERROR!!! can't %s(%s): %s\n", em, dn, strerror(errno));
buf[sizeof(buf) - 1] = '\0';
return(MkStrCpy(buf, &ti));
}
if ((fd = open(dn, O_RDONLY, 0)) < 0) {
em = "open";
goto kmem_error;
}
(void) close(fd);
/*
* Check /dev/mem access.
*/
dn = "/dev/mem";
if (stat(dn, &sb)) {
/*
* If /dev/mem can't be found, ignore the error.
*/
return((char *)NULL);
}
if ((fd = open(dn, O_RDONLY, 0)) < 0) {
em = "open";
goto kmem_error;
}
(void) close(fd);
#endif /* defined(LT_KMEM) */
return((char *)NULL);
}
/*
* closepipe() -- close pipe from lsof
*/
static void
closepipe()
{
if (LsofFd >= 0) {
/*
* A pipe from lsof is open. Close it and the associated stream.
*/
if (LsofFs) {
(void) fclose(LsofFs);
LsofFs = (FILE *)NULL;
}
(void) close(LsofFd);
LsofFd = -1;
}
}
/*
* ConvLsofDev() -- convert lsof device string
*
* Note: this function is dialect-specific.
*/
char *
ConvLsofDev(dev, ldev)
char *dev; /* lsof device string -- the value to the
* LSOF_FID_DEVN field of a LSOF_FID_FD block
* (see lsof_fields.h) */
LTdev_t *ldev; /* results are returned to this structure */
{
char *dp; /* device pointer */
char *em; /* error message pointer */
int tlen; /* temporary length */
/*
* Check function arguments.
*
* Establish values for decoding the device string.
*/
if (!dev)
return("ERROR!!! no ConvLsofDev() device");
if (!ldev)
return("ERROR!!! no ConvLsofDev() result pointer");
if (strncmp(dev, "0x", 2))
return("ERROR!!! no leading 0x in ConvLsofDev() device");
dp = dev + 2;
if (((tlen = (int)strlen(dp)) < 1) || (tlen > XDINDEV))
return("ERROR!!! bad ConvLsofDev() device length");
/*
* Use the pre-defined *_X() macros to do the decomposition.
*/
ldev->maj = (unsigned int)major_X(dp, &em);
if (em)
return(em);
ldev->min = (unsigned int)minor_X(dp, &em);
if (em)
return(em);
ldev->unit = (unsigned int)unit_X(dp, &em);
return(em);
}
/*
* ConvStatDev() -- convert stat(2) device number
*
* Note: this function is dialect-specific.
*/
char *
ConvStatDev(dev, ldev)
dev_t *dev; /* device number to be converted */
LTdev_t *ldev; /* results are returned to this structure */
{
/*
* Check function arguments.
*/
if (!dev)
return("ERROR!!! no ConvStatDev() device");
if (!ldev)
return("ERROR!!! no ConvStatDev() result pointer");
/*
* Use the pre-defined *_S() macros to do the decomposition.
*/
ldev->maj = (unsigned int)major_S(*dev);
ldev->min = (unsigned int)minor_S(*dev);
ldev->unit = (unsigned int)unit_S(*dev);
return((char *)NULL);
}
/*
* ExecLsof() -- execute lsof with full field output and a NUL field terminator
* in a child process
*/
char *
ExecLsof(opt)
char **opt; /* lsof options -- a pointer to an
* array of character pointers,
* terminated by a NULL pointer */
{
static char **av = (char **)NULL; /* lsof argument vector, dynamically
* allocated */
static int ava = 0; /* **av entries allocated */
char buf[2048]; /* temporary buffer */
char *em; /* error message pointer */
int fd; /* temporary file descriptor */
int optc; /* option count */
int nf; /* number of files */
int p[2]; /* pipe FDs */
char **tcpp; /* temporary character pointer
* pointer */
int ti; /* temporary integer */
int tlen; /* temporary length */
pid_t tpid; /* temporary PID holder */
/*
* It's an error if lsof is already in execution or if no lsof options
* were supplied.
*/
(void) getlsofpath();
if (LsofPid)
return("ERROR!!! ExecLsof() says lsof is already in execution");
if (!opt)
return("ERROR!!! no ExecLsof() option list");
for (optc = 0, tcpp = opt; *tcpp; optc++, tcpp++)
;
/*
* Make sure lsof is executable.
*/
if ((em = IsLsofExec()))
return(em);
/*
* Open a pipe through which lsof can return output.
*/
if (pipe(p)) {
(void) snprintf(buf, sizeof(buf) - 1,
"ERROR!!! can't open pipe: %s", strerror(errno));
return(MkStrCpy(buf, &ti));
}
/*
* Allocate and build an argument vector. The first entry will be set
* to "lsof", the second to "-wFr", and the third to "-F0". Additional
* entries will be set as supplied by the caller.
*/
if ((optc + 4) > ava) {
tlen = (int)(sizeof(char *) * (optc + 4));
if (!av)
av = (char **)malloc(tlen);
else
av = (char **)realloc((void *)av, tlen);
if (!av) {
(void) snprintf(buf, sizeof(buf) - 1,
"LTlib: ExecLsof() can't allocat pointers for %d arguments",
optc + 4);
return(MkStrCpy(buf, &ti));
}
ava = optc + 4;
}
for (ti = 0, tcpp = opt; ti < (optc + 3); ti++) {
switch(ti) {
case 0:
av[ti] = "lsof";
break;
case 1:
av[ti] = "-wFr";
break;
case 2:
av[ti] = "-F0";
break;
default:
av[ti] = *tcpp;
tcpp++;
}
}
av[ti] = (char *)NULL;
/*
* Fork a child process to run lsof.
*/
switch((tpid = fork())) {
case (pid_t)0:
/*
* This is the child process.
*
* First close all file descriptors except the output side of the pipe.
*
* Make the output side of the pipe STDOUT and STDERR.
*/
for (fd = 0, nf = getdtablesize(); fd < nf; fd++) {
if (fd == p[1])
continue;
(void) close(fd);
}
if (p[1] != 1)
(void) dup2(p[1], 1);
if (p[1] != 2)
(void) dup2(p[1], 2);
if ((p[1] != 1) && (p[1] != 2))
(void) close(p[1]);
/*
* Execute lsof.
*/
(void) execv(LsofPath, av);
_exit(0); /* (Shouldn't get here.) */
case (pid_t)-1:
/*
* A fork error occurred. Form and return a message.
*/
(void) snprintf(buf, sizeof(buf) - 1,
"ERROR!!! ExecLsof() can't fork: %s", strerror(errno));
buf[sizeof(buf) - 1] = '\0';
return(MkStrCpy(buf, &ti));
default:
/*
* This is the parent.
*
* Save the lsof child PID.
*
* Close the output side of the pipe.
*
* Save the input side of the pipe as LsofFd; open a stream for it.
*/
LsofPid = tpid;
(void) close(p[1]);
LsofFd = p[0];
if (!(LsofFs = fdopen(LsofFd, "r")))
return("ERROR!!! ExecLsof() can't open stream to lsof output FD");
}
/*
* Wait a bit for lsof to start and put something in its pipe, then return
* an "All is well." response.
*/
sleep(1);
return((char *)NULL);
}
/*
* getlsofpath() -- get lsof path, either from LT_LSOF_PATH in the environment
* or from LT_DEF_LSOF_PATH
*/
static void
getlsofpath()
{
char *tcp; /* temporary character pointer */
int ti; /* temporary integer */
if (LsofPath)
return;
if ((tcp = getenv("LT_LSOF_PATH")))
LsofPath = MkStrCpy(tcp, &ti);
else
LsofPath = LT_DEF_LSOF_PATH;
}
/*
* GetOpt() -- Local get option
*
* Borrowed from lsof's main.c source file.
*
* Liberally adapted from the public domain AT&T getopt() source,
* distributed at the 1985 UNIFORM conference in Dallas
*
* The modifications allow `?' to be an option character and allow
* the caller to decide that an option that may be followed by a
* value doesn't have one -- e.g., has a default instead.
*/
static int
GetOpt(ct, opt, rules, em, pn)
int ct; /* option count */
char *opt[]; /* options */
char *rules; /* option rules */
char **em; /* error message return */
char *pn;
{
register int c; /* character value */
register char *cp = (char *)NULL; /* character pointer */
char embf[2048]; /* error message buffer */
int tlen; /* temporary message length from
* MkStrCpy() */
*em = (char *)NULL;
if (GOx2 == 0) {
/*
* Move to a new entry of the option array.
*
* EOF if:
*
* Option list has been exhausted;
* Next option doesn't start with `-' or `+';
* Next option has nothing but `-' or `+';
* Next option is ``--'' or ``++''.
*/
if (GOx1 >= ct
|| (opt[GOx1][0] != '-' && opt[GOx1][0] != '+')
|| !opt[GOx1][1])
return(EOF);
if (strcmp(opt[GOx1], "--") == 0 || strcmp(opt[GOx1], "++") == 0) {
GOx1++;
return(EOF);
}
GOx2 = 1;
}
/*
* Flag `:' option character as an error.
*
* Check for a rule on this option character.
*/
if ((c = opt[GOx1][GOx2]) == ':') {
(void) snprintf(embf, sizeof(embf) - 1,
"ERROR!!! colon is an illegal option character.");
embf[sizeof(embf) - 1] = '\0';
*em = MkStrCpy(embf, &tlen);
} else if (!(cp = strchr(rules, c))) {
(void) snprintf(embf, sizeof(embf) - 1,
"ERROR!!! illegal option character: %c", c);
embf[sizeof(embf) - 1] = '\0';
*em = MkStrCpy(embf, &tlen);
}
if (*em) {
/*
* An error was detected.
*
* Advance to the next option character.
*
* Return the character causing the error.
*/
if (opt[GOx1][++GOx2] == '\0') {
GOx1++;
GOx2 = 0;
}
return(c);
}
if (*(cp + 1) == ':') {
/*
* The option may have a following value. The caller decides if it does.
*
* Don't indicate that an option of ``--'' is a possible value.
*
* Finally, on the assumption that the caller will decide that the possible
* value belongs to the option, position to the option following the
* possible value, so that the next call to GetOpt() will find it.
*/
if(opt[GOx1][GOx2 + 1] != '\0') {
GOv = &opt[GOx1++][GOx2];
} else if (++GOx1 >= ct)
GOv = (char *)NULL;
else {
GOv = opt[GOx1];
if (strcmp(GOv, "--") == 0)
GOv = (char *)NULL;
else
GOx1++;
}
GOx2 = 0;
} else {
/*
* The option character stands alone with no following value.
*
* Advance to the next option character.
*/
if (opt[GOx1][++GOx2] == '\0') {
GOx2 = 0;
GOx1++;
}
GOv = (char *)NULL;
}
/*
* Return the option character.
*/
return(c);
}
/*
* IsLsofExec() -- see if lsof is executable
*/
char *
IsLsofExec()
{
char buf[2048]; /* temporary buffer */
int len; /* temporary length */
(void) getlsofpath();
if (access(LsofPath, X_OK) < 0) {
(void) snprintf(buf, sizeof(buf) - 1,
"ERROR!!! can't execute %s: %s", LsofPath, strerror(errno));
return(MkStrCpy(buf, &len));
}
return((char *)NULL);
}
/*
* LTlibClean() -- clean up LTlib resource accesses
*/
void
LTlibClean()
{
(void) StopLsof();
}
/*
* MkStrCpy() -- make string copy
*/
char *
MkStrCpy(src, len)
char *src; /* string source to copy */
int *len; /* returned length allocation */
{
char *rp; /* return pointer */
int srclen; /* source string length */
if (!src) {
(void) fprintf(stderr, "ERROR!!! no string supplied to MkStrCpy()\n");
exit(1);
}
srclen = (int)strlen(src);
*len = srclen++;
if (!(rp = (char *)malloc(srclen))) {
(void) fprintf(stderr, "ERROR!!! MkStrCpy() -- no malloc() space");
exit(1);
}
(void) strcpy(rp, src);
return(rp);
}
/*
* PrtMsg() -- print message
*/
void
PrtMsg(mp, pn)
char *mp; /* message pointer -- may be NULL to
* trigger space prefix initialization
*/
char *pn; /* program name */
{
static int pfxlen = -1; /* prefix length, based on program */
/* name -- computed on first call
* when pfxlen == -1 */
static char *pfx = (char *)NULL; /* prefix (spaces) */
int ti; /* temporary index */
if (pfxlen == -1) {
/*
* This is the first call. Compute the prefix length and build the
* prefix.
*/
if (!pn)
pfxlen = 0;
else
pfxlen = (int)(strlen(pn));
pfxlen += (int)strlen(" ... ");
if (!(pfx = (char *)malloc(pfxlen + 1))) {
(void) printf( "ERROR!!! not enough space for %d space prefix\n",
pfxlen);
exit(1);
}
for (ti = 0; ti < pfxlen; ti++) {
pfx[ti] = ' ';
}
pfx[pfxlen] = '\0';
MsgStat = 0;
}
/*
* Process the message.
*/
if (MsgStat)
(void) printf("%s", pfx);
if (mp && *mp) {
(void) printf("%s\n", mp);
MsgStat = 1;
}
}
/*
* PrtMsgX() -- print message and exit
*/
void
PrtMsgX(mp, pn, f, xv)
char *mp; /* message pointer */
char *pn; /* program name */
void (*f)(); /* clean-up function pointer */
int xv; /* exit value */
{
if (mp)
PrtMsg(mp, pn);
if (f)
(void) (*f)();
(void) LTlibClean();
exit(xv);
}
/*
* RdFrLsof() -- read from lsof
*/
LTfldo_t *
RdFrLsof(nf, em)
int *nf; /* number of fields receiver */
char **em; /* error message pointer receiver */
{
char buf[2048]; /* temporary buffer */
int bufl = (int)sizeof(buf); /* size of buf[] */
char *blim = &buf[bufl - 1]; /* buf[] limit (last character
* address) */
char *fsp; /* field start pointer */
char *tcp; /* temporary character pointer */
LTfldo_t *tfop; /* temporary field output pointer */
int ti; /* temporary index */
int tlen; /* remporary length */
char *vp; /* value character pointer */
/*
* Check for errors.
*/
if (!em)
return((LTfldo_t *)NULL);
if (!nf) {
*em = "ERROR!!! RdFrLsof() not given a count return pointer";
return((LTfldo_t *)NULL);
}
*em = (char *)NULL;
*nf = 0;
/*
* If fields are in use, release their resources.
*/
for (ti = 0, tfop = Fo; (ti < Ufo); ti++, tfop++) {
if (tfop->v)
(void) free((void *)tfop->v);
}
Ufo = 0;
/*
* Read a line from lsof.
*/
if (!fgets(buf, bufl - 2, LsofFs)) {
/*
* An lsof pipe EOF has been reached. Indicate that with a NULL
* pointer return, coupled with a NULL error message return pointer
* (set above), and a field count of zero (set above).
*/
return((LTfldo_t *)NULL);
}
/*
* Parse the lsof line, allocating field output structures as appropriate.
*
* It is expected that fields will end in a NUL ('\0') or a NL ('\0') and
* that a NL ends all fields in the lsof line.
*/
for (tcp = buf, Ufo = 0; (*tcp != '\n') && (tcp < blim); tcp++) {
/*
* Start a new field. The first character is the LSOF_FID_*.
*
* First allocate an LTfldo_t structure.
*/
if (Ufo >= Afo) {
/*
* More LTfldo_t space is required.
*/
Afo += LT_FLDO_ALLOC;
tlen = (int)(Afo * sizeof(LTfldo_t));
if (Fo)
Fo = (LTfldo_t *)realloc(Fo, tlen);
else
Fo = (LTfldo_t *)malloc(tlen);
if (!Fo) {
/*
* A serious error has occurred; no LTfldo_t space is available.
*/
(void) snprintf(buf, bufl,
"ERROR!!! RdFrLsof() can't allocate %d pointer bytes",
tlen);
*em = MkStrCpy(buf, &ti);
*nf = -1;
return((LTfldo_t *)NULL);
}
}
tfop = Fo + Ufo;
tfop->v = (char *)NULL;
Ufo++;
/*
* Save the LSOF_FID_* character. Then compute the field value length,
* and make a copy of it.
*/
tfop->ft = *tcp++;
fsp = tcp;
tlen = 0;
while (*tcp && (*tcp != '\n') && (tcp < blim)) {
tcp++;
tlen++;
}
if (!(vp = (char *)malloc(tlen + 1))) {
/*
* A serious error has occurred; there's no space for the field value.
*/
(void) snprintf(buf, bufl,
"ERROR!!! RdFrLsof() can't allocate %d field bytes", tlen + 1);
*em = MkStrCpy(buf, &ti);
*nf = -1;
return((LTfldo_t *)NULL);
}
(void) memcpy((void *)vp, (void *)fsp, tlen);
vp[tlen] = '\0';
tfop->v = vp;
if (*tcp == '\n')
break;
if (tcp >= blim) {
/*
* The lsof line has no NL terminator; that's an error.
*/
*em = "ERROR!!! RdFrLsof() didn't find a NL";
*nf = -1;
return((LTfldo_t *)NULL);
}
}
/*
* The end of the lsof line has been reached. If no fields were assembled,
* return an error indicate. Otherwise return the fields and their count.
*/
if (!Ufo) {
*em = "ERROR!!! RdFrLsof() read an empty lsof line";
*nf = -1;
return((LTfldo_t *)NULL);
}
*nf = Ufo;
*em = (char *)NULL;
return(Fo);
}
/*
* ScanArg() -- scan arguments
*/
int
ScanArg(ac, av, opt, pn)
int ac; /* argument count */
char *av[]; /* argument pointers */
char *opt; /* option string */
char *pn; /* program name */
{
char *em; /* pointer to error message returned by
* GetOpt() */
char embf[2048]; /* error message buffer */
int rv = 0; /* return value */
int tc; /* temporary character value */
/*
* Preset possible argument values.
*/
LTopt_h = 0;
if (LTopt_p) {
(void) free((void *)LTopt_p);
LTopt_p = (char *)NULL;
}
/*
* Process the options according to the supplied option string.
*/
while ((tc = GetOpt(ac, av, opt, &em, pn)) != EOF) {
if (em) {
rv = 1;
PrtMsg(em, pn);
continue;
}
switch (tc) {
case 'h':
LTopt_h = 1;
break;
case 'p':
if (!GOv || *GOv == '-' || *GOv == '+') {
rv = 1;
(void) PrtMsg("ERROR!!! -p not followed by a path", pn);
} else
LTopt_p = GOv;
break;
default:
rv = 1;
(void) snprintf(embf, sizeof(embf) - 1,
"ERROR!!! unknown option: %c", tc);
PrtMsg(embf, pn);
}
}
for (; GOx1 < ac; GOx1++) {
/*
* Report extraneous arguments.
*/
rv = 1;
(void) snprintf(embf, sizeof(embf) - 1,
"ERROR!!! extraneous option: \"%s\"", av[GOx1]);
PrtMsg(embf, pn);
}
return(rv);
}
/*
* StopLsof() -- stop a running lsof process and close the pipe from it
*/
void
StopLsof()
{
pid_t pid;
if (LsofPid) {
/*
* An lsof child process may be active. Wait for (or kill) it.
*/
pid = wait3(NULL, WNOHANG, NULL);
if (pid != LsofPid) {
(void) kill(LsofPid, SIGKILL);
sleep(2);
pid = wait3(NULL, WNOHANG, NULL);
}
LsofPid = (pid_t)0;
}
(void) closepipe();
}
/*
* x2dev() -- convert hex string to device number
*/
static X2DEV_T
x2dev(x, em)
char *x; /* hex string */
char **em; /* error message receiver */
{
char buf[2048]; /* temporary message buffer */
int c; /* character holder */
X2DEV_T dev; /* device number result */
char *wx; /* working hex string pointer */
int xl; /* hex string length */
if (!x || !*x) {
*em = "ERROR!!! no hex string supplied to x2dev()";
return(0);
}
wx = strncasecmp(x, "0x", 2) ? x : (x + 2);
if (((xl = (int)strlen(wx)) < 1) || (xl > XDINDEV)) {
(void) snprintf(buf, sizeof(buf) - 1,
"ERROR!!! x2dev(\"%s\") bad length: %d", x, xl + 2);
buf[sizeof(buf) - 1] = '\0';
*em = MkStrCpy(buf, &c);
return(0);
}
/*
* Assemble the device number result from the hex string.
*/
for (dev = (X2DEV_T)0; *wx; wx++) {
if (isdigit((unsigned char)*wx)) {
dev = (dev << 4) | (unsigned int)(((int)*wx - (int)'0') & 0xf);
continue;
}
c = (int) tolower((unsigned char)*wx);
if ((c >= (int)'a') && (c <= (int)'f')) {
dev = (dev << 4) | (unsigned int)((c - 'a' + 10) & 0xf);
continue;
}
(void) snprintf(buf, sizeof(buf) - 1,
"ERROR!!! x2dev(\"%s\") non-hex character: %c", x, c);
*em = MkStrCpy(buf, &c);
}
/*
* Return result and no error indication.
*/
*em = (char *)NULL;
return(dev);
}