source: MondoRescue/branches/stable/mindi-busybox/networking/ifupdown.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 31.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * ifupdown for busybox
4 * Copyright (c) 2002 Glenn McGrath <bug1@iinet.net.au>
5 * Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org>
6 *
7 * Based on ifupdown v 0.6.4 by Anthony Towns
8 * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au>
9 *
10 * Changes to upstream version
11 * Remove checks for kernel version, assume kernel version 2.2.0 or better.
12 * Lines in the interfaces file cannot wrap.
13 * To adhere to the FHS, the default state file is /var/run/ifstate
14 * (defined via CONFIG_IFUPDOWN_IFSTATE_PATH) and can be overridden by build
15 * configuration.
16 *
17 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
18 */
19
20#include <sys/utsname.h>
21#include <fnmatch.h>
22#include <getopt.h>
23
24#include "libbb.h"
25
26#define MAX_OPT_DEPTH 10
27#define EUNBALBRACK 10001
28#define EUNDEFVAR 10002
29#define EUNBALPER 10000
30
31#if ENABLE_FEATURE_IFUPDOWN_MAPPING
32#define MAX_INTERFACE_LENGTH 10
33#endif
34
35#define debug_noise(args...) /*fprintf(stderr, args)*/
36
37/* Forward declaration */
38struct interface_defn_t;
39
40typedef int execfn(char *command);
41
42struct method_t {
43 const char *name;
44 int (*up)(struct interface_defn_t *ifd, execfn *e);
45 int (*down)(struct interface_defn_t *ifd, execfn *e);
46};
47
48struct address_family_t {
49 const char *name;
50 int n_methods;
51 const struct method_t *method;
52};
53
54struct mapping_defn_t {
55 struct mapping_defn_t *next;
56
57 int max_matches;
58 int n_matches;
59 char **match;
60
61 char *script;
62
63 int max_mappings;
64 int n_mappings;
65 char **mapping;
66};
67
68struct variable_t {
69 char *name;
70 char *value;
71};
72
73struct interface_defn_t {
74 const struct address_family_t *address_family;
75 const struct method_t *method;
76
77 char *iface;
78 int max_options;
79 int n_options;
80 struct variable_t *option;
81};
82
83struct interfaces_file_t {
84 llist_t *autointerfaces;
85 llist_t *ifaces;
86 struct mapping_defn_t *mappings;
87};
88
89#define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:"
90enum {
91 OPT_do_all = 0x1,
92 OPT_no_act = 0x2,
93 OPT_verbose = 0x4,
94 OPT_force = 0x8,
95 OPT_no_mappings = 0x10,
96};
97#define DO_ALL (option_mask32 & OPT_do_all)
98#define NO_ACT (option_mask32 & OPT_no_act)
99#define VERBOSE (option_mask32 & OPT_verbose)
100#define FORCE (option_mask32 & OPT_force)
101#define NO_MAPPINGS (option_mask32 & OPT_no_mappings)
102
103static char **my_environ;
104
105static const char *startup_PATH;
106
107#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
108
109static void addstr(char **bufp, const char *str, size_t str_length)
110{
111 /* xasprintf trick will be smaller, but we are often
112 * called with str_length == 1 - don't want to have
113 * THAT much of malloc/freeing! */
114 char *buf = *bufp;
115 int len = (buf ? strlen(buf) : 0);
116 str_length++;
117 buf = xrealloc(buf, len + str_length);
118 /* copies at most str_length-1 chars! */
119 safe_strncpy(buf + len, str, str_length);
120 *bufp = buf;
121}
122
123static int strncmpz(const char *l, const char *r, size_t llen)
124{
125 int i = strncmp(l, r, llen);
126
127 if (i == 0)
128 return -r[llen];
129 return i;
130}
131
132static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd)
133{
134 int i;
135
136 if (strncmpz(id, "iface", idlen) == 0) {
137 char *result;
138 static char label_buf[20];
139 safe_strncpy(label_buf, ifd->iface, sizeof(label_buf));
140 result = strchr(label_buf, ':');
141 if (result) {
142 *result = '\0';
143 }
144 return label_buf;
145 }
146 if (strncmpz(id, "label", idlen) == 0) {
147 return ifd->iface;
148 }
149 for (i = 0; i < ifd->n_options; i++) {
150 if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
151 return ifd->option[i].value;
152 }
153 }
154 return NULL;
155}
156
157#if ENABLE_FEATURE_IFUPDOWN_IP
158static int count_netmask_bits(const char *dotted_quad)
159{
160// int result;
161// unsigned a, b, c, d;
162// /* Found a netmask... Check if it is dotted quad */
163// if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
164// return -1;
165// if ((a|b|c|d) >> 8)
166// return -1; /* one of numbers is >= 256 */
167// d |= (a << 24) | (b << 16) | (c << 8); /* IP */
168// d = ~d; /* 11110000 -> 00001111 */
169
170 /* Shorter version */
171 int result;
172 struct in_addr ip;
173 unsigned d;
174
175 if (inet_aton(dotted_quad, &ip) == 0)
176 return -1; /* malformed dotted IP */
177 d = ntohl(ip.s_addr); /* IP in host order */
178 d = ~d; /* 11110000 -> 00001111 */
179 if (d & (d+1)) /* check that it is in 00001111 form */
180 return -1; /* no it is not */
181 result = 32;
182 while (d) {
183 d >>= 1;
184 result--;
185 }
186 return result;
187}
188#endif
189
190static char *parse(const char *command, struct interface_defn_t *ifd)
191{
192 size_t old_pos[MAX_OPT_DEPTH] = { 0 };
193 int okay[MAX_OPT_DEPTH] = { 1 };
194 int opt_depth = 1;
195 char *result = NULL;
196
197 while (*command) {
198 switch (*command) {
199 default:
200 addstr(&result, command, 1);
201 command++;
202 break;
203 case '\\':
204 if (command[1]) {
205 addstr(&result, command + 1, 1);
206 command += 2;
207 } else {
208 addstr(&result, command, 1);
209 command++;
210 }
211 break;
212 case '[':
213 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
214 old_pos[opt_depth] = result ? strlen(result) : 0;
215 okay[opt_depth] = 1;
216 opt_depth++;
217 command += 2;
218 } else {
219 addstr(&result, "[", 1);
220 command++;
221 }
222 break;
223 case ']':
224 if (command[1] == ']' && opt_depth > 1) {
225 opt_depth--;
226 if (!okay[opt_depth]) {
227 result[old_pos[opt_depth]] = '\0';
228 }
229 command += 2;
230 } else {
231 addstr(&result, "]", 1);
232 command++;
233 }
234 break;
235 case '%':
236 {
237 char *nextpercent;
238 char *varvalue;
239
240 command++;
241 nextpercent = strchr(command, '%');
242 if (!nextpercent) {
243 errno = EUNBALPER;
244 free(result);
245 return NULL;
246 }
247
248 varvalue = get_var(command, nextpercent - command, ifd);
249
250 if (varvalue) {
251 addstr(&result, varvalue, strlen(varvalue));
252 } else {
253#if ENABLE_FEATURE_IFUPDOWN_IP
254 /* Sigh... Add a special case for 'ip' to convert from
255 * dotted quad to bit count style netmasks. */
256 if (strncmp(command, "bnmask", 6) == 0) {
257 unsigned res;
258 varvalue = get_var("netmask", 7, ifd);
259 if (varvalue) {
260 res = count_netmask_bits(varvalue);
261 if (res > 0) {
262 const char *argument = utoa(res);
263 addstr(&result, argument, strlen(argument));
264 command = nextpercent + 1;
265 break;
266 }
267 }
268 }
269#endif
270 okay[opt_depth - 1] = 0;
271 }
272
273 command = nextpercent + 1;
274 }
275 break;
276 }
277 }
278
279 if (opt_depth > 1) {
280 errno = EUNBALBRACK;
281 free(result);
282 return NULL;
283 }
284
285 if (!okay[0]) {
286 errno = EUNDEFVAR;
287 free(result);
288 return NULL;
289 }
290
291 return result;
292}
293
294/* execute() returns 1 for success and 0 for failure */
295static int execute(const char *command, struct interface_defn_t *ifd, execfn *exec)
296{
297 char *out;
298 int ret;
299
300 out = parse(command, ifd);
301 if (!out) {
302 /* parse error? */
303 return 0;
304 }
305 /* out == "": parsed ok but not all needed variables known, skip */
306 ret = out[0] ? (*exec)(out) : 1;
307
308 free(out);
309 if (ret != 1) {
310 return 0;
311 }
312 return 1;
313}
314#endif
315
316#if ENABLE_FEATURE_IFUPDOWN_IPV6
317static int loopback_up6(struct interface_defn_t *ifd, execfn *exec)
318{
319#if ENABLE_FEATURE_IFUPDOWN_IP
320 int result;
321 result = execute("ip addr add ::1 dev %iface%", ifd, exec);
322 result += execute("ip link set %iface% up", ifd, exec);
323 return ((result == 2) ? 2 : 0);
324#else
325 return execute("ifconfig %iface% add ::1", ifd, exec);
326#endif
327}
328
329static int loopback_down6(struct interface_defn_t *ifd, execfn *exec)
330{
331#if ENABLE_FEATURE_IFUPDOWN_IP
332 return execute("ip link set %iface% down", ifd, exec);
333#else
334 return execute("ifconfig %iface% del ::1", ifd, exec);
335#endif
336}
337
338static int static_up6(struct interface_defn_t *ifd, execfn *exec)
339{
340 int result;
341#if ENABLE_FEATURE_IFUPDOWN_IP
342 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
343 result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
344 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
345 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
346#else
347 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
348 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
349 result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec);
350#endif
351 return ((result == 3) ? 3 : 0);
352}
353
354static int static_down6(struct interface_defn_t *ifd, execfn *exec)
355{
356#if ENABLE_FEATURE_IFUPDOWN_IP
357 return execute("ip link set %iface% down", ifd, exec);
358#else
359 return execute("ifconfig %iface% down", ifd, exec);
360#endif
361}
362
363#if ENABLE_FEATURE_IFUPDOWN_IP
364static int v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
365{
366 int result;
367 result = execute("ip tunnel add %iface% mode sit remote "
368 "%endpoint%[[ local %local%]][[ ttl %ttl%]]", ifd, exec);
369 result += execute("ip link set %iface% up", ifd, exec);
370 result += execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec);
371 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
372 return ((result == 4) ? 4 : 0);
373}
374
375static int v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
376{
377 return execute("ip tunnel del %iface%", ifd, exec);
378}
379#endif
380
381static const struct method_t methods6[] = {
382#if ENABLE_FEATURE_IFUPDOWN_IP
383 { "v4tunnel", v4tunnel_up, v4tunnel_down, },
384#endif
385 { "static", static_up6, static_down6, },
386 { "loopback", loopback_up6, loopback_down6, },
387};
388
389static const struct address_family_t addr_inet6 = {
390 "inet6",
391 ARRAY_SIZE(methods6),
392 methods6
393};
394#endif /* FEATURE_IFUPDOWN_IPV6 */
395
396#if ENABLE_FEATURE_IFUPDOWN_IPV4
397static int loopback_up(struct interface_defn_t *ifd, execfn *exec)
398{
399#if ENABLE_FEATURE_IFUPDOWN_IP
400 int result;
401 result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec);
402 result += execute("ip link set %iface% up", ifd, exec);
403 return ((result == 2) ? 2 : 0);
404#else
405 return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec);
406#endif
407}
408
409static int loopback_down(struct interface_defn_t *ifd, execfn *exec)
410{
411#if ENABLE_FEATURE_IFUPDOWN_IP
412 int result;
413 result = execute("ip addr flush dev %iface%", ifd, exec);
414 result += execute("ip link set %iface% down", ifd, exec);
415 return ((result == 2) ? 2 : 0);
416#else
417 return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec);
418#endif
419}
420
421static int static_up(struct interface_defn_t *ifd, execfn *exec)
422{
423 int result;
424#if ENABLE_FEATURE_IFUPDOWN_IP
425 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
426 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
427 result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
428 result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);
429 return ((result == 3) ? 3 : 0);
430#else
431 /* ifconfig said to set iface up before it processes hw %hwaddress%,
432 * which then of course fails. Thus we run two separate ifconfig */
433 result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
434 ifd, exec);
435 result += execute("ifconfig %iface% %address% netmask %netmask%"
436 "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
437 ifd, exec);
438 result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);
439 return ((result == 3) ? 3 : 0);
440#endif
441}
442
443static int static_down(struct interface_defn_t *ifd, execfn *exec)
444{
445 int result;
446#if ENABLE_FEATURE_IFUPDOWN_IP
447 result = execute("ip addr flush dev %iface%", ifd, exec);
448 result += execute("ip link set %iface% down", ifd, exec);
449#else
450 result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec);
451 result += execute("ifconfig %iface% down", ifd, exec);
452#endif
453 return ((result == 2) ? 2 : 0);
454}
455
456#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
457struct dhcp_client_t
458{
459 const char *name;
460 const char *startcmd;
461 const char *stopcmd;
462};
463
464static const struct dhcp_client_t ext_dhcp_clients[] = {
465 { "dhcpcd",
466 "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%",
467 "dhcpcd -k %iface%",
468 },
469 { "dhclient",
470 "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",
471 "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",
472 },
473 { "pump",
474 "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",
475 "pump -i %iface% -k",
476 },
477 { "udhcpc",
478 "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
479 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
480 },
481};
482#endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
483
484static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)
485{
486#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
487 int i;
488#if ENABLE_FEATURE_IFUPDOWN_IP
489 /* ip doesn't up iface when it configures it (unlike ifconfig) */
490 if (!execute("ip link set %iface% up", ifd, exec))
491 return 0;
492#endif
493 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
494 if (exists_execable(ext_dhcp_clients[i].name))
495 return execute(ext_dhcp_clients[i].startcmd, ifd, exec);
496 }
497 bb_error_msg("no dhcp clients found");
498 return 0;
499#elif ENABLE_APP_UDHCPC
500#if ENABLE_FEATURE_IFUPDOWN_IP
501 /* ip doesn't up iface when it configures it (unlike ifconfig) */
502 if (!execute("ip link set %iface% up", ifd, exec))
503 return 0;
504#endif
505 return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid "
506 "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
507 ifd, exec);
508#else
509 return 0; /* no dhcp support */
510#endif
511}
512
513static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
514{
515#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
516 int i;
517 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
518 if (exists_execable(ext_dhcp_clients[i].name))
519 return execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
520 }
521 bb_error_msg("no dhcp clients found, using static interface shutdown");
522 return static_down(ifd, exec);
523#elif ENABLE_APP_UDHCPC
524 return execute("kill "
525 "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
526#else
527 return 0; /* no dhcp support */
528#endif
529}
530
531static int manual_up_down(struct interface_defn_t *ifd, execfn *exec)
532{
533 return 1;
534}
535
536static int bootp_up(struct interface_defn_t *ifd, execfn *exec)
537{
538 return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
539 "[[ --server %server%]][[ --hwaddr %hwaddr%]]"
540 " --returniffail --serverbcast", ifd, exec);
541}
542
543static int ppp_up(struct interface_defn_t *ifd, execfn *exec)
544{
545 return execute("pon[[ %provider%]]", ifd, exec);
546}
547
548static int ppp_down(struct interface_defn_t *ifd, execfn *exec)
549{
550 return execute("poff[[ %provider%]]", ifd, exec);
551}
552
553static int wvdial_up(struct interface_defn_t *ifd, execfn *exec)
554{
555 return execute("start-stop-daemon --start -x wvdial "
556 "-p /var/run/wvdial.%iface% -b -m --[[ %provider%]]", ifd, exec);
557}
558
559static int wvdial_down(struct interface_defn_t *ifd, execfn *exec)
560{
561 return execute("start-stop-daemon --stop -x wvdial "
562 "-p /var/run/wvdial.%iface% -s 2", ifd, exec);
563}
564
565static const struct method_t methods[] = {
566 { "manual", manual_up_down, manual_up_down, },
567 { "wvdial", wvdial_up, wvdial_down, },
568 { "ppp", ppp_up, ppp_down, },
569 { "static", static_up, static_down, },
570 { "bootp", bootp_up, static_down, },
571 { "dhcp", dhcp_up, dhcp_down, },
572 { "loopback", loopback_up, loopback_down, },
573};
574
575static const struct address_family_t addr_inet = {
576 "inet",
577 ARRAY_SIZE(methods),
578 methods
579};
580
581#endif /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */
582
583static char *next_word(char **buf)
584{
585 unsigned short length;
586 char *word;
587
588 if (!buf || !*buf || !**buf) {
589 return NULL;
590 }
591
592 /* Skip over leading whitespace */
593 word = skip_whitespace(*buf);
594
595 /* Skip over comments */
596 if (*word == '#') {
597 return NULL;
598 }
599
600 /* Find the length of this word */
601 length = strcspn(word, " \t\n");
602 if (length == 0) {
603 return NULL;
604 }
605 *buf = word + length;
606 /*DBU:[dave@cray.com] if we are already at EOL dont't increment beyond it */
607 if (**buf) {
608 **buf = '\0';
609 (*buf)++;
610 }
611
612 return word;
613}
614
615static const struct address_family_t *get_address_family(const struct address_family_t *const af[], char *name)
616{
617 int i;
618
619 if (!name)
620 return NULL;
621
622 for (i = 0; af[i]; i++) {
623 if (strcmp(af[i]->name, name) == 0) {
624 return af[i];
625 }
626 }
627 return NULL;
628}
629
630static const struct method_t *get_method(const struct address_family_t *af, char *name)
631{
632 int i;
633
634 if (!name)
635 return NULL;
636
637 for (i = 0; i < af->n_methods; i++) {
638 if (strcmp(af->method[i].name, name) == 0) {
639 return &af->method[i];
640 }
641 }
642 return NULL;
643}
644
645static const llist_t *find_list_string(const llist_t *list, const char *string)
646{
647 if (string == NULL)
648 return NULL;
649
650 while (list) {
651 if (strcmp(list->data, string) == 0) {
652 return list;
653 }
654 list = list->link;
655 }
656 return NULL;
657}
658
659static struct interfaces_file_t *read_interfaces(const char *filename)
660{
661#if ENABLE_FEATURE_IFUPDOWN_MAPPING
662 struct mapping_defn_t *currmap = NULL;
663#endif
664 struct interface_defn_t *currif = NULL;
665 struct interfaces_file_t *defn;
666 FILE *f;
667 char *firstword;
668 char *buf;
669
670 enum { NONE, IFACE, MAPPING } currently_processing = NONE;
671
672 defn = xzalloc(sizeof(struct interfaces_file_t));
673
674 f = xfopen(filename, "r");
675
676 while ((buf = xmalloc_getline(f)) != NULL) {
677 char *buf_ptr = buf;
678
679 firstword = next_word(&buf_ptr);
680 if (firstword == NULL) {
681 free(buf);
682 continue; /* blank line */
683 }
684
685 if (strcmp(firstword, "mapping") == 0) {
686#if ENABLE_FEATURE_IFUPDOWN_MAPPING
687 currmap = xzalloc(sizeof(struct mapping_defn_t));
688
689 while ((firstword = next_word(&buf_ptr)) != NULL) {
690 if (currmap->max_matches == currmap->n_matches) {
691 currmap->max_matches = currmap->max_matches * 2 + 1;
692 currmap->match = xrealloc(currmap->match, sizeof(currmap->match) * currmap->max_matches);
693 }
694
695 currmap->match[currmap->n_matches++] = xstrdup(firstword);
696 }
697 currmap->max_mappings = 0;
698 currmap->n_mappings = 0;
699 currmap->mapping = NULL;
700 currmap->script = NULL;
701 {
702 struct mapping_defn_t **where = &defn->mappings;
703 while (*where != NULL) {
704 where = &(*where)->next;
705 }
706 *where = currmap;
707 currmap->next = NULL;
708 }
709 debug_noise("Added mapping\n");
710#endif
711 currently_processing = MAPPING;
712 } else if (strcmp(firstword, "iface") == 0) {
713 static const struct address_family_t *const addr_fams[] = {
714#if ENABLE_FEATURE_IFUPDOWN_IPV4
715 &addr_inet,
716#endif
717#if ENABLE_FEATURE_IFUPDOWN_IPV6
718 &addr_inet6,
719#endif
720 NULL
721 };
722
723 char *iface_name;
724 char *address_family_name;
725 char *method_name;
726 llist_t *iface_list;
727
728 currif = xzalloc(sizeof(struct interface_defn_t));
729 iface_name = next_word(&buf_ptr);
730 address_family_name = next_word(&buf_ptr);
731 method_name = next_word(&buf_ptr);
732
733 if (buf_ptr == NULL) {
734 bb_error_msg("too few parameters for line \"%s\"", buf);
735 return NULL;
736 }
737
738 /* ship any trailing whitespace */
739 buf_ptr = skip_whitespace(buf_ptr);
740
741 if (buf_ptr[0] != '\0') {
742 bb_error_msg("too many parameters \"%s\"", buf);
743 return NULL;
744 }
745
746 currif->iface = xstrdup(iface_name);
747
748 currif->address_family = get_address_family(addr_fams, address_family_name);
749 if (!currif->address_family) {
750 bb_error_msg("unknown address type \"%s\"", address_family_name);
751 return NULL;
752 }
753
754 currif->method = get_method(currif->address_family, method_name);
755 if (!currif->method) {
756 bb_error_msg("unknown method \"%s\"", method_name);
757 return NULL;
758 }
759
760 for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
761 struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
762 if ((strcmp(tmp->iface, currif->iface) == 0) &&
763 (tmp->address_family == currif->address_family)) {
764 bb_error_msg("duplicate interface \"%s\"", tmp->iface);
765 return NULL;
766 }
767 }
768 llist_add_to_end(&(defn->ifaces), (char*)currif);
769
770 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
771 currently_processing = IFACE;
772 } else if (strcmp(firstword, "auto") == 0) {
773 while ((firstword = next_word(&buf_ptr)) != NULL) {
774
775 /* Check the interface isnt already listed */
776 if (find_list_string(defn->autointerfaces, firstword)) {
777 bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf);
778 }
779
780 /* Add the interface to the list */
781 llist_add_to_end(&(defn->autointerfaces), xstrdup(firstword));
782 debug_noise("\nauto %s\n", firstword);
783 }
784 currently_processing = NONE;
785 } else {
786 switch (currently_processing) {
787 case IFACE:
788 {
789 int i;
790
791 if (strlen(buf_ptr) == 0) {
792 bb_error_msg("option with empty value \"%s\"", buf);
793 return NULL;
794 }
795
796 if (strcmp(firstword, "up") != 0
797 && strcmp(firstword, "down") != 0
798 && strcmp(firstword, "pre-up") != 0
799 && strcmp(firstword, "post-down") != 0) {
800 for (i = 0; i < currif->n_options; i++) {
801 if (strcmp(currif->option[i].name, firstword) == 0) {
802 bb_error_msg("duplicate option \"%s\"", buf);
803 return NULL;
804 }
805 }
806 }
807 }
808 if (currif->n_options >= currif->max_options) {
809 struct variable_t *opt;
810
811 currif->max_options = currif->max_options + 10;
812 opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
813 currif->option = opt;
814 }
815 currif->option[currif->n_options].name = xstrdup(firstword);
816 currif->option[currif->n_options].value = xstrdup(buf_ptr);
817 if (!currif->option[currif->n_options].name) {
818 perror(filename);
819 return NULL;
820 }
821 if (!currif->option[currif->n_options].value) {
822 perror(filename);
823 return NULL;
824 }
825 debug_noise("\t%s=%s\n", currif->option[currif->n_options].name,
826 currif->option[currif->n_options].value);
827 currif->n_options++;
828 break;
829 case MAPPING:
830#if ENABLE_FEATURE_IFUPDOWN_MAPPING
831 if (strcmp(firstword, "script") == 0) {
832 if (currmap->script != NULL) {
833 bb_error_msg("duplicate script in mapping \"%s\"", buf);
834 return NULL;
835 } else {
836 currmap->script = xstrdup(next_word(&buf_ptr));
837 }
838 } else if (strcmp(firstword, "map") == 0) {
839 if (currmap->max_mappings == currmap->n_mappings) {
840 currmap->max_mappings = currmap->max_mappings * 2 + 1;
841 currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
842 }
843 currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr));
844 currmap->n_mappings++;
845 } else {
846 bb_error_msg("misplaced option \"%s\"", buf);
847 return NULL;
848 }
849#endif
850 break;
851 case NONE:
852 default:
853 bb_error_msg("misplaced option \"%s\"", buf);
854 return NULL;
855 }
856 }
857 free(buf);
858 }
859 if (ferror(f) != 0) {
860 /* ferror does NOT set errno! */
861 bb_error_msg_and_die("%s: I/O error", filename);
862 }
863 fclose(f);
864
865 return defn;
866}
867
868static char *setlocalenv(const char *format, const char *name, const char *value)
869{
870 char *result;
871 char *here;
872 char *there;
873
874 result = xasprintf(format, name, value);
875
876 for (here = there = result; *there != '=' && *there; there++) {
877 if (*there == '-')
878 *there = '_';
879 if (isalpha(*there))
880 *there = toupper(*there);
881
882 if (isalnum(*there) || *there == '_') {
883 *here = *there;
884 here++;
885 }
886 }
887 memmove(here, there, strlen(there) + 1);
888
889 return result;
890}
891
892static void set_environ(struct interface_defn_t *iface, const char *mode)
893{
894 char **environend;
895 int i;
896 const int n_env_entries = iface->n_options + 5;
897 char **ppch;
898
899 if (my_environ != NULL) {
900 for (ppch = my_environ; *ppch; ppch++) {
901 free(*ppch);
902 *ppch = NULL;
903 }
904 free(my_environ);
905 }
906 my_environ = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
907 environend = my_environ;
908
909 for (i = 0; i < iface->n_options; i++) {
910 if (strcmp(iface->option[i].name, "up") == 0
911 || strcmp(iface->option[i].name, "down") == 0
912 || strcmp(iface->option[i].name, "pre-up") == 0
913 || strcmp(iface->option[i].name, "post-down") == 0
914 ) {
915 continue;
916 }
917 *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
918 }
919
920 *(environend++) = setlocalenv("%s=%s", "IFACE", iface->iface);
921 *(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
922 *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
923 *(environend++) = setlocalenv("%s=%s", "MODE", mode);
924 *(environend++) = setlocalenv("%s=%s", "PATH", startup_PATH);
925}
926
927static int doit(char *str)
928{
929 if (option_mask32 & (OPT_no_act|OPT_verbose)) {
930 puts(str);
931 }
932 if (!(option_mask32 & OPT_no_act)) {
933 pid_t child;
934 int status;
935
936 fflush(NULL);
937 child = fork();
938 switch (child) {
939 case -1: /* failure */
940 return 0;
941 case 0: /* child */
942 execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ);
943 exit(127);
944 }
945 waitpid(child, &status, 0);
946 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
947 return 0;
948 }
949 }
950 return 1;
951}
952
953static int execute_all(struct interface_defn_t *ifd, const char *opt)
954{
955 int i;
956 char *buf;
957 for (i = 0; i < ifd->n_options; i++) {
958 if (strcmp(ifd->option[i].name, opt) == 0) {
959 if (!doit(ifd->option[i].value)) {
960 return 0;
961 }
962 }
963 }
964
965 buf = xasprintf("run-parts /etc/network/if-%s.d", opt);
966 /* heh, we don't bother free'ing it */
967 return doit(buf);
968}
969
970static int check(char *str)
971{
972 return str != NULL;
973}
974
975static int iface_up(struct interface_defn_t *iface)
976{
977 if (!iface->method->up(iface, check)) return -1;
978 set_environ(iface, "start");
979 if (!execute_all(iface, "pre-up")) return 0;
980 if (!iface->method->up(iface, doit)) return 0;
981 if (!execute_all(iface, "up")) return 0;
982 return 1;
983}
984
985static int iface_down(struct interface_defn_t *iface)
986{
987 if (!iface->method->down(iface,check)) return -1;
988 set_environ(iface, "stop");
989 if (!execute_all(iface, "down")) return 0;
990 if (!iface->method->down(iface, doit)) return 0;
991 if (!execute_all(iface, "post-down")) return 0;
992 return 1;
993}
994
995#if ENABLE_FEATURE_IFUPDOWN_MAPPING
996static int popen2(FILE **in, FILE **out, char *command, ...)
997{
998 va_list ap;
999 char *argv[11] = { command };
1000 int argc;
1001 int infd[2], outfd[2];
1002 pid_t pid;
1003
1004 argc = 1;
1005 va_start(ap, command);
1006 while ((argc < 10) && (argv[argc] = va_arg(ap, char *))) {
1007 argc++;
1008 }
1009 argv[argc] = NULL; /* make sure */
1010 va_end(ap);
1011
1012 if (pipe(infd) != 0) {
1013 return 0;
1014 }
1015
1016 if (pipe(outfd) != 0) {
1017 close(infd[0]);
1018 close(infd[1]);
1019 return 0;
1020 }
1021
1022 fflush(NULL);
1023 switch (pid = fork()) {
1024 case -1: /* failure */
1025 close(infd[0]);
1026 close(infd[1]);
1027 close(outfd[0]);
1028 close(outfd[1]);
1029 return 0;
1030 case 0: /* child */
1031 dup2(infd[0], 0);
1032 dup2(outfd[1], 1);
1033 close(infd[0]);
1034 close(infd[1]);
1035 close(outfd[0]);
1036 close(outfd[1]);
1037 BB_EXECVP(command, argv);
1038 exit(127);
1039 default: /* parent */
1040 *in = fdopen(infd[1], "w");
1041 *out = fdopen(outfd[0], "r");
1042 close(infd[0]);
1043 close(outfd[1]);
1044 return pid;
1045 }
1046 /* unreached */
1047}
1048
1049static char *run_mapping(char *physical, struct mapping_defn_t * map)
1050{
1051 FILE *in, *out;
1052 int i, status;
1053 pid_t pid;
1054
1055 char *logical = xstrdup(physical);
1056
1057 /* Run the mapping script. */
1058 pid = popen2(&in, &out, map->script, physical, NULL);
1059
1060 /* popen2() returns 0 on failure. */
1061 if (pid == 0)
1062 return logical;
1063
1064 /* Write mappings to stdin of mapping script. */
1065 for (i = 0; i < map->n_mappings; i++) {
1066 fprintf(in, "%s\n", map->mapping[i]);
1067 }
1068 fclose(in);
1069 waitpid(pid, &status, 0);
1070
1071 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1072 /* If the mapping script exited successfully, try to
1073 * grab a line of output and use that as the name of the
1074 * logical interface. */
1075 char *new_logical = xmalloc(MAX_INTERFACE_LENGTH);
1076
1077 if (fgets(new_logical, MAX_INTERFACE_LENGTH, out)) {
1078 /* If we are able to read a line of output from the script,
1079 * remove any trailing whitespace and use this value
1080 * as the name of the logical interface. */
1081 char *pch = new_logical + strlen(new_logical) - 1;
1082
1083 while (pch >= new_logical && isspace(*pch))
1084 *(pch--) = '\0';
1085
1086 free(logical);
1087 logical = new_logical;
1088 } else {
1089 /* If we are UNABLE to read a line of output, discard our
1090 * freshly allocated memory. */
1091 free(new_logical);
1092 }
1093 }
1094
1095 fclose(out);
1096
1097 return logical;
1098}
1099#endif /* FEATURE_IFUPDOWN_MAPPING */
1100
1101static llist_t *find_iface_state(llist_t *state_list, const char *iface)
1102{
1103 unsigned short iface_len = strlen(iface);
1104 llist_t *search = state_list;
1105
1106 while (search) {
1107 if ((strncmp(search->data, iface, iface_len) == 0)
1108 && (search->data[iface_len] == '=')) {
1109 return search;
1110 }
1111 search = search->link;
1112 }
1113 return NULL;
1114}
1115
1116/* read the previous state from the state file */
1117static llist_t *read_iface_state(void)
1118{
1119 llist_t *state_list = NULL;
1120 FILE *state_fp = fopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "r");
1121
1122 if (state_fp) {
1123 char *start, *end_ptr;
1124 while ((start = xmalloc_fgets(state_fp)) != NULL) {
1125 /* We should only need to check for a single character */
1126 end_ptr = start + strcspn(start, " \t\n");
1127 *end_ptr = '\0';
1128 llist_add_to(&state_list, start);
1129 }
1130 fclose(state_fp);
1131 }
1132 return state_list;
1133}
1134
1135
1136int ifupdown_main(int argc, char **argv);
1137int ifupdown_main(int argc, char **argv)
1138{
1139 int (*cmds)(struct interface_defn_t *) = NULL;
1140 struct interfaces_file_t *defn;
1141 llist_t *target_list = NULL;
1142 const char *interfaces = "/etc/network/interfaces";
1143 bool any_failures = 0;
1144
1145 cmds = iface_down;
1146 if (applet_name[2] == 'u') {
1147 /* ifup command */
1148 cmds = iface_up;
1149 }
1150
1151 getopt32(argv, OPTION_STR, &interfaces);
1152 if (argc - optind > 0) {
1153 if (DO_ALL) bb_show_usage();
1154 } else {
1155 if (!DO_ALL) bb_show_usage();
1156 }
1157
1158 debug_noise("reading %s file:\n", interfaces);
1159 defn = read_interfaces(interfaces);
1160 debug_noise("\ndone reading %s\n\n", interfaces);
1161
1162 if (!defn) {
1163 return EXIT_FAILURE;
1164 }
1165
1166 startup_PATH = getenv("PATH");
1167 if (!startup_PATH) startup_PATH = "";
1168
1169 /* Create a list of interfaces to work on */
1170 if (DO_ALL) {
1171 target_list = defn->autointerfaces;
1172 } else {
1173 llist_add_to_end(&target_list, argv[optind]);
1174 }
1175
1176 /* Update the interfaces */
1177 while (target_list) {
1178 llist_t *iface_list;
1179 struct interface_defn_t *currif;
1180 char *iface;
1181 char *liface;
1182 char *pch;
1183 bool okay = 0;
1184 unsigned cmds_ret;
1185
1186 iface = xstrdup(target_list->data);
1187 target_list = target_list->link;
1188
1189 pch = strchr(iface, '=');
1190 if (pch) {
1191 *pch = '\0';
1192 liface = xstrdup(pch + 1);
1193 } else {
1194 liface = xstrdup(iface);
1195 }
1196
1197 if (!FORCE) {
1198 llist_t *state_list = read_iface_state();
1199 const llist_t *iface_state = find_iface_state(state_list, iface);
1200
1201 if (cmds == iface_up) {
1202 /* ifup */
1203 if (iface_state) {
1204 bb_error_msg("interface %s already configured", iface);
1205 continue;
1206 }
1207 } else {
1208 /* ifdown */
1209 if (!iface_state) {
1210 bb_error_msg("interface %s not configured", iface);
1211 continue;
1212 }
1213 }
1214 llist_free(state_list, free);
1215 }
1216
1217#if ENABLE_FEATURE_IFUPDOWN_MAPPING
1218 if ((cmds == iface_up) && !NO_MAPPINGS) {
1219 struct mapping_defn_t *currmap;
1220
1221 for (currmap = defn->mappings; currmap; currmap = currmap->next) {
1222 int i;
1223 for (i = 0; i < currmap->n_matches; i++) {
1224 if (fnmatch(currmap->match[i], liface, 0) != 0)
1225 continue;
1226 if (VERBOSE) {
1227 printf("Running mapping script %s on %s\n", currmap->script, liface);
1228 }
1229 liface = run_mapping(iface, currmap);
1230 break;
1231 }
1232 }
1233 }
1234#endif
1235
1236 iface_list = defn->ifaces;
1237 while (iface_list) {
1238 currif = (struct interface_defn_t *) iface_list->data;
1239 if (strcmp(liface, currif->iface) == 0) {
1240 char *oldiface = currif->iface;
1241
1242 okay = 1;
1243 currif->iface = iface;
1244
1245 debug_noise("\nConfiguring interface %s (%s)\n", liface, currif->address_family->name);
1246
1247 /* Call the cmds function pointer, does either iface_up() or iface_down() */
1248 cmds_ret = cmds(currif);
1249 if (cmds_ret == -1) {
1250 bb_error_msg("don't seem to have all the variables for %s/%s",
1251 liface, currif->address_family->name);
1252 any_failures = 1;
1253 } else if (cmds_ret == 0) {
1254 any_failures = 1;
1255 }
1256
1257 currif->iface = oldiface;
1258 }
1259 iface_list = iface_list->link;
1260 }
1261 if (VERBOSE) {
1262 puts("");
1263 }
1264
1265 if (!okay && !FORCE) {
1266 bb_error_msg("ignoring unknown interface %s", liface);
1267 any_failures = 1;
1268 } else if (!NO_ACT) {
1269 /* update the state file */
1270 FILE *state_fp;
1271 llist_t *state;
1272 llist_t *state_list = read_iface_state();
1273 llist_t *iface_state = find_iface_state(state_list, iface);
1274
1275 if (cmds == iface_up) {
1276 char * const newiface = xasprintf("%s=%s", iface, liface);
1277 if (iface_state == NULL) {
1278 llist_add_to_end(&state_list, newiface);
1279 } else {
1280 free(iface_state->data);
1281 iface_state->data = newiface;
1282 }
1283 } else {
1284 /* Remove an interface from state_list */
1285 llist_unlink(&state_list, iface_state);
1286 free(llist_pop(&iface_state));
1287 }
1288
1289 /* Actually write the new state */
1290 state_fp = xfopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "w");
1291 state = state_list;
1292 while (state) {
1293 if (state->data) {
1294 fprintf(state_fp, "%s\n", state->data);
1295 }
1296 state = state->link;
1297 }
1298 fclose(state_fp);
1299 llist_free(state_list, free);
1300 }
1301 }
1302
1303 return any_failures;
1304}
Note: See TracBrowser for help on using the repository browser.