Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <fcntl.h>
3 : : #include <ctype.h>
4 : : #include <string.h>
5 : : #include <stdlib.h>
6 : :
7 : : #include "types.h"
8 : : #include "sysctl.h"
9 : : #include "util.h"
10 : :
11 : : #define __SYSCTL_OP(__ret, __fd, __req, __type, __nr, __op) \
12 : : do { \
13 : : if (__op == CTL_READ) \
14 : : __ret = sysctl_read_##__type(__fd, __req, \
15 : : (__type *)(__req)->arg, \
16 : : __nr); \
17 : : else if (__op == CTL_WRITE) \
18 : : __ret = sysctl_write_##__type(__fd, __req, \
19 : : (__type *)(__req)->arg, \
20 : : __nr); \
21 : : else if (__op == CTL_PRINT) \
22 : : __ret = sysctl_print_##__type(__fd, __req, \
23 : : (__type *)(__req)->arg, \
24 : : __nr); \
25 : : else if (__op == CTL_PRINT) \
26 : : __ret = sysctl_show_##__type(__fd, __req, \
27 : : (__type *)(__req)->arg, \
28 : : __nr); \
29 : : else \
30 : : __ret = -1; \
31 : : } while (0)
32 : :
33 : : #define GEN_SYSCTL_READ_FUNC(__type, __conv) \
34 : : static int sysctl_read_##__type(int fd, \
35 : : struct sysctl_req *req, \
36 : : __type *arg, \
37 : : int nr) \
38 : : { \
39 : : char buf[1024] = {0}; \
40 : : int i, ret = -1; \
41 : : char *p = buf; \
42 : : \
43 : : ret = read(fd, buf, sizeof(buf)); \
44 : : if (ret < 0) { \
45 : : pr_perror("Can't read %s", req->name); \
46 : : ret = -1; \
47 : : goto err; \
48 : : } \
49 : : \
50 : : for (i = 0; i < nr && p < buf + sizeof(buf); p++, i++) \
51 : : ((__type *)arg)[i] = __conv(p, &p, 10); \
52 : : \
53 : : if (i != nr) { \
54 : : pr_err("Not enough params for %s (%d != %d)\n", \
55 : : req->name, i, nr); \
56 : : goto err; \
57 : : } \
58 : : \
59 : : ret = 0; \
60 : : \
61 : : err: \
62 : : return ret; \
63 : : }
64 : :
65 : : #define GEN_SYSCTL_WRITE_FUNC(__type, __fmt) \
66 : : static int sysctl_write_##__type(int fd, \
67 : : struct sysctl_req *req, \
68 : : __type *arg, \
69 : : int nr) \
70 : : { \
71 : : char buf[1024]; \
72 : : int i, ret = -1; \
73 : : int off = 0; \
74 : : \
75 : : for (i = 0; i < nr && off < sizeof(buf) - 2; i++) { \
76 : : snprintf(&buf[off], sizeof(buf) - off, __fmt, arg[i]); \
77 : : off += strlen(&buf[off]); \
78 : : } \
79 : : \
80 : : if (i != nr) { \
81 : : pr_err("Not enough space for %s (%d != %d)\n", \
82 : : req->name, i, nr); \
83 : : goto err; \
84 : : } \
85 : : \
86 : : /* trailing spaces in format */ \
87 : : while (off > 0 && isspace(buf[off - 1])) \
88 : : off--; \
89 : : buf[off + 0] = '\n'; \
90 : : buf[off + 1] = '\0'; \
91 : : ret = write(fd, buf, off + 2); \
92 : : if (ret < 0) { \
93 : : pr_perror("Can't write %s", req->name); \
94 : : ret = -1; \
95 : : goto err; \
96 : : } \
97 : : \
98 : : ret = 0; \
99 : : err: \
100 : : return ret; \
101 : : }
102 : :
103 : : #define GEN_SYSCTL_PRINT_FUNC(__type, __fmt) \
104 : : static int sysctl_print_##__type(int fd, \
105 : : struct sysctl_req *req, \
106 : : __type *arg, \
107 : : int nr) \
108 : : { \
109 : : int i; \
110 : : pr_info("sysctl: <%s> = <", req->name); \
111 : : for (i = 0; i < nr; i++) \
112 : : pr_info(__fmt, arg[i]); \
113 : : pr_info(">\n"); \
114 : : \
115 : : return 0; \
116 : : }
117 : :
118 : : #define GEN_SYSCTL_SHOW_FUNC(__type, __fmt) \
119 : : static int sysctl_show_##__type(int fd, \
120 : : struct sysctl_req *req, \
121 : : __type *arg, \
122 : : int nr) \
123 : : { \
124 : : int i; \
125 : : pr_msg("sysctl: <%s> = <", req->name); \
126 : : for (i = 0; i < nr; i++) \
127 : : pr_msg(__fmt, arg[i]); \
128 : : pr_msg(">\n"); \
129 : : \
130 : : return 0; \
131 : : }
132 : :
133 [ + - ][ + + ]: 1865 : GEN_SYSCTL_READ_FUNC(u32, strtoul);
[ + - ][ - + ]
134 [ + - ][ + + ]: 324 : GEN_SYSCTL_READ_FUNC(u64, strtoull);
[ + - ][ - + ]
135 : :
136 [ + + ][ + - ]: 7455 : GEN_SYSCTL_WRITE_FUNC(u32, "%u ");
[ + - ][ + + ]
[ - + ]
137 [ + + ][ + - ]: 1350 : GEN_SYSCTL_WRITE_FUNC(u64, "%lu ");
[ + - ][ + + ]
[ - + ]
138 : :
139 [ + + ]: 5175 : GEN_SYSCTL_PRINT_FUNC(u32, "%u ");
140 [ + + ]: 900 : GEN_SYSCTL_PRINT_FUNC(u64, "%lu ");
141 [ # # ]: 0 : GEN_SYSCTL_PRINT_FUNC(char, "%c");
142 : :
143 [ # # ]: 0 : GEN_SYSCTL_SHOW_FUNC(u32, "%u ");
144 [ # # ]: 0 : GEN_SYSCTL_SHOW_FUNC(u64, "%lu ");
145 [ # # ]: 0 : GEN_SYSCTL_SHOW_FUNC(char, "%c");
146 : :
147 : : static int
148 : 436 : sysctl_write_char(int fd, struct sysctl_req *req, char *arg, int nr)
149 : : {
150 : 436 : pr_debug("%s nr %d\n", req->name, nr);
151 [ + - ]: 436 : if (dprintf(fd, "%s\n", arg) < 0)
152 : : return -1;
153 : :
154 : : return 0;
155 : : }
156 : :
157 : : static int
158 : 0 : sysctl_read_char(int fd, struct sysctl_req *req, char *arg, int nr)
159 : : {
160 : 0 : int ret = -1;
161 : :
162 : 0 : pr_debug("%s nr %d\n", req->name, nr);
163 : 0 : ret = read(fd, arg, nr);
164 [ # # ]: 0 : if (ret < 0) {
165 : 0 : pr_perror("Can't read %s", req->name);
166 : : goto err;
167 : : }
168 : : ret = 0;
169 : :
170 : : err:
171 : 0 : return ret;
172 : : }
173 : :
174 : 6819 : static int __sysctl_op(int dir, struct sysctl_req *req, int op)
175 : : {
176 : 6819 : int fd = -1;
177 : 6819 : int ret = -1;
178 : 6819 : int nr = 1;
179 : :
180 [ + + ]: 6819 : if (dir > 0) {
181 : : int flags;
182 : :
183 [ + + ]: 4119 : if (op == CTL_READ)
184 : : flags = O_RDONLY;
185 : : else
186 : 3146 : flags = O_WRONLY;
187 : :
188 : 4119 : fd = openat(dir, req->name, flags);
189 [ - + ]: 4119 : if (fd < 0) {
190 : 0 : pr_perror("Can't open sysctl %s", req->name);
191 : 0 : return -1;
192 : : }
193 : : }
194 : :
195 [ + + - + : 6819 : switch (CTL_TYPE(req->type)) {
+ - ]
196 : : case __CTL_U32A:
197 : 531 : nr = CTL_LEN(req->type);
198 : : case CTL_U32:
199 [ + + ][ + + ]: 5321 : __SYSCTL_OP(ret, fd, req, u32, nr, op);
[ + - ][ # # ]
200 : : break;
201 : : case __CTL_U64A:
202 : 0 : nr = CTL_LEN(req->type);
203 : : case CTL_U64:
204 [ + + ][ + + ]: 1062 : __SYSCTL_OP(ret, fd, req, u64, nr, op);
[ + - ][ # # ]
205 : : break;
206 : : case __CTL_STR:
207 : 436 : nr = CTL_LEN(req->type);
208 [ - + ][ + - ]: 436 : __SYSCTL_OP(ret, fd, req, char, nr, op);
[ # # ][ # # ]
209 : : break;
210 : : }
211 : :
212 [ + + ]: 6819 : if (fd > 0)
213 : 4119 : close(fd);
214 : :
215 : 6819 : return ret;
216 : : }
217 : :
218 : 760 : int sysctl_op(struct sysctl_req *req, int op)
219 : : {
220 : 760 : int ret = 0;
221 : 760 : int dir = -1;
222 : :
223 [ + + ]: 760 : if (op != CTL_PRINT && op != CTL_SHOW) {
224 : 535 : dir = open("/proc/sys", O_RDONLY);
225 [ + - ]: 760 : if (dir < 0) {
226 : 0 : pr_perror("Can't open sysctl dir");
227 : 0 : return -1;
228 : : }
229 : : }
230 : :
231 [ + + ]: 7579 : while (req->name) {
232 : 6819 : ret = __sysctl_op(dir, req, op);
233 [ + - ]: 6819 : if (ret < 0)
234 : : break;
235 : 6819 : req++;
236 : : }
237 : :
238 [ + + ]: 760 : if (dir > 0)
239 : 535 : close(dir);
240 : 760 : return ret;
241 : 3136 : }
|