blob: 8864360294cc0a61221d81ec8ff44abf587f0ecf [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
2 * proc01.c - Tests Linux /proc file reading.
3 *
4 * Copyright (C) 2001 Stephane Fillod <f4cfe@free.fr>
subrata_modakcf473b72009-02-05 11:15:57 +00005 * Copyright (c) 2008, 2009 Red Hat, Inc.
subrata_modak4bb656a2009-02-26 12:02:09 +00006 *
plars865695b2001-08-27 22:15:12 +00007 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
subrata_modak4bb656a2009-02-26 12:02:09 +000010 *
plars865695b2001-08-27 22:15:12 +000011 * This program is distributed in the hope that it would be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
subrata_modak4bb656a2009-02-26 12:02:09 +000014 *
plars865695b2001-08-27 22:15:12 +000015 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
subrata_modak4bb656a2009-02-26 12:02:09 +000021 *
plars865695b2001-08-27 22:15:12 +000022 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write the Free Software Foundation, Inc., 59
24 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
subrata_modak4bb656a2009-02-26 12:02:09 +000025 *
plars865695b2001-08-27 22:15:12 +000026 */
27
subrata_modakafe343d2009-02-05 11:20:49 +000028#include "config.h"
29
subrata_modakda124b92009-10-13 14:00:45 +000030#include <errno.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <limits.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <dirent.h>
plars865695b2001-08-27 22:15:12 +000038#include <unistd.h>
39#include <fcntl.h>
subrata_modakca317e62007-11-13 09:25:05 +000040#include <fnmatch.h>
plars865695b2001-08-27 22:15:12 +000041
subrata_modak190c7ad2009-03-16 08:27:20 +000042#ifdef HAVE_LIBSELINUX_DEVEL
subrata_modakafe343d2009-02-05 11:20:49 +000043#include <selinux/selinux.h>
44#endif
45
plars865695b2001-08-27 22:15:12 +000046#include "test.h"
47#include "usctest.h"
48
plars865695b2001-08-27 22:15:12 +000049#define MAX_BUFF_SIZE 65536
subrata_modak8a9ecb72008-05-26 06:09:19 +000050#define MAX_FUNC_NAME 256
plars865695b2001-08-27 22:15:12 +000051
vapier10fe5d82006-08-21 07:16:54 +000052char *TCID = "proc01";
53int TST_TOTAL = 1;
plars865695b2001-08-27 22:15:12 +000054extern int Tst_count;
55
yaberauneyada963562009-11-15 08:21:45 +000056static int opt_verbose = 0;
57static int opt_procpath = 0;
58static char *opt_procpathstr;
59static int opt_buffsize = 0;
60static int opt_readirq = 0;
61static char *opt_buffsizestr;
plars865695b2001-08-27 22:15:12 +000062
yaberauneyada963562009-11-15 08:21:45 +000063static char *procpath = "/proc";
64static char selfpath[] = "/proc/self";
65size_t buffsize = 1024;
plars865695b2001-08-27 22:15:12 +000066
yaberauneyada963562009-11-15 08:21:45 +000067unsigned long long total_read = 0;
vapier10fe5d82006-08-21 07:16:54 +000068unsigned int total_obj = 0;
plars865695b2001-08-27 22:15:12 +000069
subrata_modakda124b92009-10-13 14:00:45 +000070struct mapping {
71 char func[MAX_FUNC_NAME];
72 char file[PATH_MAX];
73 int err;
subrata_modak8a9ecb72008-05-26 06:09:19 +000074};
subrata_modakda124b92009-10-13 14:00:45 +000075
subrata_modak8a9ecb72008-05-26 06:09:19 +000076typedef struct mapping Mapping;
77
78/* Those are known failures for 2.6.18 baremetal kernel and Xen dom0
79 kernel on i686, x86_64, ia64, ppc64 and s390x. In addition, It looks
80 like if SELinux is disabled, the test may still fail on some other
81 entries. */
yaberauneyada963562009-11-15 08:21:45 +000082const Mapping known_issues[] = {
subrata_modak8a9ecb72008-05-26 06:09:19 +000083 {"open", "/proc/acpi/event", EBUSY},
84 {"open", "/proc/sal/cpe/data", EBUSY},
85 {"open", "/proc/sal/cmc/data", EBUSY},
86 {"open", "/proc/sal/init/data", EBUSY},
87 {"open", "/proc/sal/mca/data", EBUSY},
88 {"read", "/proc/kmsg", EAGAIN},
89 {"read", "/proc/sal/cpe/event", EAGAIN},
90 {"read", "/proc/sal/cmc/event", EAGAIN},
91 {"read", "/proc/sal/init/event", EAGAIN},
92 {"read", "/proc/sal/mca/event", EAGAIN},
93 {"read", "/proc/xen/privcmd", EINVAL},
94 {"read", "/proc/self/mem", EIO},
95 {"read", "/proc/self/task/[0-9]*/mem", EIO},
subrata_modakcf473b72009-02-05 11:15:57 +000096 {"read", "/proc/self/attr/*", EINVAL},
97 {"read", "/proc/self/task/[0-9]*/attr/*", EINVAL},
98 {"read", "/proc/ppc64/rtas/error_log", EINVAL},
Subrata Modaka9ff0b52010-06-14 17:52:10 +053099 {"read", "/proc/powerpc/rtas/error_log", EINVAL},
subrata_modakcf473b72009-02-05 11:15:57 +0000100 {"read", "/proc/fs/nfsd/unlock_filesystem", EINVAL},
101 {"read", "/proc/fs/nfsd/unlock_ip", EINVAL},
102 {"read", "/proc/fs/nfsd/filehandle", EINVAL},
103 {"read", "/proc/fs/nfsd/.getfs", EINVAL},
104 {"read", "/proc/fs/nfsd/.getfd", EINVAL},
subrata_modak8a9ecb72008-05-26 06:09:19 +0000105 {"", "", 0}
yaberauneyada963562009-11-15 08:21:45 +0000106};
subrata_modak8a9ecb72008-05-26 06:09:19 +0000107
subrata_modak190c7ad2009-03-16 08:27:20 +0000108/*
109 * If a particular LSM is enabled, it is expected that some entries can
110 * be read successfully. Otherwise, those entries will retrun some
111 * failures listed above. Here to add any LSM specific entries.
112 */
113
114/*
115 * Test macro to indicate that SELinux libraries and headers are
116 * installed.
117 */
118#ifdef HAVE_LIBSELINUX_DEVEL
yaberauneyada963562009-11-15 08:21:45 +0000119const char lsm_should_work[][PATH_MAX] = {
subrata_modakafe343d2009-02-05 11:20:49 +0000120 "/proc/self/attr/*",
121 "/proc/self/task/[0-9]*/attr/*",
122 ""
yaberauneyada963562009-11-15 08:21:45 +0000123};
subrata_modak190c7ad2009-03-16 08:27:20 +0000124/* Place holder for none of LSM is detected. */
subrata_modak13a21422009-02-16 05:44:04 +0000125#else
yaberauneyada963562009-11-15 08:21:45 +0000126const char lsm_should_work[][PATH_MAX] = {
subrata_modak13a21422009-02-16 05:44:04 +0000127 ""
yaberauneyada963562009-11-15 08:21:45 +0000128};
subrata_modak13a21422009-02-16 05:44:04 +0000129#endif
subrata_modakafe343d2009-02-05 11:20:49 +0000130
subrata_modak8a9ecb72008-05-26 06:09:19 +0000131/* Known files that does not honor O_NONBLOCK, so they will hang
subrata_modakafe343d2009-02-05 11:20:49 +0000132 the test while being read. */
yaberauneyada963562009-11-15 08:21:45 +0000133const char error_nonblock[][PATH_MAX] = {
subrata_modak8a9ecb72008-05-26 06:09:19 +0000134 "/proc/xen/xenbus",
135 ""
yaberauneyada963562009-11-15 08:21:45 +0000136};
subrata_modak8a9ecb72008-05-26 06:09:19 +0000137
yaberauneyada963562009-11-15 08:21:45 +0000138/*
139 * Verify expected failures, and then let the test to continue.
140 *
141 * Return 0 when a problem errno is found.
142 * Return 1 when a known issue is found.
143 *
subrata_modak190c7ad2009-03-16 08:27:20 +0000144 */
subrata_modak8a9ecb72008-05-26 06:09:19 +0000145int found_errno(const char *syscall, const char *obj, int tmperr)
146{
yaberauneyada963562009-11-15 08:21:45 +0000147 int i;
subrata_modak8a9ecb72008-05-26 06:09:19 +0000148
yaberauneyada963562009-11-15 08:21:45 +0000149 /* Should not see any error for certain entries if a LSM is enabled. */
150#ifdef HAVE_LIBSELINUX_DEVEL
151 if (is_selinux_enabled()) {
152 for (i = 0; lsm_should_work[i][0] != '\0'; i++) {
153 if (!strcmp(obj, lsm_should_work[i]) ||
154 !fnmatch(lsm_should_work[i], obj, FNM_PATHNAME)) {
155 return 0;
156 }
157 }
158 }
159#endif
160 for (i = 0; known_issues[i].err != 0; i++) {
161 if (tmperr == known_issues[i].err &&
162 (!strcmp(obj, known_issues[i].file) ||
163 !fnmatch(known_issues[i].file, obj, FNM_PATHNAME)) &&
164 !strcmp(syscall, known_issues[i].func)) {
165 /* Using strcmp / fnmatch could have messed up the
166 * errno value. */
167 errno = tmperr;
168 tst_resm(TINFO | TERRNO, "%s: known issue", obj);
169 return 1;
170 }
171 }
172 return 0;
subrata_modak8a9ecb72008-05-26 06:09:19 +0000173}
174
plars865695b2001-08-27 22:15:12 +0000175void cleanup()
176{
vapier10fe5d82006-08-21 07:16:54 +0000177 /*
178 * remove the tmp directory and exit
179 */
vapier10fe5d82006-08-21 07:16:54 +0000180 TEST_CLEANUP;
vapier10fe5d82006-08-21 07:16:54 +0000181 tst_rmdir();
vapier10fe5d82006-08-21 07:16:54 +0000182 tst_exit();
yaberauneyada963562009-11-15 08:21:45 +0000183
plars865695b2001-08-27 22:15:12 +0000184}
185
186void setup()
187{
vapier10fe5d82006-08-21 07:16:54 +0000188 /*
189 * setup a default signal hander and a
190 * temporary working directory.
191 */
192 tst_sig(FORK, DEF_HANDLER, cleanup);
vapier10fe5d82006-08-21 07:16:54 +0000193 TEST_PAUSE;
vapier10fe5d82006-08-21 07:16:54 +0000194 tst_tmpdir();
plars865695b2001-08-27 22:15:12 +0000195}
196
197void help()
198{
vapier10fe5d82006-08-21 07:16:54 +0000199 printf(" -b x read byte count\n");
yaberauneyada963562009-11-15 08:21:45 +0000200 printf(" -q read .../irq/... entries\n");
vapier10fe5d82006-08-21 07:16:54 +0000201 printf(" -r x proc pathname\n");
202 printf(" -v verbose mode\n");
plars865695b2001-08-27 22:15:12 +0000203}
204
205/*
206 * add the -m option whose parameter is the
207 * pages that should be mapped.
208 */
vapier10fe5d82006-08-21 07:16:54 +0000209option_t options[] = {
yaberauneyada963562009-11-15 08:21:45 +0000210 { "b:", &opt_buffsize, &opt_buffsizestr},
211 { "q", &opt_readirq, NULL },
212 { "r:", &opt_procpath, &opt_procpathstr},
213 { "v", &opt_verbose, NULL },
214 { NULL, NULL, NULL }
plars865695b2001-08-27 22:15:12 +0000215};
216
plars865695b2001-08-27 22:15:12 +0000217/*
subrata_modak4bb656a2009-02-26 12:02:09 +0000218 * NB: this function is recursive
plars865695b2001-08-27 22:15:12 +0000219 * returns 0 if no error encountered, otherwise number of errors (objs)
220 *
yaberauneyada963562009-11-15 08:21:45 +0000221 * REM: Funny enough, while developing this function (actually replacing
plars865695b2001-08-27 22:15:12 +0000222 * streamed fopen by standard open), I hit a real /proc bug.
223 * On a 2.2.13-SuSE kernel, "cat /proc/tty/driver/serial" would fail
224 * with EFAULT, while "cat /proc/tty/driver/serial > somefile" wouldn't.
225 * Okay, this might be due to a slight serial misconfiguration, but still.
226 * Analysis with strace showed up the difference was on the count size
227 * of read (1024 bytes vs 4096 bytes). So I tested further..
subrata_modak4bb656a2009-02-26 12:02:09 +0000228 * read count of 512 bytes adds /proc/tty/drivers to the list
229 * of broken proc files, while 64 bytes reads removes
yaberauneyada963562009-11-15 08:21:45 +0000230 * /proc/tty/driver/serial from the list. Interesting, isn't it?
plars865695b2001-08-27 22:15:12 +0000231 * Now, there's a -b option to this test, so you can try your luck. --SF
232 *
233 * It's more fun to run this test it as root, as all the files will be accessible!
234 * (however, be careful, there might be some bufferoverflow holes..)
235 * reading proc files might be also a good kernel latency killer.
236 */
yaberauneyada963562009-11-15 08:21:45 +0000237long readproc(const char *obj)
plars865695b2001-08-27 22:15:12 +0000238{
yaberauneyada963562009-11-15 08:21:45 +0000239 DIR *dir = NULL; /* pointer to a directory */
vapier10fe5d82006-08-21 07:16:54 +0000240 struct dirent *dir_ent; /* pointer to directory entries */
241 char dirobj[PATH_MAX]; /* object inside directory to modify */
242 struct stat statbuf; /* used to hold stat information */
subrata_modak8a9ecb72008-05-26 06:09:19 +0000243 int fd, tmperr, i;
vapier10fe5d82006-08-21 07:16:54 +0000244 ssize_t nread;
245 static char buf[MAX_BUFF_SIZE]; /* static kills reentrancy, but we don't care about the contents */
plars865695b2001-08-27 22:15:12 +0000246
vapier10fe5d82006-08-21 07:16:54 +0000247 /* Determine the file type */
248 if (lstat(obj, &statbuf) < 0) {
yaberauneyada963562009-11-15 08:21:45 +0000249
vapier10fe5d82006-08-21 07:16:54 +0000250 /* permission denied is not considered as error */
251 if (errno != EACCES) {
yaberauneyada963562009-11-15 08:21:45 +0000252 tst_resm(TFAIL | TERRNO, "%s: lstat", obj);
vapier10fe5d82006-08-21 07:16:54 +0000253 return 1;
plars865695b2001-08-27 22:15:12 +0000254 }
255 return 0;
yaberauneyada963562009-11-15 08:21:45 +0000256
plars865695b2001-08-27 22:15:12 +0000257 }
258
yaberauneyada963562009-11-15 08:21:45 +0000259 /* Prevent loops, but read /proc/self. */
subrata_modakca317e62007-11-13 09:25:05 +0000260 if (S_ISLNK(statbuf.st_mode) && strcmp(obj, selfpath))
vapier10fe5d82006-08-21 07:16:54 +0000261 return 0;
262
263 total_obj++;
264
265 /* Take appropriate action, depending on the file type */
subrata_modakca317e62007-11-13 09:25:05 +0000266 if (S_ISDIR(statbuf.st_mode) || !strcmp(obj, selfpath)) {
yaberauneyada963562009-11-15 08:21:45 +0000267
vapier10fe5d82006-08-21 07:16:54 +0000268 /* object is a directory */
269
yaberauneyada963562009-11-15 08:21:45 +0000270 /*
271 * Skip over the /proc/irq directory, unless the user
272 * requested that we read the directory because it could
273 * map to a broken driver which effectively `hangs' the
274 * test.
275 */
yaberauneyaf0ff0022009-11-24 06:37:15 +0000276 if (!opt_readirq && !strcmp("/proc/irq", obj)) {
yaberauneyada963562009-11-15 08:21:45 +0000277 return 0;
vapier10fe5d82006-08-21 07:16:54 +0000278 /* Open the directory to get access to what is in it */
yaberauneyada963562009-11-15 08:21:45 +0000279 } else if ((dir = opendir(obj)) == NULL) {
vapier10fe5d82006-08-21 07:16:54 +0000280 if (errno != EACCES) {
yaberauneyada963562009-11-15 08:21:45 +0000281 tst_resm(TFAIL | TERRNO, "%s: opendir",
282 obj);
vapier10fe5d82006-08-21 07:16:54 +0000283 return 1;
plars865695b2001-08-27 22:15:12 +0000284 }
plars865695b2001-08-27 22:15:12 +0000285 return 0;
yaberauneyada963562009-11-15 08:21:45 +0000286 } else {
287
288 long ret_val = 0;
289
290 /* Loop through the entries in the directory */
291 for (dir_ent = (struct dirent *)readdir(dir);
292 dir_ent != NULL;
293 dir_ent = (struct dirent *)readdir(dir)) {
294
295 /* Ignore ".", "..", "kcore", and
296 * "/proc/<pid>" (unless this is our
297 * starting point as directed by the
298 * user).
299 */
300 if ( strcmp(dir_ent->d_name, ".") &&
301 strcmp(dir_ent->d_name, "..") &&
302 strcmp(dir_ent->d_name, "kcore") &&
303 (fnmatch("[0-9]*", dir_ent->d_name,
304 FNM_PATHNAME) ||
305 strcmp(obj, procpath))) {
306
307 if (opt_verbose) {
308 fprintf(stderr, "%s\n",
309 dir_ent->d_name);
310 }
311
312 /* Recursively call this routine to test the
313 * current entry */
314 snprintf(dirobj, PATH_MAX,
315 "%s/%s", obj,
316 dir_ent->d_name);
317 ret_val += readproc(dirobj);
318
319 }
320
321 }
322
323 /* Close the directory */
324 if (dir)
325 (void) closedir(dir);
326
327 return ret_val;
328
plars865695b2001-08-27 22:15:12 +0000329 }
vapier10fe5d82006-08-21 07:16:54 +0000330
vapier10fe5d82006-08-21 07:16:54 +0000331 } else { /* if it's not a dir, read it! */
332
333 if (!S_ISREG(statbuf.st_mode))
334 return 0;
335
yaberauneyada963562009-11-15 08:21:45 +0000336#ifdef DEBUG
337 fprintf(stderr, "%s", obj);
338#endif
subrata_modak8a9ecb72008-05-26 06:09:19 +0000339
yaberauneyada963562009-11-15 08:21:45 +0000340 /* is O_NONBLOCK enough to escape from FIFO's ? */
341 if ((fd = open(obj, O_RDONLY | O_NONBLOCK)) < 0) {
342
343 tmperr = errno;
344
345 if (!found_errno("open", obj, tmperr)) {
346
347 errno = tmperr;
348
349 if (errno != EACCES) {
350 tst_resm(TFAIL | TERRNO,
351 "%s: open failed", obj);
352 return 1;
353 }
354
vapier10fe5d82006-08-21 07:16:54 +0000355 }
356 return 0;
yaberauneyada963562009-11-15 08:21:45 +0000357
358 }
359
360 /* Skip write-only files. */
361 if ((statbuf.st_mode & S_IRUSR) == 0 &&
362 (statbuf.st_mode & S_IWUSR) != 0) {
363 tst_resm(TINFO, "%s: is write-only.", obj);
364 return 0;
vapier10fe5d82006-08-21 07:16:54 +0000365 }
366
yaberauneyada963562009-11-15 08:21:45 +0000367 /* Skip files does not honor O_NONBLOCK. */
368 for (i = 0; error_nonblock[i][0] != '\0'; i++) {
369 if (!strcmp(obj, error_nonblock[i])) {
370 tst_resm(TWARN, "%s: does not honor "
371 "O_NONBLOCK", obj);
vapier10fe5d82006-08-21 07:16:54 +0000372 return 0;
373 }
yaberauneyada963562009-11-15 08:21:45 +0000374 }
375
376 do {
377
378 nread = read(fd, buf, buffsize);
379
380 if (nread < 0) {
381
382 tmperr = errno;
383 (void) close(fd);
384
385 /* ignore no perm (not root) and no
386 * process (terminated) errors */
387 if (!found_errno("read", obj,
388 tmperr)) {
389
390 errno = tmperr;
391
392 if (errno != EACCES &&
393 errno != ESRCH) {
394 tst_resm(TFAIL | TERRNO,
395 "read failed: "
396 "%s", obj);
397 return 1;
398 }
399 return 0;
400
401 }
402
403 }
404
vapier10fe5d82006-08-21 07:16:54 +0000405 if (opt_verbose) {
406#ifdef DEBUG
yaberauneyada963562009-11-15 08:21:45 +0000407 fprintf(stderr, "%ld", nread);
vapier10fe5d82006-08-21 07:16:54 +0000408#endif
subrata_modak2f4de1d2008-05-26 06:10:16 +0000409 fprintf(stderr, ".");
vapier10fe5d82006-08-21 07:16:54 +0000410 }
411
412 total_read += nread;
yaberauneyada963562009-11-15 08:21:45 +0000413
414 } while (0 < nread);
415
vapier10fe5d82006-08-21 07:16:54 +0000416 if (opt_verbose)
yaberauneyada963562009-11-15 08:21:45 +0000417 fprintf(stderr, "\n");
418
419 if (0 <= fd)
420 (void) close(fd);
421
plars865695b2001-08-27 22:15:12 +0000422 }
plars865695b2001-08-27 22:15:12 +0000423
yaberauneyada963562009-11-15 08:21:45 +0000424 /* It's better to assume success by default rather than failure. */
plars865695b2001-08-27 22:15:12 +0000425 return 0;
yaberauneyada963562009-11-15 08:21:45 +0000426
plars865695b2001-08-27 22:15:12 +0000427}
428
vapier10fe5d82006-08-21 07:16:54 +0000429int main(int argc, char *argv[])
430{
431 char *msg;
432 int lc;
433
subrata_modakda124b92009-10-13 14:00:45 +0000434 if ((msg = parse_opts(argc, argv, options, help)) != NULL)
vapier10fe5d82006-08-21 07:16:54 +0000435 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
436
437 if (opt_buffsize) {
438 size_t bs;
439 bs = atoi(opt_buffsizestr);
440 if (bs <= MAX_BUFF_SIZE)
441 buffsize = bs;
442 else
443 tst_brkm(TBROK, cleanup,
444 "Invalid arg for -b (max: %u): %s",
445 MAX_BUFF_SIZE, opt_buffsizestr);
446 }
447
yaberauneyada963562009-11-15 08:21:45 +0000448 if (opt_procpath)
vapier10fe5d82006-08-21 07:16:54 +0000449 procpath = opt_procpathstr;
vapier10fe5d82006-08-21 07:16:54 +0000450
451 setup();
452
453 for (lc = 0; TEST_LOOPING(lc); lc++) {
454 Tst_count = 0;
455
456 TEST(readproc(procpath));
457
458 if (TEST_RETURN != 0) {
subrata_modakda124b92009-10-13 14:00:45 +0000459 tst_resm(TFAIL, "readproc() failed with %ld errors.",
vapier10fe5d82006-08-21 07:16:54 +0000460 TEST_RETURN);
461 } else {
462 tst_resm(TPASS, "readproc() completed successfully, "
yaberauneyada963562009-11-15 08:21:45 +0000463 "total read: %llu bytes, %u objs", total_read,
vapier10fe5d82006-08-21 07:16:54 +0000464 total_obj);
465 }
466 }
467
468 cleanup();
469 return 0;
470}