1/* 2 * LTszoff.c -- Lsof Test small file (< 32 bits) size and offset tests 3 * 4 * V. Abell 5 * Purdue University 6 */ 7 8 9/* 10 * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana 11 * 47907. All rights reserved. 12 * 13 * Written by V. Abell. 14 * 15 * This software is not subject to any license of the American Telephone 16 * and Telegraph Company or the Regents of the University of California. 17 * 18 * Permission is granted to anyone to use this software for any purpose on 19 * any computer system, and to alter it and redistribute it freely, subject 20 * to the following restrictions: 21 * 22 * 1. Neither the authors nor Purdue University are responsible for any 23 * consequences of the use of this software. 24 * 25 * 2. The origin of this software must not be misrepresented, either by 26 * explicit claim or by omission. Credit to the authors and Purdue 27 * University must appear in documentation and sources. 28 * 29 * 3. Altered versions must be plainly marked as such, and must not be 30 * misrepresented as being the original software. 31 * 32 * 4. This notice may not be removed or altered. 33 */ 34 35#ifndef lint 36static char copyright[] = 37"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; 38#endif 39 40#include "LsofTest.h" 41#include "lsof_fields.h" 42 43 44/* 45 * Pre-definitions that might be undefined by dialects 46 */ 47 48#define OFFTST_STAT 1 /* offset tests status */ 49 50 51#if defined(LT_DIAL_linux) 52/* 53 * Linux-specific items 54 */ 55 56#undef OFFTST_STAT 57#define OFFTST_STAT 0 /* Linux lsof may not be able to report 58 * offsets -- see the function 59 * ck_Linux_offset_support() */ 60 61_PROTOTYPE(static int ck_Linux_offset_support,(void)); 62#endif /* defined(LT_DIAL_linux) */ 63 64 65/* 66 * Local definitions 67 */ 68 69#define TYTST_SZ 0 /* size test type */ 70#define TYTST_0to 1 /* 0t offset test type */ 71#define TYTST_0xo 2 /* 0x offset test type */ 72#define TSTFSZ 32768 /* test file size */ 73 74 75/* 76 * Globals 77 */ 78 79int Fd = -1; /* test file descriptor; open if >= 0 */ 80pid_t MyPid = (pid_t)0; /* PID of this process */ 81char *Path = (char *)NULL; /* test file path; none if NULL */ 82char *Pn = (char *)NULL; /* program name */ 83 84 85/* 86 * Local function prototypes 87 */ 88 89_PROTOTYPE(static void cleanup,(void)); 90_PROTOTYPE(static char *testlsof,(int tt, char *opt, char *xval)); 91 92 93/* 94 * Main program 95 */ 96 97int 98main(argc, argv) 99 int argc; /* argument count */ 100 char *argv[]; /* arguments */ 101{ 102 char buf[2048]; /* temporary buffer */ 103 int do_offt = OFFTST_STAT; /* do offset tests if == 1 */ 104 char *em; /* error message pointer */ 105 int ti; /* temporary index */ 106 char *tcp; /* temporary character pointer */ 107 char *tstsz = (char *)NULL; /* size test status */ 108 char *tst0to = (char *)NULL; /* offset 0t form test */ 109 char *tst0xo = (char *)NULL; /* offset 0x form test */ 110 int xv = 0; /* exit value */ 111 char xbuf[64]; /* expected value buffer */ 112/* 113 * Get program name and PID, issue start message, and build space prefix. 114 */ 115 if ((Pn = strrchr(argv[0], '/'))) 116 Pn++; 117 else 118 Pn = argv[0]; 119 MyPid = getpid(); 120 (void) printf("%s ... ", Pn); 121 (void) fflush(stdout); 122 PrtMsg((char *)NULL, Pn); 123/* 124 * Process arguments. 125 */ 126 if (ScanArg(argc, argv, "hp:", Pn)) 127 xv = 1; 128 if (xv || LTopt_h) { 129 (void) PrtMsg("usage: [-h] [-p path]", Pn); 130 PrtMsg (" -h print help (this panel)", Pn); 131 PrtMsgX (" -p path define test file path", Pn, cleanup, xv); 132 } 133 134#if defined(LT_DIAL_linux) 135/* 136 * If this is Linux, see if lsof can report file offsets. 137 */ 138 do_offt = ck_Linux_offset_support(); 139#endif /* defined(LT_DIAL_linux) */ 140 141/* 142 * See if lsof can be executed and can access kernel memory. 143 */ 144 if ((em = IsLsofExec())) 145 (void) PrtMsgX(em, Pn, cleanup, 1); 146 if ((em = CanRdKmem())) 147 (void) PrtMsgX(em, Pn, cleanup, 1); 148/* 149 * If a path was supplied in an "-p path" option, use it. Otherwise construct 150 * a path in the CWD. 151 */ 152 if (!(Path = LTopt_p)) { 153 (void) snprintf(buf, sizeof(buf) - 1, "./config.LTszoff%ld", 154 (long)MyPid); 155 buf[sizeof(buf) - 1] = '\0'; 156 Path = MkStrCpy(buf, &ti); 157 } 158/* 159 * Open a new test file at the specified path. 160 */ 161 (void) unlink(Path); 162 if ((Fd = open(Path, O_RDWR|O_CREAT, 0600)) < 0) { 163 (void) fprintf(stderr, "ERROR!!! can't open %s\n", Path); 164 165print_file_error: 166 167 MsgStat = 1; 168 (void) snprintf(buf, sizeof(buf) - 1, " Errno %d: %s", 169 errno, strerror(errno)); 170 buf[sizeof(buf) - 1] = '\0'; 171 (void) PrtMsgX(buf, Pn, cleanup, 1); 172 } 173/* 174 * Write the test file to its expected size. 175 */ 176 for (ti = 0; ti < sizeof(buf); ti++) { 177 buf[ti] = (char)(ti & 0xff); 178 } 179 for (ti = 0; ti < TSTFSZ; ti += sizeof(buf)) { 180 if (write(Fd, buf, sizeof(buf)) != sizeof(buf)) { 181 (void) fprintf(stderr, "ERROR!!! can't write %d bytes to %s\n", 182 (int)sizeof(buf), Path); 183 goto print_file_error; 184 } 185 } 186/* 187 * Fsync() the file. 188 */ 189 if (fsync(Fd)) { 190 (void) fprintf(stderr, "ERROR!!! can't fsync %s\n", Path); 191 goto print_file_error; 192 } 193/* 194 * Do the tests. Skip offset tests as indicated. 195 */ 196 (void) snprintf(xbuf, sizeof(xbuf) - 1, "%d", TSTFSZ); 197 xbuf[sizeof(xbuf) - 1] = '\0'; 198 if ((tstsz = testlsof(TYTST_SZ, "-s", xbuf))) 199 (void) PrtMsg(tstsz, Pn); 200 if (do_offt) { 201 (void) snprintf(xbuf, sizeof(xbuf) - 1, "0t%d", TSTFSZ); 202 xbuf[sizeof(xbuf) - 1] = '\0'; 203 if ((tst0to = testlsof(TYTST_0to, "-o", xbuf))) 204 (void) PrtMsg(tst0to, Pn); 205 (void) snprintf(xbuf, sizeof(xbuf) - 1, "0x%x", TSTFSZ); 206 xbuf[sizeof(xbuf) - 1] = '\0'; 207 if ((tst0xo = testlsof(TYTST_0xo, "-oo2", xbuf))) 208 (void) PrtMsg(tst0to, Pn); 209 } else { 210 PrtMsg("WARNING!!! lsof can't return file offsets for this dialect,", 211 Pn); 212 PrtMsg(" so offset tests have been disabled.", Pn); 213 } 214/* 215 * Compute exit value and exit. 216 */ 217 if (tstsz || tst0to || tst0xo) { 218 tcp = (char *)NULL; 219 xv = 1; 220 } else { 221 tcp = "OK"; 222 xv = 0; 223 } 224 (void) PrtMsgX(tcp, Pn, cleanup, xv); 225 return(0); 226} 227 228 229#if defined(LT_DIAL_linux) 230/* 231 * ck_Linux_offset_support() -- see if lsof can report offsets for this 232 * Linux implementation 233 */ 234 235static int 236ck_Linux_offset_support() 237{ 238 char buf[1024]; /* lsof output line buffer */ 239 int bufl = sizeof(buf); /* size of buf[] */ 240 char *opv[5]; /* option vector for lsof */ 241 int rv = 1; /* return value: 242 * 0 == no lsof offset support 243 * 1 == lsof offset support */ 244/* 245 * Ask lsof to report the test's FD zero offset. 246 */ 247 if (IsLsofExec()) 248 return(0); 249 opv[0] = "-o"; 250 snprintf(buf, bufl - 1, "-p%d", (int)getpid()); 251 opv[1] = buf; 252 opv[2] = "-ad0"; 253 opv[3] = "+w"; 254 opv[4] = (char *)NULL; 255 if (ExecLsof(opv)) 256 return(0); 257/* 258 * Read the lsof output. Look for a line with "WARNING: can't report offset" 259 * in it. If it is found, then this Linux lsof can't report offsets. 260 */ 261 while(fgets(buf, bufl - 1, LsofFs)) { 262 if (strstr(buf, "WARNING: can't report offset")) { 263 rv = 0; 264 break; 265 } 266 } 267 (void) StopLsof(); 268 return(rv); 269} 270#endif /* defined(LT_DIAL_linux) */ 271 272 273/* 274 * cleanup() -- release resources 275 */ 276 277static void 278cleanup() 279{ 280 if (Fd >= 0) { 281 (void) close(Fd); 282 Fd = -1; 283 if (Path) { 284 (void) unlink(Path); 285 Path = (char *)NULL; 286 } 287 } 288} 289 290 291/* 292 * testlsof() -- test the open file with lsof 293 */ 294 295static char * 296testlsof(tt, opt, xval) 297 int tt; /* test type -- TYTST_* symbol */ 298 char *opt; /* extra lsof options */ 299 char *xval; /* expected value */ 300{ 301 char buf[2048]; /* temporary buffer */ 302 char *cem; /* current error message pointer */ 303 LTfldo_t *cmdp; /* command pointer */ 304 LTfldo_t *devp; /* device pointer */ 305 int ff = 0; /* file found status */ 306 LTfldo_t *fop; /* field output pointer */ 307 char ibuf[64]; /* inode number buffer */ 308 LTfldo_t *inop; /* inode number pointer */ 309 LTdev_t lsofdc; /* lsof device components */ 310 int nf; /* number of fields */ 311 LTfldo_t *offp; /* offset pointer */ 312 char *opv[4]; /* option vector for ExecLsof() */ 313 char *pem = (char *)NULL; /* previous error message pointer */ 314 pid_t pid; /* PID */ 315 int pids = 0; /* PID found status */ 316 struct stat sb; /* stat(2) buffer */ 317 LTdev_t stdc; /* stat(2) device components */ 318 LTfldo_t *szp; /* size pointer */ 319 char *tcp; /* temporary character pointer */ 320 int ti; /* temporary integer */ 321 char *tnm1, *tnm2; /* test names */ 322 int ts = 0; /* test status flag */ 323 LTfldo_t *typ; /* file type pointer */ 324/* 325 * Check the test type. 326 */ 327 switch (tt) { 328 case TYTST_SZ: 329 tnm1 = ""; 330 tnm2 = " size"; 331 break; 332 case TYTST_0to: 333 tnm1 = " 0t"; 334 tnm2 = " offset"; 335 break; 336 case TYTST_0xo: 337 tnm1 = " 0x"; 338 tnm2 = " offset"; 339 break; 340 default: 341 (void) snprintf(buf, sizeof(buf) - 1, 342 "ERROR!!! illegal test type: %d", tt); 343 buf[sizeof(buf) - 1] = '\0'; 344 (void) PrtMsgX(buf, Pn, cleanup, 1); 345 } 346/* 347 * Get test file's information. 348 */ 349 if (stat(Path, &sb)) { 350 (void) snprintf(buf, sizeof(buf) - 1, 351 "ERROR!!! can't stat(2) %s: %s", Path, strerror(errno)); 352 buf[sizeof(buf) - 1] = '\0'; 353 PrtMsgX(buf, Pn, cleanup, 1); 354 } 355/* 356 * Extract components from test file's stat buffer. 357 */ 358 if ((cem = ConvStatDev(&sb.st_dev, &stdc))) 359 PrtMsgX(buf, Pn, cleanup, 1); 360 (void) snprintf(ibuf, sizeof(ibuf) - 1, "%u", (unsigned int)sb.st_ino); 361 ibuf[sizeof(ibuf) - 1] = '\0'; 362/* 363 * Complete the option vector and start lsof execution. 364 */ 365 ti = 0; 366 if (opt && *opt) 367 opv[ti++] = opt; 368 369#if defined(USE_LSOF_C_OPT) 370 opv[ti++] = "-C"; 371#else /* !defined(USE_LSOF_C_OPT) */ 372 opv[ti++] = "--"; 373#endif /* defined(USE_LSOF_C_OPT) */ 374 375 opv[ti++] = Path; 376 opv[ti] = (char *)NULL; 377 if ((cem = ExecLsof(opv))) 378 return(cem); 379/* 380 * Read lsof output. 381 */ 382 while (!ff && !cem && (fop = RdFrLsof(&nf, &cem))) { 383 if (cem) { 384 if (pem) 385 (void) PrtMsg(pem, Pn); 386 return(cem); 387 } 388 switch (fop->ft) { 389 case LSOF_FID_PID: 390 391 /* 392 * This is a process information line. 393 */ 394 pid = (pid_t)atoi(fop->v); 395 pids = 1; 396 cmdp = (LTfldo_t *)NULL; 397 for (fop++, ti = 1; ti < nf; fop++, ti++) { 398 switch (fop->ft) { 399 case LSOF_FID_CMD: 400 cmdp = fop; 401 break; 402 } 403 } 404 if (!cmdp || (pid != MyPid)) 405 pids = 0; 406 break; 407 case LSOF_FID_FD: 408 409 /* 410 * This is a file descriptor line. Make sure its number matches the 411 * test file's descriptor number. 412 */ 413 if (!pids) 414 break; 415 for (ti = 0, tcp = fop->v; *tcp; tcp++) { 416 417 /* 418 * Convert file descriptor to a number. 419 */ 420 if (*tcp == ' ') 421 continue; 422 if (((int)*tcp < (int)'0') || ((int)*tcp > (int)'9')) { 423 ti = -1; 424 break; 425 } 426 ti = (ti * 10) + (int)*tcp - (int)'0'; 427 } 428 if (Fd != ti) 429 break; 430 /* 431 * Scan for device, inode, offset, size and type fields. 432 */ 433 devp = inop = offp = szp = typ = (LTfldo_t *)NULL; 434 for (fop++, ti = 1; ti < nf; fop++, ti++) { 435 switch (fop->ft) { 436 case LSOF_FID_DEVN: 437 devp = fop; 438 break; 439 case LSOF_FID_INODE: 440 inop = fop; 441 break; 442 case LSOF_FID_OFFSET: 443 offp = fop; 444 break; 445 case LSOF_FID_SIZE: 446 szp = fop; 447 break; 448 case LSOF_FID_TYPE: 449 typ = fop; 450 break; 451 } 452 } 453 /* 454 * Check the results of the file descriptor field scan. 455 */ 456 if (!devp || !inop || !typ) 457 break; 458 if (strcasecmp(typ->v, "reg") && strcasecmp(typ->v, "vreg")) 459 break; 460 if ((cem = ConvLsofDev(devp->v, &lsofdc))) { 461 if (pem) 462 (void) PrtMsg(pem, Pn); 463 pem = cem; 464 break; 465 } 466 if ((stdc.maj != lsofdc.maj) 467 || (stdc.min != lsofdc.min) 468 || (stdc.unit != lsofdc.unit) 469 || strcmp(inop->v, ibuf) 470 ) { 471 break; 472 } 473 /* 474 * The specified file has been located. Do the specified test. 475 */ 476 ff = 1; 477 fop = (tt == TYTST_SZ) ? szp : offp; 478 if (!fop) { 479 (void) snprintf(buf, sizeof(buf) - 1, 480 "ERROR!!! %s%s test, but no lsof%s", tnm1, tnm2, tnm2); 481 ts = 1; 482 } else if (strcmp(fop->v, xval)) { 483 (void) snprintf(buf, sizeof(buf) - 1, 484 "ERROR!!! %s%s mismatch: expected %s, got %s", 485 tnm1, tnm2, xval, fop->v); 486 ts = 1; 487 } 488 if (ts) { 489 buf[sizeof(buf) - 1] = '\0'; 490 cem = MkStrCpy(buf, &ti); 491 if (pem) 492 (void) PrtMsg(pem, Pn); 493 pem = cem; 494 } 495 break; 496 } 497 } 498 (void) StopLsof(); 499 if (!ff) { 500 (void) snprintf(buf, sizeof(buf) - 1, 501 "ERROR!!! test file %s not found by lsof", Path); 502 buf[sizeof(buf) - 1] = '\0'; 503 cem = MkStrCpy(buf, &ti); 504 if (pem) 505 (void) PrtMsg(pem, Pn); 506 return(cem); 507 } 508 return(pem); 509} 510