]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/kern/sysctl_kern_proc.c
ktls_test: Add a require_toe option similar to require_ifnet.
[FreeBSD/FreeBSD.git] / tests / sys / kern / sysctl_kern_proc.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2021 The FreeBSD Foundation
5  *
6  * This software was developed by Mark Johnston under sponsorship from
7  * the FreeBSD Foundation.
8  */
9
10 #include <sys/param.h>
11 #include <sys/stat.h>
12 #include <sys/sysctl.h>
13 #include <sys/user.h>
14 #include <sys/wait.h>
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <atf-c.h>
22
23 /*
24  * These tests exercise the KERN_PROC_* sysctls.
25  */
26
27 /*
28  * Loop through all valid PIDs and try to fetch info for each one.
29  */
30 static void
31 sysctl_kern_proc_all(int cmd)
32 {
33         int mib[4], pid_max;
34         void *buf;
35         size_t sz;
36
37         sz = sizeof(pid_max);
38         ATF_REQUIRE(sysctlbyname("kern.pid_max", &pid_max, &sz, NULL, 0) == 0);
39
40         mib[0] = CTL_KERN;
41         mib[1] = KERN_PROC;
42         mib[2] = cmd;
43         for (int i = 1; i <= pid_max; i++) {
44                 mib[3] = i;
45
46                 if (sysctl(mib, 4, NULL, &sz, NULL, 0) == 0) {
47                         buf = malloc(sz);
48                         ATF_REQUIRE(buf != NULL);
49                         (void)sysctl(mib, 4, buf, &sz, NULL, 0);
50                         free(buf);
51                 }
52         }
53
54         mib[3] = -1;
55         ATF_REQUIRE_ERRNO(ESRCH, sysctl(mib, 4, NULL, &sz, NULL, 0) != 0);
56 }
57
58 /*
59  * Validate behaviour of the KERN_PROC_CWD sysctl.
60  */
61 ATF_TC_WITHOUT_HEAD(sysctl_kern_proc_cwd);
62 ATF_TC_BODY(sysctl_kern_proc_cwd, tc)
63 {
64         struct kinfo_file kfile;
65         char cwd[PATH_MAX];
66         int cmd, mib[4];
67         size_t sz;
68         pid_t child;
69         int status;
70
71         cmd = KERN_PROC_CWD;
72
73         mib[0] = CTL_KERN;
74         mib[1] = KERN_PROC;
75         mib[2] = cmd;
76         mib[3] = getpid();
77
78         /* Try querying the kernel for the output buffer size. */
79         sz = 0;
80         ATF_REQUIRE(sysctl(mib, 4, NULL, &sz, NULL, 0) == 0);
81         ATF_REQUIRE(sz <= sizeof(kfile));
82
83         sz = sizeof(kfile);
84         memset(&kfile, 0, sz);
85         ATF_REQUIRE(sysctl(mib, 4, &kfile, &sz, NULL, 0) == 0);
86         ATF_REQUIRE(sz <= sizeof(kfile));
87         ATF_REQUIRE(sz == (u_int)kfile.kf_structsize);
88
89         /* Make sure that we get the same result from getcwd(2). */
90         ATF_REQUIRE(getcwd(cwd, sizeof(cwd)) == cwd);
91         ATF_REQUIRE(strcmp(cwd, kfile.kf_path) == 0);
92
93         /* Spot-check some of the kinfo fields. */
94         ATF_REQUIRE(kfile.kf_type == KF_TYPE_VNODE);
95         ATF_REQUIRE(kfile.kf_fd == KF_FD_TYPE_CWD);
96         ATF_REQUIRE(S_ISDIR(kfile.kf_un.kf_file.kf_file_mode));
97         ATF_REQUIRE((kfile.kf_status & KF_ATTR_VALID) != 0);
98
99         /*
100          * Verify that a child process can get our CWD info, and that it
101          * matches the info we got above.
102          */
103         child = fork();
104         ATF_REQUIRE(child != -1);
105         if (child == 0) {
106                 struct kinfo_file pkfile;
107
108                 mib[0] = CTL_KERN;
109                 mib[1] = KERN_PROC;
110                 mib[2] = KERN_PROC_CWD;
111                 mib[3] = getppid();
112
113                 sz = sizeof(pkfile);
114                 memset(&pkfile, 0, sz);
115                 if (sysctl(mib, 4, &pkfile, &sz, NULL, 0) != 0)
116                         _exit(1);
117                 if (memcmp(&kfile, &pkfile, sizeof(kfile)) != 0)
118                         _exit(2);
119                 _exit(0);
120         }
121         ATF_REQUIRE(waitpid(child, &status, 0) == child);
122         ATF_REQUIRE(WIFEXITED(status));
123         ATF_REQUIRE(WEXITSTATUS(status) == 0);
124
125         /*
126          * Truncate the output buffer ever so slightly and make sure that we get
127          * an error.
128          */
129         sz--;
130         ATF_REQUIRE_ERRNO(ENOMEM, sysctl(mib, 4, &kfile, &sz, NULL, 0) != 0);
131
132         sysctl_kern_proc_all(cmd);
133 }
134
135 /*
136  * Validate behaviour of the KERN_PROC_FILEDESC sysctl.
137  */
138 ATF_TC_WITHOUT_HEAD(sysctl_kern_proc_filedesc);
139 ATF_TC_BODY(sysctl_kern_proc_filedesc, tc)
140 {
141         int cmd, fd, mib[4];
142         struct kinfo_file *kfile;
143         char *buf, tmp[16];
144         size_t sz, sz1;
145
146         cmd = KERN_PROC_FILEDESC;
147
148         mib[0] = CTL_KERN;
149         mib[1] = KERN_PROC;
150         mib[2] = cmd;
151         mib[3] = getpid();
152
153         sz = 0;
154         ATF_REQUIRE(sysctl(mib, 4, NULL, &sz, NULL, 0) == 0);
155         ATF_REQUIRE(sz >= __offsetof(struct kinfo_file, kf_structsize) +
156             sizeof(kfile->kf_structsize));
157
158         buf = malloc(sz);
159         ATF_REQUIRE(buf != NULL);
160
161         ATF_REQUIRE(sysctl(mib, 4, buf, &sz, NULL, 0) == 0);
162
163         /* Walk over the list of returned files. */
164         for (sz1 = 0; sz1 < sz; sz1 += kfile->kf_structsize) {
165                 kfile = (void *)(buf + sz1);
166
167                 ATF_REQUIRE((unsigned int)kfile->kf_structsize <= sz);
168                 ATF_REQUIRE((unsigned int)kfile->kf_structsize + sz1 <= sz);
169
170                 ATF_REQUIRE((kfile->kf_status & KF_ATTR_VALID) != 0);
171         }
172         /* We shouldn't have any trailing bytes. */
173         ATF_REQUIRE(sz1 == sz);
174
175         /*
176          * Open a file.  This increases the size of the output buffer, so an
177          * attempt to re-fetch the records without increasing the buffer size
178          * should fail with ENOMEM.
179          */
180         snprintf(tmp, sizeof(tmp), "tmp.XXXXXX");
181         fd = mkstemp(tmp);
182         ATF_REQUIRE(fd >= 0);
183         ATF_REQUIRE_ERRNO(ENOMEM, sysctl(mib, 4, buf, &sz, NULL, 0) != 0);
184
185         ATF_REQUIRE(unlink(tmp) == 0);
186         ATF_REQUIRE(close(fd) == 0);
187
188         free(buf);
189
190         sysctl_kern_proc_all(cmd);
191 }
192
193 ATF_TP_ADD_TCS(tp)
194 {
195         ATF_TP_ADD_TC(tp, sysctl_kern_proc_cwd);
196         ATF_TP_ADD_TC(tp, sysctl_kern_proc_filedesc);
197
198         return (atf_no_error());
199 }