]> git.proxmox.com Git - mirror_lxcfs.git/blame - tests/test_syscalls.c
tests: include missing sys/sysmacros.h header
[mirror_lxcfs.git] / tests / test_syscalls.c
CommitLineData
a8b6c3e0
SH
1#define _GNU_SOURCE
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
a95d68e5 6#include <sys/sysmacros.h>
a8b6c3e0
SH
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <linux/un.h>
10#include <attr/xattr.h>
11#include <utime.h>
12#include <sys/stat.h>
13#include <sys/mount.h>
14#include <libgen.h>
15#include <fcntl.h>
16#include <errno.h>
17
18
19void test_open(const char *path)
20{
21 int fd = open(path, O_RDONLY);
22 if (fd >= 0) {
23 fprintf(stderr, "leak at open of %s\n", path);
24 exit(1);
25 }
26 if (errno != ENOENT) {
27 fprintf(stderr, "leak at open of %s: errno was %d\n", path, errno);
28 exit(1);
29 }
30}
31
32void test_stat(const char *path)
33{
34 struct stat sb;
35 if (stat(path, &sb) >= 0) {
36 fprintf(stderr, "leak at stat of %s\n", path);
37 exit(1);
38 }
39 if (errno != ENOENT) {
40 fprintf(stderr, "leak at stat of %s: errno was %d\n", path, errno);
41 exit(1);
42 }
43}
44
45void test_access(const char *path)
46{
47 if (access(path, O_RDONLY) >= 0) {
48 fprintf(stderr, "leak at access of %s\n", path);
49 exit(1);
50 }
51 if (errno != ENOENT) {
52 fprintf(stderr, "leak at access of %s: errno was %d\n", path, errno);
53 exit(1);
54 }
55}
56
57void test_bind(const char *path)
58{
59 int sfd;
60 struct sockaddr_un my_addr, peer_addr;
61
62 sfd = socket(AF_UNIX, SOCK_STREAM, 0);
63
64 if (sfd < 0) {
65 fprintf(stderr, "Failed to open a socket for bind test\n");
66 exit(1);
67 }
68 memset(&my_addr, 0, sizeof(struct sockaddr_un));
69 my_addr.sun_family = AF_UNIX;
70 strncpy(my_addr.sun_path, path,
71 sizeof(my_addr.sun_path) - 1);
72 if (bind(sfd, (struct sockaddr *) &my_addr,
73 sizeof(struct sockaddr_un)) != -1) {
74 fprintf(stderr, "leak at bind of %s\n", path);
75 exit(1);
76 }
77 if (errno != ENOENT && errno != ENOSYS) {
78 fprintf(stderr, "leak at bind of %s: errno was %s\n", path, strerror(errno));
79 exit(1);
80 }
81 close(sfd);
82}
83
84void test_bindmount(const char *path)
85{
86 if (mount(path, path, "none", MS_BIND, NULL) == 0) {
87 fprintf(stderr, "leak at bind mount of %s\n", path);
88 exit(1);
89 }
90}
91
92void test_truncate(const char *path)
93{
94 if (truncate(path, 0) == 0) {
95 fprintf(stderr, "leak at truncate of %s\n", path);
96 exit(1);
97 }
98}
99
100void test_chdir(const char *path)
101{
102 if (chdir(path) == 0) {
103 fprintf(stderr, "leak at chdir to %s\n", path);
104 exit(1);
105 }
106}
107
108void test_rename(const char *path)
109{
110 char *d = strdupa(path), *tmpname;
111 d = dirname(d);
112 size_t len = strlen(path) + 30;
113
114 tmpname = alloca(len);
115 snprintf(tmpname, len, "%s/%d", d, (int)getpid());
116 if (rename(path, tmpname) == 0 || errno != ENOENT) {
117 fprintf(stderr, "leak at rename of %s\n", path);
118 exit(1);
119 }
120}
121
122void test_mkdir(const char *path)
123{
124 size_t len = strlen(path) + 30;
125 char *tmpname = alloca(len);
126 snprintf(tmpname, len, "%s/%d", path, (int)getpid());
127
128 if (mkdir(path, 0755) == 0) {
129 fprintf(stderr, "leak at mkdir of %s\n", path);
130 exit(1);
131 }
132 if (errno != ENOENT) {
133 fprintf(stderr, "leak at mkdir of %s, errno was %s\n", path, strerror(errno));
134 exit(1);
135 }
136 if (mkdir(tmpname, 0755) == 0) {
137 fprintf(stderr, "leak at mkdir of %s\n", tmpname);
138 exit(1);
139 }
140 if (errno != ENOENT) {
141 fprintf(stderr, "leak at mkdir of %s, errno was %s\n", path, strerror(errno));
142 exit(1);
143 }
144}
145
146void test_rmdir(const char *path)
147{
148 size_t len = strlen(path) + 30;
149 char *tmpname = alloca(len);
150 snprintf(tmpname, len, "%s/%d", path, (int)getpid());
151
152 if (rmdir(path) == 0 || errno != ENOENT) {
153 fprintf(stderr, "leak at rmdir of %s\n", path);
154 exit(1);
155 }
156 if (rmdir(tmpname) == 0 || errno != ENOENT) {
157 fprintf(stderr, "leak at rmdir of %s\n", tmpname);
158 exit(1);
159 }
160}
161
162void test_creat(const char *path)
163{
164 if (creat(path, 0755) >= 0) {
165 fprintf(stderr, "leak at creat of %s\n", path);
166 exit(1);
167 }
168 if (errno != ENOENT && errno != ENOSYS) {
169 fprintf(stderr, "leak at creat of %s: errno was %s\n", path, strerror(errno));
170 exit(1);
171 }
172}
173
174void test_link(const char *path)
175{
176 char *d = strdupa(path), *tmpname;
177 d = dirname(d);
178 size_t len = strlen(path) + 30;
179 tmpname = alloca(len);
180 snprintf(tmpname, len, "%s/%d", d, (int)getpid());
181
182 if (link(path, tmpname) == 0) {
183 fprintf(stderr, "leak at link of %s\n", path);
184 exit(1);
185 }
186 if (errno != ENOENT && errno != ENOSYS) {
187 fprintf(stderr, "leak at link of %s: errno was %s\n", path, strerror(errno));
188 exit(1);
189 }
190
191 if (link(tmpname, path) == 0) {
192 fprintf(stderr, "leak at link (2) of %s\n", path);
193 exit(1);
194 }
195 if (errno != ENOENT && errno != ENOSYS) {
196 fprintf(stderr, "leak at link (2) of %s: errno was %s\n", path, strerror(errno));
197 exit(1);
198 }
199}
200
201void test_unlink(const char *path)
202{
203 if (unlink(path) == 0) {
204 fprintf(stderr, "leak at unlink of %s\n", path);
205 exit(1);
206 }
207 if (errno != ENOENT && errno != ENOSYS) {
208 fprintf(stderr, "leak at unlink of %s: errno was %s\n", path, strerror(errno));
209 exit(1);
210 }
211}
212
213void test_symlink(const char *path)
214{
215 char *d = strdupa(path), *tmpname;
216 d = dirname(d);
217 size_t len = strlen(path) + 30;
218 tmpname = alloca(len);
219 snprintf(tmpname, len, "%s/%d", d, (int)getpid());
220
221 if (symlink(tmpname, path) == 0) {
222 fprintf(stderr, "leak at symlink of %s\n", path);
223 exit(1);
224 }
225 if (errno != ENOENT && errno != ENOSYS) {
226 fprintf(stderr, "leak at symlink of %s: errno was %s\n", path, strerror(errno));
227 exit(1);
228 }
229 if (symlink(path, tmpname) == 0) {
230 fprintf(stderr, "leak at symlink (2) of %s\n", path);
231 exit(1);
232 }
233 if (errno != ENOENT && errno != ENOSYS) {
234 fprintf(stderr, "leak at symlink (2) of %s: errno was %s\n", path, strerror(errno));
235 exit(1);
236 }
237}
238
239void test_readlink(const char *path)
240{
241 char *dest = alloca(2 * strlen(path));
242
243 if (readlink(path, dest, 2 * strlen(path)) >= 0) {
244 fprintf(stderr, "leak at readlink of %s\n", path);
245 exit(1);
246 }
247 if (errno != ENOENT && errno != ENOSYS) {
248 fprintf(stderr, "leak at readlink of %s: errno was %s\n", path, strerror(errno));
249 exit(1);
250 }
251}
252
253void test_chmod(const char *path)
254{
255 if (chmod(path, 0755) == 0) {
256 fprintf(stderr, "leak at chmod of %s\n", path);
257 exit(1);
258 }
259 if (errno != ENOENT && errno != ENOSYS) {
260 fprintf(stderr, "leak at chmod of %s: errno was %s\n", path, strerror(errno));
261 exit(1);
262 }
263}
264
265void test_chown(const char *path)
266{
267 if (chown(path, 0, 0) == 0) {
268 fprintf(stderr, "leak at chown of %s\n", path);
269 exit(1);
270 }
271 if (errno != ENOENT && errno != ENOSYS) {
272 fprintf(stderr, "leak at chown of %s: errno was %s\n", path, strerror(errno));
273 exit(1);
274 }
275}
276
277void test_lchown(const char *path)
278{
279 if (lchown(path, 0, 0) == 0) {
280 fprintf(stderr, "leak at lchown of %s\n", path);
281 exit(1);
282 }
283 if (errno != ENOENT && errno != ENOSYS) {
284 fprintf(stderr, "leak at lchown of %s: errno was %s\n", path, strerror(errno));
285 exit(1);
286 }
287}
288
289void test_mknod(const char *path)
290{
291 if (mknod(path, 0755, makedev(0, 0)) == 0) {
292 fprintf(stderr, "leak at mknod of %s\n", path);
293 exit(1);
294 }
295 if (errno != ENOENT && errno != ENOSYS) {
296 fprintf(stderr, "leak at mknod of %s: errno was %s\n", path, strerror(errno));
297 exit(1);
298 }
299}
300
301void test_chroot(const char *path)
302{
303 if (chroot(path) == 0) {
304 fprintf(stderr, "leak at chroot of %s\n", path);
305 exit(1);
306 }
307 if (errno != ENOENT && errno != ENOSYS) {
308 fprintf(stderr, "leak at chroot of %s: errno was %s\n", path, strerror(errno));
309 exit(1);
310 }
311}
312
313void test_xattrs(const char *path)
314{
315 /*
316 * might consider doing all of:
317 * setxattr
318 * lsetxattr
319 * getxattr
320 * lgetxattr
321 * listxattr
322 * llistxattr
323 * removexattr
324 * lremovexattr
325 */
326 char value[200];
327 if (getxattr(path, "security.selinux", value, 200) >= 0) {
328 fprintf(stderr, "leak at getxattr of %s\n", path);
329 exit(1);
330 }
331 if (errno != ENOENT && errno != ENOSYS) {
332 fprintf(stderr, "leak at getxattr of %s: errno was %s\n", path, strerror(errno));
333 exit(1);
334 }
335}
336
337void test_utimes(const char *path)
338{
339 struct utimbuf times;
340 times.actime = 0;
341 times.modtime = 0;
342
343 if (utime(path, &times) == 0) {
344 fprintf(stderr, "leak at utime of %s\n", path);
345 exit(1);
346 }
347 if (errno != ENOENT && errno != ENOSYS) {
348 fprintf(stderr, "leak at utime of %s: errno was %s\n", path, strerror(errno));
349 exit(1);
350 }
351}
352
353void test_openat(const char *path)
354{
355 char *d = strdupa(path), *f, *tmpname;
356 int fd, fd2;
357 f = basename(d);
358 d = dirname(d);
359 fd = open(d, O_RDONLY);
360 if (fd < 0) {
361 fprintf(stderr, "Error in openat test: could not open parent dir\n");
362 fprintf(stderr, "(this is expected on the second run)\n");
363 return;
364 }
365 fd2 = openat(fd, f, O_RDONLY);
366 if (fd2 >= 0 || errno != ENOENT) {
367 fprintf(stderr, "leak at openat of %s\n", f);
368 exit(1);
369 }
370 size_t len = strlen(path) + strlen("/cgroup.procs") + 1;
371 tmpname = alloca(len);
372 snprintf(tmpname, len, "%s/cgroup.procs", f);
373 fd2 = openat(fd, tmpname, O_RDONLY);
374 if (fd2 >= 0 || errno != ENOENT) {
375 fprintf(stderr, "leak at openat of %s\n", tmpname);
376 exit(1);
377 }
378 close(fd);
379}
380
381int main(int argc, char *argv[])
382{
383 char *procspath;
384 size_t len;
385
386 if (geteuid() != 0) {
387 fprintf(stderr, "Run me as root\n");
388 exit(1);
389 }
390
391 if (argc != 2) {
392 fprintf(stderr, "Usage: %s [lxcfs_test_cgroup_path]\n", argv[0]);
393 exit(1);
394 }
395
396 /* Try syscalls on the directory and on $directory/cgroup.procs */
397 len = strlen(argv[1]) + strlen("/cgroup.procs") + 1;
398 procspath = alloca(len);
399 snprintf(procspath, len, "%s/cgroup.procs", argv[1]);
400
401 test_open(argv[1]);
402 test_open(procspath);
403 test_stat(argv[1]);
404 test_stat(procspath);
405 test_access(argv[1]);
406 test_access(procspath);
407
408 test_bind(argv[1]);
409 test_bind(procspath);
410 test_bindmount(argv[1]);
411 test_bindmount(procspath);
412 test_truncate(argv[1]);
413 test_truncate(procspath);
414 test_chdir(argv[1]);
415 test_chdir(procspath);
416 test_rename(argv[1]);
417 test_rename(procspath);
418 test_mkdir(argv[1]);
419 test_mkdir(procspath);
420 test_rmdir(argv[1]);
421 test_rmdir(procspath);
422 test_creat(argv[1]);
423 test_creat(procspath);
424 test_link(argv[1]);
425 test_link(procspath);
426 test_unlink(argv[1]);
427 test_unlink(procspath);
428 test_symlink(argv[1]);
429 test_symlink(procspath);
430 test_readlink(argv[1]);
431 test_readlink(procspath);
432 test_chmod(argv[1]);
433 test_chmod(procspath);
434 test_chown(argv[1]);
435 test_chown(procspath);
436 test_lchown(argv[1]);
437 test_lchown(procspath);
438 test_mknod(argv[1]);
439 test_mknod(procspath);
440 test_chroot(argv[1]);
441 test_chroot(procspath);
442 test_xattrs(argv[1]);
443 test_xattrs(procspath);
444 test_utimes(argv[1]);
445 test_utimes(procspath);
446
447 test_openat(argv[1]);
448 // meh... linkat etc?
449
450 printf("All tests passed\n");
451 return 0;
452}