Commit | Line | Data |
---|---|---|
3ba23f05 MB |
1 | This patch adds bindings to Linux syscalls for which glibc has symbols. |
2 | ||
3 | Using the FFI would have been nice, but that's not an option when using | |
4 | a statically-linked Guile in an initrd that doesn't have libc.so around. | |
5 | ||
6 | diff --git a/libguile/posix.c b/libguile/posix.c | |
7 | --- a/libguile/posix.c | |
8 | +++ b/libguile/posix.c | |
9 | @@ -2375,6 +2375,336 @@ scm_init_popen (void) | |
10 | } | |
11 | #endif /* HAVE_START_CHILD */ | |
12 | ||
13 | +\f | |
14 | +/* Linux! */ | |
15 | +#ifdef __linux__ | |
16 | + | |
17 | +#include <sys/mount.h> | |
18 | +#include <sys/syscall.h> | |
19 | + | |
20 | +#include "libguile/foreign.h" | |
21 | +#include "libguile/bytevectors.h" | |
22 | +#include <libguile/variable.h> | |
23 | + | |
24 | +SCM_DEFINE (scm_mount, "mount", 3, 2, 0, | |
25 | + (SCM source, SCM target, SCM type, SCM flags, SCM data), | |
26 | + "Mount file system of @var{type} specified by @var{source} " | |
27 | + "on @var{target}.") | |
28 | +#define FUNC_NAME s_scm_mount | |
29 | +{ | |
30 | + int err; | |
31 | + char *c_source, *c_target, *c_type, *c_data; | |
32 | + unsigned long c_flags; | |
33 | + | |
34 | + c_source = scm_to_locale_string (source); | |
35 | + c_target = scm_to_locale_string (target); | |
36 | + c_type = scm_to_locale_string (type); | |
37 | + c_flags = SCM_UNBNDP (flags) ? 0 : scm_to_ulong (flags); | |
38 | + | |
39 | + if (SCM_UNBNDP (data) || scm_is_false (data)) | |
40 | + c_data = NULL; | |
41 | + else | |
42 | + c_data = scm_to_locale_string (data); | |
43 | + | |
44 | + err = mount (c_source, c_target, c_type, c_flags, c_data); | |
45 | + if (err != 0) | |
46 | + err = errno; | |
47 | + | |
48 | + free (c_source); | |
49 | + free (c_target); | |
50 | + free (c_type); | |
51 | + | |
52 | + if (c_data != NULL) | |
53 | + free (c_data); | |
54 | + | |
55 | + if (err != 0) | |
56 | + { | |
57 | + errno = err; | |
58 | + SCM_SYSERROR; | |
59 | + } | |
60 | + | |
61 | + return SCM_UNSPECIFIED; | |
62 | +} | |
63 | +#undef FUNC_NAME | |
64 | + | |
65 | +SCM_DEFINE (scm_umount, "umount", 1, 0, 0, | |
66 | + (SCM target), | |
67 | + "Unmount the file system on @var{target}.") | |
68 | +#define FUNC_NAME s_scm_umount | |
69 | +{ | |
70 | + int err; | |
71 | + char *c_target; | |
72 | + | |
73 | + c_target = scm_to_locale_string (target); | |
74 | + | |
75 | + err = umount (c_target); | |
76 | + if (err != 0) | |
77 | + err = errno; | |
78 | + | |
79 | + free (c_target); | |
80 | + | |
81 | + if (err != 0) | |
82 | + { | |
83 | + errno = err; | |
84 | + SCM_SYSERROR; | |
85 | + } | |
86 | + | |
87 | + return SCM_UNSPECIFIED; | |
88 | +} | |
89 | +#undef FUNC_NAME | |
90 | + | |
91 | +/* Linux's module installation syscall. See `kernel/module.c' in Linux; | |
92 | + the function itself is part of the GNU libc. | |
93 | + | |
94 | + Load the LEN bytes at MODULE as a kernel module, with arguments from | |
95 | + ARGS, a space-separated list of options. */ | |
96 | +extern long init_module (void *module, unsigned long len, const char *args); | |
97 | + | |
98 | +/* Load a kernel module from FD. FLAGS must be a bitwise or of | |
99 | + MODULE_INIT_* constants. The GNU libc doesn't provide a wrapper for | |
100 | + this one so we use 'syscall'. */ | |
101 | +static int | |
102 | +finit_module (int fd, const char *args, int flags) | |
103 | +{ | |
104 | + return syscall (SYS_finit_module, fd, args, flags); | |
105 | +} | |
106 | + | |
107 | + | |
108 | +SCM_DEFINE (scm_load_linux_module, "load-linux-module", 1, 1, 0, | |
109 | + (SCM data, SCM options), | |
110 | + "Load the Linux kernel module whose contents are in bytevector " | |
111 | + "DATA (the contents of a @code{.ko} file), with the arguments " | |
112 | + "from the OPTIONS string.") | |
113 | +#define FUNC_NAME s_scm_load_linux_module | |
114 | +{ | |
115 | + long err; | |
116 | + void *c_data; | |
117 | + unsigned long c_len; | |
118 | + char *c_options; | |
119 | + | |
120 | + SCM_VALIDATE_BYTEVECTOR (SCM_ARG1, data); | |
121 | + | |
122 | + c_data = SCM_BYTEVECTOR_CONTENTS (data); | |
123 | + c_len = SCM_BYTEVECTOR_LENGTH (data); | |
124 | + c_options = | |
125 | + scm_to_locale_string (SCM_UNBNDP (options) ? scm_nullstr : options); | |
126 | + | |
127 | + err = init_module (c_data, c_len, c_options); | |
128 | + | |
129 | + free (c_options); | |
130 | + | |
131 | + if (err != 0) | |
132 | + SCM_SYSERROR; | |
133 | + | |
134 | + return SCM_UNSPECIFIED; | |
135 | +} | |
136 | +#undef FUNC_NAME | |
137 | + | |
138 | +SCM_DEFINE (scm_load_linux_module_fd, "load-linux-module/fd", 1, 2, 0, | |
139 | + (SCM fd, SCM options, SCM flags), | |
140 | + "Load the Linux kernel module from the file at FD, " | |
141 | + "with the arguments from the OPTIONS string, and " | |
142 | + "optionally the given FLAGS.") | |
143 | +#define FUNC_NAME s_scm_load_linux_module_fd | |
144 | +{ | |
145 | + long err; | |
146 | + int c_fd, c_flags; | |
147 | + char *c_options; | |
148 | + | |
149 | + c_fd = scm_to_int (fd); | |
150 | + c_options = | |
151 | + scm_to_locale_string (SCM_UNBNDP (options) ? scm_nullstr : options); | |
152 | + c_flags = SCM_UNBNDP (flags) ? 0 : scm_to_int (flags); | |
153 | + | |
154 | + err = finit_module (c_fd, c_options, c_flags); | |
155 | + | |
156 | + free (c_options); | |
157 | + | |
158 | + if (err != 0) | |
159 | + SCM_SYSERROR; | |
160 | + | |
161 | + return SCM_UNSPECIFIED; | |
162 | +} | |
163 | +#undef FUNC_NAME | |
164 | + | |
165 | + | |
166 | +/* Rebooting, halting, and all that. */ | |
167 | + | |
168 | +#include <sys/reboot.h> | |
169 | + | |
170 | +SCM_VARIABLE_INIT (flag_RB_AUTOBOOT, "RB_AUTOBOOT", | |
171 | + scm_from_int (RB_AUTOBOOT)); | |
172 | +SCM_VARIABLE_INIT (flag_RB_HALT_SYSTEM, "RB_HALT_SYSTEM", | |
173 | + scm_from_int (RB_HALT_SYSTEM)); | |
174 | +SCM_VARIABLE_INIT (flag_RB_ENABLE_CAD, "RB_ENABLE_CAD", | |
175 | + scm_from_int (RB_ENABLE_CAD)); | |
176 | +SCM_VARIABLE_INIT (flag_RB_DISABLE_CAD, "RB_DISABLE_CAD", | |
177 | + scm_from_int (RB_DISABLE_CAD)); | |
178 | +SCM_VARIABLE_INIT (flag_RB_POWER_OFF, "RB_POWER_OFF", | |
179 | + scm_from_int (RB_POWER_OFF)); | |
180 | +SCM_VARIABLE_INIT (flag_RB_SW_SUSPEND, "RB_SW_SUSPEND", | |
181 | + scm_from_int (RB_SW_SUSPEND)); | |
182 | +SCM_VARIABLE_INIT (flag_RB_KEXEC, "RB_KEXEC", | |
183 | + scm_from_int (RB_KEXEC)); | |
184 | + | |
185 | +SCM_DEFINE (scm_reboot, "reboot", 0, 1, 0, | |
186 | + (SCM command), | |
187 | + "Reboot the system. @var{command} must be one of the @code{RB_} " | |
188 | + "constants; if omitted, @var{RB_AUTOBOOT} is used, thus " | |
189 | + "performing a hard reset.") | |
190 | +#define FUNC_NAME s_scm_reboot | |
191 | +{ | |
192 | + int c_command; | |
193 | + | |
194 | + if (SCM_UNBNDP (command)) | |
195 | + c_command = RB_AUTOBOOT; | |
196 | + else | |
197 | + c_command = scm_to_int (command); | |
198 | + | |
199 | + reboot (c_command); | |
200 | + | |
201 | + return SCM_UNSPECIFIED; /* likely unreached */ | |
202 | +} | |
203 | +#undef FUNC_NAME | |
204 | + | |
205 | +/* Linux network interfaces. See <linux/if.h>. */ | |
206 | + | |
207 | +#include <linux/if.h> | |
208 | +#include <linux/sockios.h> | |
209 | +#include "libguile/socket.h" | |
210 | + | |
211 | +SCM_VARIABLE_INIT (flag_IFF_UP, "IFF_UP", | |
212 | + scm_from_int (IFF_UP)); | |
213 | +SCM_VARIABLE_INIT (flag_IFF_BROADCAST, "IFF_BROADCAST", | |
214 | + scm_from_int (IFF_BROADCAST)); | |
215 | +SCM_VARIABLE_INIT (flag_IFF_DEBUG, "IFF_DEBUG", | |
216 | + scm_from_int (IFF_DEBUG)); | |
217 | +SCM_VARIABLE_INIT (flag_IFF_LOOPBACK, "IFF_LOOPBACK", | |
218 | + scm_from_int (IFF_LOOPBACK)); | |
219 | +SCM_VARIABLE_INIT (flag_IFF_POINTOPOINT, "IFF_POINTOPOINT", | |
220 | + scm_from_int (IFF_POINTOPOINT)); | |
221 | +SCM_VARIABLE_INIT (flag_IFF_NOTRAILERS, "IFF_NOTRAILERS", | |
222 | + scm_from_int (IFF_NOTRAILERS)); | |
223 | +SCM_VARIABLE_INIT (flag_IFF_RUNNING, "IFF_RUNNING", | |
224 | + scm_from_int (IFF_RUNNING)); | |
225 | +SCM_VARIABLE_INIT (flag_IFF_NOARP, "IFF_NOARP", | |
226 | + scm_from_int (IFF_NOARP)); | |
227 | +SCM_VARIABLE_INIT (flag_IFF_PROMISC, "IFF_PROMISC", | |
228 | + scm_from_int (IFF_PROMISC)); | |
229 | +SCM_VARIABLE_INIT (flag_IFF_ALLMULTI, "IFF_ALLMULTI", | |
230 | + scm_from_int (IFF_ALLMULTI)); | |
231 | + | |
232 | +SCM_DEFINE (scm_set_network_interface_address, "set-network-interface-address", | |
233 | + 3, 0, 0, | |
234 | + (SCM socket, SCM name, SCM address), | |
235 | + "Configure network interface @var{name}.") | |
236 | +#define FUNC_NAME s_scm_set_network_interface_address | |
237 | +{ | |
238 | + char *c_name; | |
239 | + struct ifreq ifr; | |
240 | + struct sockaddr *c_address; | |
241 | + size_t sa_len; | |
242 | + int fd, err; | |
243 | + | |
244 | + socket = SCM_COERCE_OUTPORT (socket); | |
245 | + SCM_VALIDATE_OPFPORT (1, socket); | |
246 | + fd = SCM_FPORT_FDES (socket); | |
247 | + | |
248 | + memset (&ifr, 0, sizeof ifr); | |
249 | + c_name = scm_to_locale_string (name); | |
250 | + c_address = scm_to_sockaddr (address, &sa_len); | |
251 | + | |
252 | + strncpy (ifr.ifr_name, c_name, sizeof ifr.ifr_name - 1); | |
253 | + memcpy (&ifr.ifr_addr, c_address, sa_len); | |
254 | + | |
255 | + err = ioctl (fd, SIOCSIFADDR, &ifr); | |
256 | + if (err != 0) | |
257 | + err = errno; | |
258 | + | |
259 | + free (c_name); | |
260 | + free (c_address); | |
261 | + | |
262 | + if (err != 0) | |
263 | + { | |
264 | + errno = err; | |
265 | + SCM_SYSERROR; | |
266 | + } | |
267 | + | |
268 | + return SCM_UNSPECIFIED; | |
269 | +} | |
270 | +#undef FUNC_NAME | |
271 | + | |
272 | +SCM_DEFINE (scm_set_network_interface_flags, "set-network-interface-flags", | |
273 | + 3, 0, 0, | |
274 | + (SCM socket, SCM name, SCM flags), | |
275 | + "Change the flags of network interface @var{name} to " | |
276 | + "@var{flags}.") | |
277 | +#define FUNC_NAME s_scm_set_network_interface_flags | |
278 | +{ | |
279 | + struct ifreq ifr; | |
280 | + char *c_name; | |
281 | + int fd, err; | |
282 | + | |
283 | + socket = SCM_COERCE_OUTPORT (socket); | |
284 | + SCM_VALIDATE_OPFPORT (1, socket); | |
285 | + fd = SCM_FPORT_FDES (socket); | |
286 | + | |
287 | + memset (&ifr, 0, sizeof ifr); | |
288 | + c_name = scm_to_locale_string (name); | |
289 | + strncpy (ifr.ifr_name, c_name, sizeof ifr.ifr_name - 1); | |
290 | + ifr.ifr_flags = scm_to_short (flags); | |
291 | + | |
292 | + err = ioctl (fd, SIOCSIFFLAGS, &ifr); | |
293 | + if (err != 0) | |
294 | + err = errno; | |
295 | + | |
296 | + free (c_name); | |
297 | + | |
298 | + if (err != 0) | |
299 | + { | |
300 | + errno = err; | |
301 | + SCM_SYSERROR; | |
302 | + } | |
303 | + | |
304 | + return SCM_UNSPECIFIED; | |
305 | +} | |
306 | +#undef FUNC_NAME | |
307 | + | |
308 | +SCM_DEFINE (scm_network_interface_flags, "network-interface-flags", | |
309 | + 2, 0, 0, | |
310 | + (SCM socket, SCM name), | |
311 | + "Return the flags of network interface @var{name}.") | |
312 | +#define FUNC_NAME s_scm_network_interface_flags | |
313 | +{ | |
314 | + struct ifreq ifr; | |
315 | + char *c_name; | |
316 | + int fd, err; | |
317 | + | |
318 | + socket = SCM_COERCE_OUTPORT (socket); | |
319 | + SCM_VALIDATE_OPFPORT (1, socket); | |
320 | + fd = SCM_FPORT_FDES (socket); | |
321 | + | |
322 | + memset (&ifr, 0, sizeof ifr); | |
323 | + c_name = scm_to_locale_string (name); | |
324 | + strncpy (ifr.ifr_name, c_name, sizeof ifr.ifr_name - 1); | |
325 | + | |
326 | + err = ioctl (fd, SIOCGIFFLAGS, &ifr); | |
327 | + if (err != 0) | |
328 | + err = errno; | |
329 | + | |
330 | + free (c_name); | |
331 | + | |
332 | + if (err != 0) | |
333 | + { | |
334 | + errno = err; | |
335 | + SCM_SYSERROR; | |
336 | + } | |
337 | + | |
338 | + return scm_from_short (ifr.ifr_flags); | |
339 | +} | |
340 | +#undef FUNC_NAME | |
341 | +#endif | |
342 | + | |
343 | void | |
344 | scm_init_posix () | |
345 | { |