xref: /linux/tools/testing/selftests/exec/binfmt_misc_common.h (revision 2686010586df2d8d01f44c670c943b3815dedc22)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Helpers shared by the binfmt_misc selftests. */
3 #ifndef __SELFTESTS_EXEC_BINFMT_MISC_COMMON_H
4 #define __SELFTESTS_EXEC_BINFMT_MISC_COMMON_H
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <libgen.h>
9 #include <limits.h>
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/mount.h>
14 #include <unistd.h>
15 
16 #define BINFMT_DIR	"/proc/sys/fs/binfmt_misc"
17 #define BINFMT_REG	BINFMT_DIR "/register"
18 
19 static inline int copy_file(const char *src, const char *dst)
20 {
21 	char buf[4096];
22 	int in, out;
23 	ssize_t n;
24 
25 	in = open(src, O_RDONLY);
26 	if (in < 0)
27 		return -1;
28 	/* The tests share /tmp, so never write through a name they don't own. */
29 	unlink(dst);
30 	out = open(dst, O_WRONLY | O_CREAT | O_EXCL, 0755);
31 	if (out < 0) {
32 		close(in);
33 		return -1;
34 	}
35 	while ((n = read(in, buf, sizeof(buf))) > 0) {
36 		if (write(out, buf, n) != n) {
37 			close(in);
38 			close(out);
39 			return -1;
40 		}
41 	}
42 	close(in);
43 	close(out);
44 	return n < 0 ? -1 : 0;
45 }
46 
47 /* Write @rule to the register file, preserving the write's errno. */
48 static inline int write_reg(const char *rule)
49 {
50 	int fd, saved;
51 	ssize_t n;
52 
53 	fd = open(BINFMT_REG, O_WRONLY);
54 	if (fd < 0)
55 		return -1;
56 	n = write(fd, rule, strlen(rule));
57 	saved = errno;
58 	close(fd);
59 	errno = saved;
60 	return n < 0 ? -1 : 0;
61 }
62 
63 static inline void unregister(const char *name)
64 {
65 	char path[PATH_MAX];
66 	int fd;
67 
68 	snprintf(path, sizeof(path), BINFMT_DIR "/%s", name);
69 	fd = open(path, O_WRONLY);
70 	if (fd >= 0) {
71 		if (write(fd, "-1", 2) < 0)
72 			; /* best effort */
73 		close(fd);
74 	}
75 }
76 
77 /* Mount binfmt_misc unless it already is, and report whether it is usable. */
78 static inline bool binfmt_misc_available(void)
79 {
80 	if (access(BINFMT_REG, F_OK) < 0)
81 		mount("binfmt_misc", BINFMT_DIR, "binfmt_misc", 0, NULL);
82 	return access(BINFMT_REG, F_OK) == 0;
83 }
84 
85 /* Absolute path of @name in the directory this test was built into. */
86 static inline int artifact_path(char *out, size_t sz, const char *name)
87 {
88 	char exe[PATH_MAX];
89 	ssize_t n;
90 
91 	n = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
92 	if (n < 0)
93 		return -1;
94 	exe[n] = '\0';
95 	if ((size_t)snprintf(out, sz, "%s/%s", dirname(exe), name) >= sz)
96 		return -1;
97 	return 0;
98 }
99 
100 #endif /* __SELFTESTS_EXEC_BINFMT_MISC_COMMON_H */
101