diff options
Diffstat (limited to 'tests/LTlib.c')
-rw-r--r-- | tests/LTlib.c | 1104 |
1 files changed, 1104 insertions, 0 deletions
diff --git a/tests/LTlib.c b/tests/LTlib.c new file mode 100644 index 0000000..be15af1 --- /dev/null +++ b/tests/LTlib.c @@ -0,0 +1,1104 @@ +/* + * 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); +} |