1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * proc01.c - Tests Linux /proc file reading.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Copyright (C) 2001 Stephane Fillod <f4cfe@free.fr>
5f08c3bdfSopenharmony_ci * Copyright (c) 2008, 2009  Red Hat, Inc.
6f08c3bdfSopenharmony_ci *
7f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify it
8f08c3bdfSopenharmony_ci * under the terms of version 2 of the GNU General Public License as
9f08c3bdfSopenharmony_ci * published by the Free Software Foundation.
10f08c3bdfSopenharmony_ci *
11f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful, but
12f08c3bdfSopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
13f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci * Further, this software is distributed without any warranty that it is
16f08c3bdfSopenharmony_ci * free of the rightful claim of any third person regarding infringement
17f08c3bdfSopenharmony_ci * or the like.  Any license provided herein, whether implied or
18f08c3bdfSopenharmony_ci * otherwise, applies only to this software file.  Patent licenses, if
19f08c3bdfSopenharmony_ci * any, provided herein do not apply to combinations of this program with
20f08c3bdfSopenharmony_ci * other software, or any other product whatsoever.
21f08c3bdfSopenharmony_ci *
22f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License along
23f08c3bdfSopenharmony_ci * with this program; if not, write the Free Software Foundation, Inc.,
24f08c3bdfSopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci */
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_ci#include "config.h"
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ci#include <errno.h>
31f08c3bdfSopenharmony_ci#include <stdio.h>
32f08c3bdfSopenharmony_ci#include <stdlib.h>
33f08c3bdfSopenharmony_ci#include <string.h>
34f08c3bdfSopenharmony_ci#include <limits.h>
35f08c3bdfSopenharmony_ci#include <sys/types.h>
36f08c3bdfSopenharmony_ci#include <sys/stat.h>
37f08c3bdfSopenharmony_ci#include <dirent.h>
38f08c3bdfSopenharmony_ci#include <unistd.h>
39f08c3bdfSopenharmony_ci#include <fcntl.h>
40f08c3bdfSopenharmony_ci#include <fnmatch.h>
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_ci#ifdef HAVE_LIBSELINUX_DEVEL
43f08c3bdfSopenharmony_ci#include <selinux/selinux.h>
44f08c3bdfSopenharmony_ci#endif
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci#include "test.h"
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ci#define MAX_BUFF_SIZE 65536
49f08c3bdfSopenharmony_ci#define MAX_FUNC_NAME 256
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_cichar *TCID = "proc01";
52f08c3bdfSopenharmony_ciint TST_TOTAL = 1;
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_cistatic int opt_verbose;
55f08c3bdfSopenharmony_cistatic int opt_procpath;
56f08c3bdfSopenharmony_cistatic char *opt_procpathstr;
57f08c3bdfSopenharmony_cistatic int opt_buffsize;
58f08c3bdfSopenharmony_cistatic int opt_readirq;
59f08c3bdfSopenharmony_cistatic char *opt_buffsizestr;
60f08c3bdfSopenharmony_cistatic int opt_maxmbytes;
61f08c3bdfSopenharmony_cistatic char *opt_maxmbytesstr;
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_cistatic char *procpath = "/proc";
64f08c3bdfSopenharmony_cistatic const char selfpath[] = "/proc/self";
65f08c3bdfSopenharmony_cisize_t buffsize = 1024;
66f08c3bdfSopenharmony_cistatic unsigned long long maxbytes;
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ciunsigned long long total_read;
69f08c3bdfSopenharmony_ciunsigned int total_obj;
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_cistruct mapping {
72f08c3bdfSopenharmony_ci	char func[MAX_FUNC_NAME];
73f08c3bdfSopenharmony_ci	char file[PATH_MAX];
74f08c3bdfSopenharmony_ci	int err;
75f08c3bdfSopenharmony_ci};
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci/* Those are known failures for 2.6.18 baremetal kernel and Xen dom0
78f08c3bdfSopenharmony_ci   kernel on i686, x86_64, ia64, ppc64 and s390x. In addition, It looks
79f08c3bdfSopenharmony_ci   like if SELinux is disabled, the test may still fail on some other
80f08c3bdfSopenharmony_ci   entries. */
81f08c3bdfSopenharmony_cistatic const struct mapping known_issues[] = {
82f08c3bdfSopenharmony_ci	{"open", "/proc/acpi/event", EBUSY},
83f08c3bdfSopenharmony_ci	{"open", "/proc/sal/cpe/data", EBUSY},
84f08c3bdfSopenharmony_ci	{"open", "/proc/sal/cmc/data", EBUSY},
85f08c3bdfSopenharmony_ci	{"open", "/proc/sal/init/data", EBUSY},
86f08c3bdfSopenharmony_ci	{"open", "/proc/sal/mca/data", EBUSY},
87f08c3bdfSopenharmony_ci	{"open", "/proc/fs/nfsd/pool_stats", ENODEV},
88f08c3bdfSopenharmony_ci	{"read", "/proc/fs/nfsd/clients/*/ctl", EINVAL},
89f08c3bdfSopenharmony_ci	{"read", "/proc/acpi/event", EAGAIN},
90f08c3bdfSopenharmony_ci	{"read", "/proc/kmsg", EAGAIN},
91f08c3bdfSopenharmony_ci	{"read", "/proc/sal/cpe/event", EAGAIN},
92f08c3bdfSopenharmony_ci	{"read", "/proc/sal/cmc/event", EAGAIN},
93f08c3bdfSopenharmony_ci	{"read", "/proc/sal/init/event", EAGAIN},
94f08c3bdfSopenharmony_ci	{"read", "/proc/sal/mca/event", EAGAIN},
95f08c3bdfSopenharmony_ci	{"read", "/proc/xen/privcmd", EIO},
96f08c3bdfSopenharmony_ci	{"read", "/proc/xen/privcmd", EINVAL},
97f08c3bdfSopenharmony_ci	{"read", "/proc/self/mem", EIO},
98f08c3bdfSopenharmony_ci	{"read", "/proc/self/task/[0-9]*/mem", EIO},
99f08c3bdfSopenharmony_ci	{"read", "/proc/self/attr/*", EINVAL},
100f08c3bdfSopenharmony_ci	{"read", "/proc/self/attr/selinux/*", EINVAL},
101f08c3bdfSopenharmony_ci	{"read", "/proc/self/attr/smack/*", EINVAL},
102f08c3bdfSopenharmony_ci	{"read", "/proc/self/attr/apparmor/*", EINVAL},
103f08c3bdfSopenharmony_ci	{"read", "/proc/self/task/[0-9]*/attr/*", EINVAL},
104f08c3bdfSopenharmony_ci	{"read", "/proc/self/task/[0-9]*/attr/smack/*", EINVAL},
105f08c3bdfSopenharmony_ci	{"read", "/proc/self/task/[0-9]*/attr/selinux/*", EINVAL},
106f08c3bdfSopenharmony_ci	{"read", "/proc/self/task/[0-9]*/attr/apparmor/*", EINVAL},
107f08c3bdfSopenharmony_ci	{"read", "/proc/self/ns/*", EINVAL},
108f08c3bdfSopenharmony_ci	{"read", "/proc/self/task/[0-9]*/ns/*", EINVAL},
109f08c3bdfSopenharmony_ci	{"read", "/proc/ppc64/rtas/error_log", EINVAL},
110f08c3bdfSopenharmony_ci	{"read", "/proc/powerpc/rtas/error_log", EINVAL},
111f08c3bdfSopenharmony_ci	{"read", "/proc/fs/nfsd/unlock_filesystem", EINVAL},
112f08c3bdfSopenharmony_ci	{"read", "/proc/fs/nfsd/unlock_ip", EINVAL},
113f08c3bdfSopenharmony_ci	{"read", "/proc/fs/nfsd/filehandle", EINVAL},
114f08c3bdfSopenharmony_ci	{"read", "/proc/fs/nfsd/.getfs", EINVAL},
115f08c3bdfSopenharmony_ci	{"read", "/proc/fs/nfsd/.getfd", EINVAL},
116f08c3bdfSopenharmony_ci	{"read", "/proc/self/net/rpc/use-gss-proxy", EAGAIN},
117f08c3bdfSopenharmony_ci	{"read", "/proc/sys/net/ipv6/conf/*/stable_secret", EIO},
118f08c3bdfSopenharmony_ci	{"read", "/proc/sys/vm/nr_hugepages", EOPNOTSUPP},
119f08c3bdfSopenharmony_ci	{"read", "/proc/sys/vm/nr_overcommit_hugepages", EOPNOTSUPP},
120f08c3bdfSopenharmony_ci	{"read", "/proc/sys/vm/nr_hugepages_mempolicy", EOPNOTSUPP},
121f08c3bdfSopenharmony_ci	{"read", "/proc/pressure/*", EOPNOTSUPP},
122f08c3bdfSopenharmony_ci	{"", "", 0}
123f08c3bdfSopenharmony_ci};
124f08c3bdfSopenharmony_ci
125f08c3bdfSopenharmony_ci/*
126f08c3bdfSopenharmony_ci * If a particular LSM is enabled, it is expected that some entries can
127f08c3bdfSopenharmony_ci * be read successfully. Otherwise, those entries will retrun some
128f08c3bdfSopenharmony_ci * failures listed above. Here to add any LSM specific entries.
129f08c3bdfSopenharmony_ci */
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ci/*
132f08c3bdfSopenharmony_ci * Test macro to indicate that SELinux libraries and headers are
133f08c3bdfSopenharmony_ci * installed.
134f08c3bdfSopenharmony_ci */
135f08c3bdfSopenharmony_ci#ifdef HAVE_LIBSELINUX_DEVEL
136f08c3bdfSopenharmony_cistatic const char lsm_should_work[][PATH_MAX] = {
137f08c3bdfSopenharmony_ci	"/proc/self/attr/*",
138f08c3bdfSopenharmony_ci	"/proc/self/attr/selinux/*",
139f08c3bdfSopenharmony_ci	"/proc/self/task/[0-9]*/attr/*",
140f08c3bdfSopenharmony_ci	"/proc/self/task/[0-9]*/attr/selinux/*",
141f08c3bdfSopenharmony_ci	""
142f08c3bdfSopenharmony_ci};
143f08c3bdfSopenharmony_ci#endif
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_ci/* Known files that does not honor O_NONBLOCK, so they will hang
146f08c3bdfSopenharmony_ci   the test while being read. */
147f08c3bdfSopenharmony_cistatic const char error_nonblock[][PATH_MAX] = {
148f08c3bdfSopenharmony_ci	"/proc/xen/xenbus",
149f08c3bdfSopenharmony_ci	""
150f08c3bdfSopenharmony_ci};
151f08c3bdfSopenharmony_ci
152f08c3bdfSopenharmony_ci/*
153f08c3bdfSopenharmony_ci * Verify expected failures, and then let the test to continue.
154f08c3bdfSopenharmony_ci *
155f08c3bdfSopenharmony_ci * Return 0 when a problem errno is found.
156f08c3bdfSopenharmony_ci * Return 1 when a known issue is found.
157f08c3bdfSopenharmony_ci *
158f08c3bdfSopenharmony_ci */
159f08c3bdfSopenharmony_cistatic int found_errno(const char *syscall, const char *obj, int tmperr)
160f08c3bdfSopenharmony_ci{
161f08c3bdfSopenharmony_ci	int i;
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci	/* Should not see any error for certain entries if a LSM is enabled. */
164f08c3bdfSopenharmony_ci#ifdef HAVE_LIBSELINUX_DEVEL
165f08c3bdfSopenharmony_ci	if (is_selinux_enabled()) {
166f08c3bdfSopenharmony_ci		for (i = 0; lsm_should_work[i][0] != '\0'; i++) {
167f08c3bdfSopenharmony_ci			if (!strcmp(obj, lsm_should_work[i]) ||
168f08c3bdfSopenharmony_ci			    !fnmatch(lsm_should_work[i], obj, FNM_PATHNAME)) {
169f08c3bdfSopenharmony_ci				return 0;
170f08c3bdfSopenharmony_ci			}
171f08c3bdfSopenharmony_ci		}
172f08c3bdfSopenharmony_ci	}
173f08c3bdfSopenharmony_ci#endif
174f08c3bdfSopenharmony_ci	for (i = 0; known_issues[i].err != 0; i++) {
175f08c3bdfSopenharmony_ci		if (tmperr == known_issues[i].err &&
176f08c3bdfSopenharmony_ci		    (!strcmp(obj, known_issues[i].file) ||
177f08c3bdfSopenharmony_ci		     !fnmatch(known_issues[i].file, obj, FNM_PATHNAME)) &&
178f08c3bdfSopenharmony_ci		    !strcmp(syscall, known_issues[i].func)) {
179f08c3bdfSopenharmony_ci			/* Using strcmp / fnmatch could have messed up the
180f08c3bdfSopenharmony_ci			 * errno value. */
181f08c3bdfSopenharmony_ci			errno = tmperr;
182f08c3bdfSopenharmony_ci			tst_resm(TINFO | TERRNO, "%s: known issue", obj);
183f08c3bdfSopenharmony_ci			return 1;
184f08c3bdfSopenharmony_ci		}
185f08c3bdfSopenharmony_ci	}
186f08c3bdfSopenharmony_ci	return 0;
187f08c3bdfSopenharmony_ci}
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_cistatic void cleanup(void)
190f08c3bdfSopenharmony_ci{
191f08c3bdfSopenharmony_ci	tst_rmdir();
192f08c3bdfSopenharmony_ci}
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_cistatic void setup(void)
195f08c3bdfSopenharmony_ci{
196f08c3bdfSopenharmony_ci	tst_sig(FORK, DEF_HANDLER, cleanup);
197f08c3bdfSopenharmony_ci	TEST_PAUSE;
198f08c3bdfSopenharmony_ci	tst_tmpdir();
199f08c3bdfSopenharmony_ci}
200f08c3bdfSopenharmony_ci
201f08c3bdfSopenharmony_civoid help(void)
202f08c3bdfSopenharmony_ci{
203f08c3bdfSopenharmony_ci	printf("  -b x    read byte count\n");
204f08c3bdfSopenharmony_ci	printf("  -m x    max megabytes to read from single file\n");
205f08c3bdfSopenharmony_ci	printf("  -q      read .../irq/... entries\n");
206f08c3bdfSopenharmony_ci	printf("  -r x    proc pathname\n");
207f08c3bdfSopenharmony_ci	printf("  -v      verbose mode\n");
208f08c3bdfSopenharmony_ci}
209f08c3bdfSopenharmony_ci
210f08c3bdfSopenharmony_ci/*
211f08c3bdfSopenharmony_ci * add the -m option whose parameter is the
212f08c3bdfSopenharmony_ci * pages that should be mapped.
213f08c3bdfSopenharmony_ci */
214f08c3bdfSopenharmony_cistatic option_t options[] = {
215f08c3bdfSopenharmony_ci	{"b:", &opt_buffsize, &opt_buffsizestr},
216f08c3bdfSopenharmony_ci	{"m:", &opt_maxmbytes, &opt_maxmbytesstr},
217f08c3bdfSopenharmony_ci	{"q", &opt_readirq, NULL},
218f08c3bdfSopenharmony_ci	{"r:", &opt_procpath, &opt_procpathstr},
219f08c3bdfSopenharmony_ci	{"v", &opt_verbose, NULL},
220f08c3bdfSopenharmony_ci	{NULL, NULL, NULL}
221f08c3bdfSopenharmony_ci};
222f08c3bdfSopenharmony_ci
223f08c3bdfSopenharmony_ci/*
224f08c3bdfSopenharmony_ci * NB: this function is recursive
225f08c3bdfSopenharmony_ci * returns 0 if no error encountered, otherwise number of errors (objs)
226f08c3bdfSopenharmony_ci *
227f08c3bdfSopenharmony_ci * REM: Funny enough, while developing this function (actually replacing
228f08c3bdfSopenharmony_ci *	streamed fopen by standard open), I hit a real /proc bug.
229f08c3bdfSopenharmony_ci *	On a 2.2.13-SuSE kernel, "cat /proc/tty/driver/serial" would fail
230f08c3bdfSopenharmony_ci *	with EFAULT, while "cat /proc/tty/driver/serial > somefile" wouldn't.
231f08c3bdfSopenharmony_ci *	Okay, this might be due to a slight serial misconfiguration, but still.
232f08c3bdfSopenharmony_ci *	Analysis with strace showed up the difference was on the count size
233f08c3bdfSopenharmony_ci *	of read (1024 bytes vs 4096 bytes). So I tested further..
234f08c3bdfSopenharmony_ci *	read count of 512 bytes adds /proc/tty/drivers to the list
235f08c3bdfSopenharmony_ci *	of broken proc files, while 64 bytes reads removes
236f08c3bdfSopenharmony_ci *	/proc/tty/driver/serial from the list. Interesting, isn't it?
237f08c3bdfSopenharmony_ci *	Now, there's a -b option to this test, so you can try your luck. --SF
238f08c3bdfSopenharmony_ci *
239f08c3bdfSopenharmony_ci * It's more fun to run this test it as root, as all the files will be accessible!
240f08c3bdfSopenharmony_ci * (however, be careful, there might be some bufferoverflow holes..)
241f08c3bdfSopenharmony_ci * reading proc files might be also a good kernel latency killer.
242f08c3bdfSopenharmony_ci */
243f08c3bdfSopenharmony_cistatic long readproc(const char *obj)
244f08c3bdfSopenharmony_ci{
245f08c3bdfSopenharmony_ci	DIR *dir = NULL;	/* pointer to a directory */
246f08c3bdfSopenharmony_ci	struct dirent *dir_ent;	/* pointer to directory entries */
247f08c3bdfSopenharmony_ci	char dirobj[PATH_MAX];	/* object inside directory to modify */
248f08c3bdfSopenharmony_ci	struct stat statbuf;	/* used to hold stat information */
249f08c3bdfSopenharmony_ci	int fd, tmperr, i;
250f08c3bdfSopenharmony_ci	ssize_t nread;
251f08c3bdfSopenharmony_ci	static char buf[MAX_BUFF_SIZE];	/* static kills reentrancy, but we don't care about the contents */
252f08c3bdfSopenharmony_ci	unsigned long long file_total_read = 0;
253f08c3bdfSopenharmony_ci
254f08c3bdfSopenharmony_ci	/* Determine the file type */
255f08c3bdfSopenharmony_ci	if (lstat(obj, &statbuf) < 0) {
256f08c3bdfSopenharmony_ci
257f08c3bdfSopenharmony_ci		/* permission denied is not considered as error */
258f08c3bdfSopenharmony_ci		if (errno != EACCES) {
259f08c3bdfSopenharmony_ci			tst_resm(TFAIL | TERRNO, "%s: lstat", obj);
260f08c3bdfSopenharmony_ci			return 1;
261f08c3bdfSopenharmony_ci		}
262f08c3bdfSopenharmony_ci		return 0;
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci	}
265f08c3bdfSopenharmony_ci
266f08c3bdfSopenharmony_ci	/* Prevent loops, but read /proc/self. */
267f08c3bdfSopenharmony_ci	if (S_ISLNK(statbuf.st_mode) && strcmp(obj, selfpath))
268f08c3bdfSopenharmony_ci		return 0;
269f08c3bdfSopenharmony_ci
270f08c3bdfSopenharmony_ci	total_obj++;
271f08c3bdfSopenharmony_ci
272f08c3bdfSopenharmony_ci	/* Take appropriate action, depending on the file type */
273f08c3bdfSopenharmony_ci	if (S_ISDIR(statbuf.st_mode) || !strcmp(obj, selfpath)) {
274f08c3bdfSopenharmony_ci
275f08c3bdfSopenharmony_ci		/* object is a directory */
276f08c3bdfSopenharmony_ci
277f08c3bdfSopenharmony_ci		/*
278f08c3bdfSopenharmony_ci		 * Skip over the /proc/irq directory, unless the user
279f08c3bdfSopenharmony_ci		 * requested that we read the directory because it could
280f08c3bdfSopenharmony_ci		 * map to a broken driver which effectively `hangs' the
281f08c3bdfSopenharmony_ci		 * test.
282f08c3bdfSopenharmony_ci		 */
283f08c3bdfSopenharmony_ci		if (!opt_readirq && !strcmp("/proc/irq", obj)) {
284f08c3bdfSopenharmony_ci			return 0;
285f08c3bdfSopenharmony_ci			/* Open the directory to get access to what is in it */
286f08c3bdfSopenharmony_ci		} else if ((dir = opendir(obj)) == NULL) {
287f08c3bdfSopenharmony_ci			if (errno != EACCES) {
288f08c3bdfSopenharmony_ci				tst_resm(TFAIL | TERRNO, "%s: opendir", obj);
289f08c3bdfSopenharmony_ci				return 1;
290f08c3bdfSopenharmony_ci			}
291f08c3bdfSopenharmony_ci			return 0;
292f08c3bdfSopenharmony_ci		} else {
293f08c3bdfSopenharmony_ci
294f08c3bdfSopenharmony_ci			long ret_val = 0;
295f08c3bdfSopenharmony_ci
296f08c3bdfSopenharmony_ci			/* Loop through the entries in the directory */
297f08c3bdfSopenharmony_ci			for (dir_ent = (struct dirent *)readdir(dir);
298f08c3bdfSopenharmony_ci			     dir_ent != NULL;
299f08c3bdfSopenharmony_ci			     dir_ent = (struct dirent *)readdir(dir)) {
300f08c3bdfSopenharmony_ci
301f08c3bdfSopenharmony_ci				/* Ignore ".", "..", "kcore", and
302f08c3bdfSopenharmony_ci				 * "/proc/<pid>" (unless this is our
303f08c3bdfSopenharmony_ci				 * starting point as directed by the
304f08c3bdfSopenharmony_ci				 * user).
305f08c3bdfSopenharmony_ci				 */
306f08c3bdfSopenharmony_ci				if (strcmp(dir_ent->d_name, ".") &&
307f08c3bdfSopenharmony_ci				    strcmp(dir_ent->d_name, "..") &&
308f08c3bdfSopenharmony_ci				    strcmp(dir_ent->d_name, "kcore") &&
309f08c3bdfSopenharmony_ci				    (fnmatch("[0-9]*", dir_ent->d_name,
310f08c3bdfSopenharmony_ci					     FNM_PATHNAME) ||
311f08c3bdfSopenharmony_ci				     strcmp(obj, procpath))) {
312f08c3bdfSopenharmony_ci
313f08c3bdfSopenharmony_ci					if (opt_verbose) {
314f08c3bdfSopenharmony_ci						fprintf(stderr, "%s\n",
315f08c3bdfSopenharmony_ci							dir_ent->d_name);
316f08c3bdfSopenharmony_ci					}
317f08c3bdfSopenharmony_ci
318f08c3bdfSopenharmony_ci					/* Recursively call this routine to test the
319f08c3bdfSopenharmony_ci					 * current entry */
320f08c3bdfSopenharmony_ci					snprintf(dirobj, PATH_MAX,
321f08c3bdfSopenharmony_ci						 "%s/%s", obj, dir_ent->d_name);
322f08c3bdfSopenharmony_ci					ret_val += readproc(dirobj);
323f08c3bdfSopenharmony_ci
324f08c3bdfSopenharmony_ci				}
325f08c3bdfSopenharmony_ci
326f08c3bdfSopenharmony_ci			}
327f08c3bdfSopenharmony_ci
328f08c3bdfSopenharmony_ci			/* Close the directory */
329f08c3bdfSopenharmony_ci			if (dir)
330f08c3bdfSopenharmony_ci				(void)closedir(dir);
331f08c3bdfSopenharmony_ci
332f08c3bdfSopenharmony_ci			return ret_val;
333f08c3bdfSopenharmony_ci
334f08c3bdfSopenharmony_ci		}
335f08c3bdfSopenharmony_ci
336f08c3bdfSopenharmony_ci	} else {		/* if it's not a dir, read it! */
337f08c3bdfSopenharmony_ci
338f08c3bdfSopenharmony_ci		if (!S_ISREG(statbuf.st_mode))
339f08c3bdfSopenharmony_ci			return 0;
340f08c3bdfSopenharmony_ci
341f08c3bdfSopenharmony_ci#ifdef DEBUG
342f08c3bdfSopenharmony_ci		fprintf(stderr, "%s", obj);
343f08c3bdfSopenharmony_ci#endif
344f08c3bdfSopenharmony_ci
345f08c3bdfSopenharmony_ci		/* is O_NONBLOCK enough to escape from FIFO's ? */
346f08c3bdfSopenharmony_ci		fd = open(obj, O_RDONLY | O_NONBLOCK);
347f08c3bdfSopenharmony_ci		if (fd < 0) {
348f08c3bdfSopenharmony_ci			tmperr = errno;
349f08c3bdfSopenharmony_ci
350f08c3bdfSopenharmony_ci			if (!found_errno("open", obj, tmperr)) {
351f08c3bdfSopenharmony_ci
352f08c3bdfSopenharmony_ci				errno = tmperr;
353f08c3bdfSopenharmony_ci
354f08c3bdfSopenharmony_ci				if (errno != EACCES) {
355f08c3bdfSopenharmony_ci					tst_resm(TFAIL | TERRNO,
356f08c3bdfSopenharmony_ci						 "%s: open failed", obj);
357f08c3bdfSopenharmony_ci					return 1;
358f08c3bdfSopenharmony_ci				}
359f08c3bdfSopenharmony_ci
360f08c3bdfSopenharmony_ci			}
361f08c3bdfSopenharmony_ci			return 0;
362f08c3bdfSopenharmony_ci
363f08c3bdfSopenharmony_ci		}
364f08c3bdfSopenharmony_ci
365f08c3bdfSopenharmony_ci		/* Skip write-only files. */
366f08c3bdfSopenharmony_ci		if ((statbuf.st_mode & S_IRUSR) == 0 &&
367f08c3bdfSopenharmony_ci		    (statbuf.st_mode & S_IWUSR) != 0) {
368f08c3bdfSopenharmony_ci			tst_resm(TINFO, "%s: is write-only.", obj);
369f08c3bdfSopenharmony_ci			(void)close(fd);
370f08c3bdfSopenharmony_ci			return 0;
371f08c3bdfSopenharmony_ci		}
372f08c3bdfSopenharmony_ci
373f08c3bdfSopenharmony_ci		/* Skip files does not honor O_NONBLOCK. */
374f08c3bdfSopenharmony_ci		for (i = 0; error_nonblock[i][0] != '\0'; i++) {
375f08c3bdfSopenharmony_ci			if (!strcmp(obj, error_nonblock[i])) {
376f08c3bdfSopenharmony_ci				tst_resm(TINFO, "%s: does not honor "
377f08c3bdfSopenharmony_ci					 "O_NONBLOCK", obj);
378f08c3bdfSopenharmony_ci				(void)close(fd);
379f08c3bdfSopenharmony_ci				return 0;
380f08c3bdfSopenharmony_ci			}
381f08c3bdfSopenharmony_ci		}
382f08c3bdfSopenharmony_ci
383f08c3bdfSopenharmony_ci		file_total_read = 0;
384f08c3bdfSopenharmony_ci		do {
385f08c3bdfSopenharmony_ci
386f08c3bdfSopenharmony_ci			nread = read(fd, buf, buffsize);
387f08c3bdfSopenharmony_ci
388f08c3bdfSopenharmony_ci			if (nread < 0) {
389f08c3bdfSopenharmony_ci
390f08c3bdfSopenharmony_ci				tmperr = errno;
391f08c3bdfSopenharmony_ci				(void)close(fd);
392f08c3bdfSopenharmony_ci
393f08c3bdfSopenharmony_ci				/* ignore no perm (not root) and no
394f08c3bdfSopenharmony_ci				 * process (terminated) errors */
395f08c3bdfSopenharmony_ci				if (!found_errno("read", obj, tmperr)) {
396f08c3bdfSopenharmony_ci
397f08c3bdfSopenharmony_ci					errno = tmperr;
398f08c3bdfSopenharmony_ci
399f08c3bdfSopenharmony_ci					if (errno != EACCES && errno != ESRCH) {
400f08c3bdfSopenharmony_ci						tst_resm(TFAIL | TERRNO,
401f08c3bdfSopenharmony_ci							 "read failed: "
402f08c3bdfSopenharmony_ci							 "%s", obj);
403f08c3bdfSopenharmony_ci						return 1;
404f08c3bdfSopenharmony_ci					}
405f08c3bdfSopenharmony_ci					return 0;
406f08c3bdfSopenharmony_ci
407f08c3bdfSopenharmony_ci				}
408f08c3bdfSopenharmony_ci
409f08c3bdfSopenharmony_ci			} else
410f08c3bdfSopenharmony_ci				file_total_read += nread;
411f08c3bdfSopenharmony_ci
412f08c3bdfSopenharmony_ci			if (opt_verbose) {
413f08c3bdfSopenharmony_ci#ifdef DEBUG
414f08c3bdfSopenharmony_ci				fprintf(stderr, "%ld", nread);
415f08c3bdfSopenharmony_ci#endif
416f08c3bdfSopenharmony_ci				fprintf(stderr, ".");
417f08c3bdfSopenharmony_ci			}
418f08c3bdfSopenharmony_ci
419f08c3bdfSopenharmony_ci			if ((maxbytes > 0) && (file_total_read > maxbytes)) {
420f08c3bdfSopenharmony_ci				tst_resm(TINFO, "%s: reached maxmbytes (-m)",
421f08c3bdfSopenharmony_ci					 obj);
422f08c3bdfSopenharmony_ci				break;
423f08c3bdfSopenharmony_ci			}
424f08c3bdfSopenharmony_ci		} while (0 < nread);
425f08c3bdfSopenharmony_ci		total_read += file_total_read;
426f08c3bdfSopenharmony_ci
427f08c3bdfSopenharmony_ci		if (opt_verbose)
428f08c3bdfSopenharmony_ci			fprintf(stderr, "\n");
429f08c3bdfSopenharmony_ci
430f08c3bdfSopenharmony_ci		if (0 <= fd)
431f08c3bdfSopenharmony_ci			(void)close(fd);
432f08c3bdfSopenharmony_ci
433f08c3bdfSopenharmony_ci	}
434f08c3bdfSopenharmony_ci
435f08c3bdfSopenharmony_ci	/* It's better to assume success by default rather than failure. */
436f08c3bdfSopenharmony_ci	return 0;
437f08c3bdfSopenharmony_ci
438f08c3bdfSopenharmony_ci}
439f08c3bdfSopenharmony_ci
440f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
441f08c3bdfSopenharmony_ci{
442f08c3bdfSopenharmony_ci	int lc;
443f08c3bdfSopenharmony_ci
444f08c3bdfSopenharmony_ci	tst_parse_opts(argc, argv, options, help);
445f08c3bdfSopenharmony_ci
446f08c3bdfSopenharmony_ci	if (opt_buffsize) {
447f08c3bdfSopenharmony_ci		size_t bs;
448f08c3bdfSopenharmony_ci		bs = atoi(opt_buffsizestr);
449f08c3bdfSopenharmony_ci		if (bs <= MAX_BUFF_SIZE)
450f08c3bdfSopenharmony_ci			buffsize = bs;
451f08c3bdfSopenharmony_ci		else
452f08c3bdfSopenharmony_ci			tst_brkm(TBROK, cleanup,
453f08c3bdfSopenharmony_ci				 "Invalid arg for -b (max: %u): %s",
454f08c3bdfSopenharmony_ci				 MAX_BUFF_SIZE, opt_buffsizestr);
455f08c3bdfSopenharmony_ci	}
456f08c3bdfSopenharmony_ci	if (opt_maxmbytes)
457f08c3bdfSopenharmony_ci		maxbytes = atoi(opt_maxmbytesstr) * 1024 * 1024;
458f08c3bdfSopenharmony_ci
459f08c3bdfSopenharmony_ci	if (opt_procpath)
460f08c3bdfSopenharmony_ci		procpath = opt_procpathstr;
461f08c3bdfSopenharmony_ci
462f08c3bdfSopenharmony_ci	setup();
463f08c3bdfSopenharmony_ci
464f08c3bdfSopenharmony_ci	for (lc = 0; TEST_LOOPING(lc); lc++) {
465f08c3bdfSopenharmony_ci		tst_count = 0;
466f08c3bdfSopenharmony_ci
467f08c3bdfSopenharmony_ci		TEST(readproc(procpath));
468f08c3bdfSopenharmony_ci
469f08c3bdfSopenharmony_ci		if (TEST_RETURN != 0) {
470f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "readproc() failed with %ld errors.",
471f08c3bdfSopenharmony_ci				 TEST_RETURN);
472f08c3bdfSopenharmony_ci		} else {
473f08c3bdfSopenharmony_ci			tst_resm(TPASS, "readproc() completed successfully, "
474f08c3bdfSopenharmony_ci				 "total read: %llu bytes, %u objs", total_read,
475f08c3bdfSopenharmony_ci				 total_obj);
476f08c3bdfSopenharmony_ci		}
477f08c3bdfSopenharmony_ci	}
478f08c3bdfSopenharmony_ci
479f08c3bdfSopenharmony_ci	cleanup();
480f08c3bdfSopenharmony_ci	tst_exit();
481f08c3bdfSopenharmony_ci}
482