Imported Upstream version 4.87
[platform/upstream/lsof.git] / tests / LTszoff.c
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
36 static 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
79 int Fd = -1;                    /* test file descriptor; open if >= 0 */
80 pid_t MyPid = (pid_t)0;         /* PID of this process */
81 char *Path = (char *)NULL;      /* test file path; none if NULL */
82 char *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
97 int
98 main(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
165 print_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
235 static int
236 ck_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
277 static void
278 cleanup()
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
295 static char *
296 testlsof(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 }