1 /* vi: set sw=4 ts=4: */
4 * Copyright (c) 2002 Glenn McGrath
5 * Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org>
7 * Based on ifupdown v 0.6.4 by Anthony Towns
8 * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au>
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
17 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
20 //usage:#define ifup_trivial_usage
21 //usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..."
22 //usage:#define ifup_full_usage "\n\n"
23 //usage: " -a De/configure all interfaces automatically"
24 //usage: "\n -i FILE Use FILE for interface definitions"
25 //usage: "\n -n Print out what would happen, but don't do it"
26 //usage: IF_FEATURE_IFUPDOWN_MAPPING(
27 //usage: "\n (note: doesn't disable mappings)"
28 //usage: "\n -m Don't run any mappings"
30 //usage: "\n -v Print out what would happen before doing it"
31 //usage: "\n -f Force de/configuration"
33 //usage:#define ifdown_trivial_usage
34 //usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..."
35 //usage:#define ifdown_full_usage "\n\n"
36 //usage: " -a De/configure all interfaces automatically"
37 //usage: "\n -i FILE Use FILE for interface definitions"
38 //usage: "\n -n Print out what would happen, but don't do it"
39 //usage: IF_FEATURE_IFUPDOWN_MAPPING(
40 //usage: "\n (note: doesn't disable mappings)"
41 //usage: "\n -m Don't run any mappings"
43 //usage: "\n -v Print out what would happen before doing it"
44 //usage: "\n -f Force de/configuration"
47 /* After libbb.h, since it needs sys/types.h on some systems */
48 #include <sys/utsname.h>
51 #define MAX_OPT_DEPTH 10
52 #define EUNBALBRACK 10001
53 #define EUNDEFVAR 10002
54 #define EUNBALPER 10000
56 #if ENABLE_FEATURE_IFUPDOWN_MAPPING
57 #define MAX_INTERFACE_LENGTH 10
60 #define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS
62 #define debug_noise(args...) /*fprintf(stderr, args)*/
64 /* Forward declaration */
65 struct interface_defn_t
;
67 typedef int execfn(char *command
);
71 int (*up
)(struct interface_defn_t
*ifd
, execfn
*e
) FAST_FUNC
;
72 int (*down
)(struct interface_defn_t
*ifd
, execfn
*e
) FAST_FUNC
;
75 struct address_family_t
{
78 const struct method_t
*method
;
81 struct mapping_defn_t
{
82 struct mapping_defn_t
*next
;
99 struct interface_defn_t
{
100 const struct address_family_t
*address_family
;
101 const struct method_t
*method
;
105 struct variable_t
*option
;
108 struct interfaces_file_t
{
109 llist_t
*autointerfaces
;
111 struct mapping_defn_t
*mappings
;
115 #define OPTION_STR "anvf" IF_FEATURE_IFUPDOWN_MAPPING("m") "i:"
121 OPT_no_mappings
= 0x10,
123 #define DO_ALL (option_mask32 & OPT_do_all)
124 #define NO_ACT (option_mask32 & OPT_no_act)
125 #define VERBOSE (option_mask32 & OPT_verbose)
126 #define FORCE (option_mask32 & OPT_force)
127 #define NO_MAPPINGS (option_mask32 & OPT_no_mappings)
132 const char *startup_PATH
;
135 #define G (*(struct globals*)&bb_common_bufsiz1)
136 #define INIT_G() do { } while (0)
139 static const char keywords_up_down
[] ALIGN1
=
147 #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
149 static void addstr(char **bufp
, const char *str
, size_t str_length
)
151 /* xasprintf trick will be smaller, but we are often
152 * called with str_length == 1 - don't want to have
153 * THAT much of malloc/freeing! */
155 int len
= (buf
? strlen(buf
) : 0);
157 buf
= xrealloc(buf
, len
+ str_length
);
158 /* copies at most str_length-1 chars! */
159 safe_strncpy(buf
+ len
, str
, str_length
);
163 static int strncmpz(const char *l
, const char *r
, size_t llen
)
165 int i
= strncmp(l
, r
, llen
);
168 return - (unsigned char)r
[llen
];
172 static char *get_var(const char *id
, size_t idlen
, struct interface_defn_t
*ifd
)
176 if (strncmpz(id
, "iface", idlen
) == 0) {
177 // ubuntu's ifup doesn't do this:
178 //static char *label_buf;
181 //label_buf = xstrdup(ifd->iface);
182 // Remove virtual iface suffix
183 //result = strchrnul(label_buf, ':');
189 if (strncmpz(id
, "label", idlen
) == 0) {
192 for (i
= 0; i
< ifd
->n_options
; i
++) {
193 if (strncmpz(id
, ifd
->option
[i
].name
, idlen
) == 0) {
194 return ifd
->option
[i
].value
;
200 # if ENABLE_FEATURE_IFUPDOWN_IP
201 static int count_netmask_bits(const char *dotted_quad
)
204 // unsigned a, b, c, d;
205 // /* Found a netmask... Check if it is dotted quad */
206 // if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
208 // if ((a|b|c|d) >> 8)
209 // return -1; /* one of numbers is >= 256 */
210 // d |= (a << 24) | (b << 16) | (c << 8); /* IP */
211 // d = ~d; /* 11110000 -> 00001111 */
213 /* Shorter version */
218 if (inet_aton(dotted_quad
, &ip
) == 0)
219 return -1; /* malformed dotted IP */
220 d
= ntohl(ip
.s_addr
); /* IP in host order */
221 d
= ~d
; /* 11110000 -> 00001111 */
222 if (d
& (d
+1)) /* check that it is in 00001111 form */
223 return -1; /* no it is not */
233 static char *parse(const char *command
, struct interface_defn_t
*ifd
)
235 size_t old_pos
[MAX_OPT_DEPTH
] = { 0 };
236 int okay
[MAX_OPT_DEPTH
] = { 1 };
243 addstr(&result
, command
, 1);
248 addstr(&result
, command
+ 1, 1);
251 addstr(&result
, command
, 1);
256 if (command
[1] == '[' && opt_depth
< MAX_OPT_DEPTH
) {
257 old_pos
[opt_depth
] = result
? strlen(result
) : 0;
262 addstr(&result
, "[", 1);
267 if (command
[1] == ']' && opt_depth
> 1) {
269 if (!okay
[opt_depth
]) {
270 result
[old_pos
[opt_depth
]] = '\0';
274 addstr(&result
, "]", 1);
284 nextpercent
= strchr(command
, '%');
291 varvalue
= get_var(command
, nextpercent
- command
, ifd
);
294 # if ENABLE_FEATURE_IFUPDOWN_IP
295 /* "hwaddress <class> <address>":
296 * unlike ifconfig, ip doesnt want <class>
297 * (usually "ether" keyword). Skip it. */
298 if (strncmp(command
, "hwaddress", 9) == 0) {
299 varvalue
= skip_whitespace(skip_non_whitespace(varvalue
));
302 addstr(&result
, varvalue
, strlen(varvalue
));
304 # if ENABLE_FEATURE_IFUPDOWN_IP
305 /* Sigh... Add a special case for 'ip' to convert from
306 * dotted quad to bit count style netmasks. */
307 if (strncmp(command
, "bnmask", 6) == 0) {
309 varvalue
= get_var("netmask", 7, ifd
);
311 res
= count_netmask_bits(varvalue
);
313 const char *argument
= utoa(res
);
314 addstr(&result
, argument
, strlen(argument
));
315 command
= nextpercent
+ 1;
321 okay
[opt_depth
- 1] = 0;
324 command
= nextpercent
+ 1;
345 /* execute() returns 1 for success and 0 for failure */
346 static int execute(const char *command
, struct interface_defn_t
*ifd
, execfn
*exec
)
351 out
= parse(command
, ifd
);
356 /* out == "": parsed ok but not all needed variables known, skip */
357 ret
= out
[0] ? (*exec
)(out
) : 1;
366 #endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */
369 #if ENABLE_FEATURE_IFUPDOWN_IPV6
371 static int FAST_FUNC
loopback_up6(struct interface_defn_t
*ifd
, execfn
*exec
)
373 # if ENABLE_FEATURE_IFUPDOWN_IP
375 result
= execute("ip addr add ::1 dev %iface%", ifd
, exec
);
376 result
+= execute("ip link set %iface% up", ifd
, exec
);
377 return ((result
== 2) ? 2 : 0);
379 return execute("ifconfig %iface% add ::1", ifd
, exec
);
383 static int FAST_FUNC
loopback_down6(struct interface_defn_t
*ifd
, execfn
*exec
)
385 # if ENABLE_FEATURE_IFUPDOWN_IP
386 return execute("ip link set %iface% down", ifd
, exec
);
388 return execute("ifconfig %iface% del ::1", ifd
, exec
);
392 static int FAST_FUNC
manual_up_down6(struct interface_defn_t
*ifd UNUSED_PARAM
, execfn
*exec UNUSED_PARAM
)
397 static int FAST_FUNC
static_up6(struct interface_defn_t
*ifd
, execfn
*exec
)
400 # if ENABLE_FEATURE_IFUPDOWN_IP
401 result
= execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd
, exec
);
402 result
+= execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd
, exec
);
403 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
404 result
+= execute("[[ip route add ::/0 via %gateway%]][[ prio %metric%]]", ifd
, exec
);
406 result
= execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd
, exec
);
407 result
+= execute("ifconfig %iface% add %address%/%netmask%", ifd
, exec
);
408 result
+= execute("[[route -A inet6 add ::/0 gw %gateway%[[ metric %metric%]]]]", ifd
, exec
);
410 return ((result
== 3) ? 3 : 0);
413 static int FAST_FUNC
static_down6(struct interface_defn_t
*ifd
, execfn
*exec
)
415 # if ENABLE_FEATURE_IFUPDOWN_IP
416 return execute("ip link set %iface% down", ifd
, exec
);
418 return execute("ifconfig %iface% down", ifd
, exec
);
422 # if ENABLE_FEATURE_IFUPDOWN_IP
423 static int FAST_FUNC
v4tunnel_up(struct interface_defn_t
*ifd
, execfn
*exec
)
426 result
= execute("ip tunnel add %iface% mode sit remote "
427 "%endpoint%[[ local %local%]][[ ttl %ttl%]]", ifd
, exec
);
428 result
+= execute("ip link set %iface% up", ifd
, exec
);
429 result
+= execute("ip addr add %address%/%netmask% dev %iface%", ifd
, exec
);
430 result
+= execute("[[ip route add ::/0 via %gateway%]]", ifd
, exec
);
431 return ((result
== 4) ? 4 : 0);
434 static int FAST_FUNC
v4tunnel_down(struct interface_defn_t
* ifd
, execfn
* exec
)
436 return execute("ip tunnel del %iface%", ifd
, exec
);
440 static const struct method_t methods6
[] = {
441 # if ENABLE_FEATURE_IFUPDOWN_IP
442 { "v4tunnel" , v4tunnel_up
, v4tunnel_down
, },
444 { "static" , static_up6
, static_down6
, },
445 { "manual" , manual_up_down6
, manual_up_down6
, },
446 { "loopback" , loopback_up6
, loopback_down6
, },
449 static const struct address_family_t addr_inet6
= {
451 ARRAY_SIZE(methods6
),
455 #endif /* FEATURE_IFUPDOWN_IPV6 */
458 #if ENABLE_FEATURE_IFUPDOWN_IPV4
460 static int FAST_FUNC
loopback_up(struct interface_defn_t
*ifd
, execfn
*exec
)
462 # if ENABLE_FEATURE_IFUPDOWN_IP
464 result
= execute("ip addr add 127.0.0.1/8 dev %iface%", ifd
, exec
);
465 result
+= execute("ip link set %iface% up", ifd
, exec
);
466 return ((result
== 2) ? 2 : 0);
468 return execute("ifconfig %iface% 127.0.0.1 up", ifd
, exec
);
472 static int FAST_FUNC
loopback_down(struct interface_defn_t
*ifd
, execfn
*exec
)
474 # if ENABLE_FEATURE_IFUPDOWN_IP
476 result
= execute("ip addr flush dev %iface%", ifd
, exec
);
477 result
+= execute("ip link set %iface% down", ifd
, exec
);
478 return ((result
== 2) ? 2 : 0);
480 return execute("ifconfig %iface% 127.0.0.1 down", ifd
, exec
);
484 static int FAST_FUNC
static_up(struct interface_defn_t
*ifd
, execfn
*exec
)
487 # if ENABLE_FEATURE_IFUPDOWN_IP
488 result
= execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
489 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd
, exec
);
490 result
+= execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd
, exec
);
491 result
+= execute("[[ip route add default via %gateway% dev %iface%[[ prio %metric%]]]]", ifd
, exec
);
492 return ((result
== 3) ? 3 : 0);
494 /* ifconfig said to set iface up before it processes hw %hwaddress%,
495 * which then of course fails. Thus we run two separate ifconfig */
496 result
= execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
498 result
+= execute("ifconfig %iface% %address% netmask %netmask%"
499 "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
501 result
+= execute("[[route add default gw %gateway%[[ metric %metric%]] %iface%]]", ifd
, exec
);
502 return ((result
== 3) ? 3 : 0);
506 static int FAST_FUNC
static_down(struct interface_defn_t
*ifd
, execfn
*exec
)
509 # if ENABLE_FEATURE_IFUPDOWN_IP
510 result
= execute("ip addr flush dev %iface%", ifd
, exec
);
511 result
+= execute("ip link set %iface% down", ifd
, exec
);
513 /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */
514 /* Bringing the interface down deletes the routes in itself.
515 Otherwise this fails if we reference 'gateway' when using this from dhcp_down */
517 result
+= execute("ifconfig %iface% down", ifd
, exec
);
519 return ((result
== 2) ? 2 : 0);
522 # if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
523 struct dhcp_client_t
{
525 const char *startcmd
;
529 static const struct dhcp_client_t ext_dhcp_clients
[] = {
531 "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %client%]][[ -l %leasetime%]] %iface%",
535 "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",
536 "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",
539 "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",
540 "pump -i %iface% -k",
543 "udhcpc " UDHCPC_CMD_OPTIONS
" -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %client%]]"
544 "[[ -s %script%]][[ %udhcpc_opts%]]",
545 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
548 # endif /* FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
550 # if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
551 static int FAST_FUNC
dhcp_up(struct interface_defn_t
*ifd
, execfn
*exec
)
554 # if ENABLE_FEATURE_IFUPDOWN_IP
555 /* ip doesn't up iface when it configures it (unlike ifconfig) */
556 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd
, exec
))
559 /* needed if we have hwaddress on dhcp iface */
560 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd
, exec
))
563 for (i
= 0; i
< ARRAY_SIZE(ext_dhcp_clients
); i
++) {
564 if (exists_execable(ext_dhcp_clients
[i
].name
))
565 return execute(ext_dhcp_clients
[i
].startcmd
, ifd
, exec
);
567 bb_error_msg("no dhcp clients found");
571 static int FAST_FUNC
dhcp_up(struct interface_defn_t
*ifd
, execfn
*exec
)
573 # if ENABLE_FEATURE_IFUPDOWN_IP
574 /* ip doesn't up iface when it configures it (unlike ifconfig) */
575 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd
, exec
))
578 /* needed if we have hwaddress on dhcp iface */
579 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd
, exec
))
582 return execute("udhcpc " UDHCPC_CMD_OPTIONS
" -p /var/run/udhcpc.%iface%.pid "
583 "-i %iface%[[ -H %hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]",
587 static int FAST_FUNC
dhcp_up(struct interface_defn_t
*ifd UNUSED_PARAM
,
588 execfn
*exec UNUSED_PARAM
)
590 return 0; /* no dhcp support */
594 # if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
595 static int FAST_FUNC
dhcp_down(struct interface_defn_t
*ifd
, execfn
*exec
)
600 for (i
= 0; i
< ARRAY_SIZE(ext_dhcp_clients
); i
++) {
601 if (exists_execable(ext_dhcp_clients
[i
].name
)) {
602 result
= execute(ext_dhcp_clients
[i
].stopcmd
, ifd
, exec
);
609 bb_error_msg("warning: no dhcp clients found and stopped");
611 /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
612 and it may come back up because udhcpc is still shutting down */
614 result
+= static_down(ifd
, exec
);
615 return ((result
== 3) ? 3 : 0);
618 static int FAST_FUNC
dhcp_down(struct interface_defn_t
*ifd
, execfn
*exec
)
622 "test -f /var/run/udhcpc.%iface%.pid && "
623 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
625 /* Also bring the hardware interface down since
626 killing the dhcp client alone doesn't do it.
627 This enables consecutive ifup->ifdown->ifup */
628 /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
629 and it may come back up because udhcpc is still shutting down */
631 result
+= static_down(ifd
, exec
);
632 return ((result
== 3) ? 3 : 0);
635 static int FAST_FUNC
dhcp_down(struct interface_defn_t
*ifd UNUSED_PARAM
,
636 execfn
*exec UNUSED_PARAM
)
638 return 0; /* no dhcp support */
642 static int FAST_FUNC
manual_up_down(struct interface_defn_t
*ifd UNUSED_PARAM
, execfn
*exec UNUSED_PARAM
)
647 static int FAST_FUNC
bootp_up(struct interface_defn_t
*ifd
, execfn
*exec
)
649 return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
650 "[[ --server %server%]][[ --hwaddr %hwaddr%]]"
651 " --returniffail --serverbcast", ifd
, exec
);
654 static int FAST_FUNC
ppp_up(struct interface_defn_t
*ifd
, execfn
*exec
)
656 return execute("pon[[ %provider%]]", ifd
, exec
);
659 static int FAST_FUNC
ppp_down(struct interface_defn_t
*ifd
, execfn
*exec
)
661 return execute("poff[[ %provider%]]", ifd
, exec
);
664 static int FAST_FUNC
wvdial_up(struct interface_defn_t
*ifd
, execfn
*exec
)
666 return execute("start-stop-daemon --start -x wvdial "
667 "-p /var/run/wvdial.%iface% -b -m --[[ %provider%]]", ifd
, exec
);
670 static int FAST_FUNC
wvdial_down(struct interface_defn_t
*ifd
, execfn
*exec
)
672 return execute("start-stop-daemon --stop -x wvdial "
673 "-p /var/run/wvdial.%iface% -s 2", ifd
, exec
);
676 static const struct method_t methods
[] = {
677 { "manual" , manual_up_down
, manual_up_down
, },
678 { "wvdial" , wvdial_up
, wvdial_down
, },
679 { "ppp" , ppp_up
, ppp_down
, },
680 { "static" , static_up
, static_down
, },
681 { "bootp" , bootp_up
, static_down
, },
682 { "dhcp" , dhcp_up
, dhcp_down
, },
683 { "loopback", loopback_up
, loopback_down
, },
686 static const struct address_family_t addr_inet
= {
692 #endif /* FEATURE_IFUPDOWN_IPV4 */
695 /* Returns pointer to the next word, or NULL.
696 * In 1st case, advances *buf to the word after this one.
698 static char *next_word(char **buf
)
703 /* Skip over leading whitespace */
704 word
= skip_whitespace(*buf
);
710 /* Find the length of this word (can't be 0) */
711 length
= strcspn(word
, " \t\n");
713 /* Unless we are already at NUL, store NUL and advance */
714 if (word
[length
] != '\0')
715 word
[length
++] = '\0';
717 *buf
= skip_whitespace(word
+ length
);
722 static const struct address_family_t
*get_address_family(const struct address_family_t
*const af
[], char *name
)
729 for (i
= 0; af
[i
]; i
++) {
730 if (strcmp(af
[i
]->name
, name
) == 0) {
737 static const struct method_t
*get_method(const struct address_family_t
*af
, char *name
)
743 /* TODO: use index_in_str_array() */
744 for (i
= 0; i
< af
->n_methods
; i
++) {
745 if (strcmp(af
->method
[i
].name
, name
) == 0) {
746 return &af
->method
[i
];
752 static struct interfaces_file_t
*read_interfaces(const char *filename
)
754 /* Let's try to be compatible.
756 * "man 5 interfaces" says:
757 * Lines starting with "#" are ignored. Note that end-of-line
758 * comments are NOT supported, comments must be on a line of their own.
759 * A line may be extended across multiple lines by making
760 * the last character a backslash.
762 * Seen elsewhere in example config file:
763 * A first non-blank "#" character makes the rest of the line
764 * be ignored. Blank lines are ignored. Lines may be indented freely.
765 * A "\" character at the very end of the line indicates the next line
766 * should be treated as a continuation of the current one.
768 #if ENABLE_FEATURE_IFUPDOWN_MAPPING
769 struct mapping_defn_t
*currmap
= NULL
;
771 struct interface_defn_t
*currif
= NULL
;
772 struct interfaces_file_t
*defn
;
777 enum { NONE
, IFACE
, MAPPING
} currently_processing
= NONE
;
779 defn
= xzalloc(sizeof(*defn
));
780 f
= xfopen_for_read(filename
);
782 while ((buf
= xmalloc_fgetline(f
)) != NULL
) {
784 /* Trailing "\" concatenates lines */
786 while ((p
= last_char_is(buf
, '\\')) != NULL
) {
788 rest_of_line
= xmalloc_fgetline(f
);
791 p
= xasprintf("%s%s", buf
, rest_of_line
);
798 first_word
= next_word(&rest_of_line
);
799 if (!first_word
|| *first_word
== '#') {
801 continue; /* blank/comment line */
804 if (strcmp(first_word
, "mapping") == 0) {
805 #if ENABLE_FEATURE_IFUPDOWN_MAPPING
806 currmap
= xzalloc(sizeof(*currmap
));
808 while ((first_word
= next_word(&rest_of_line
)) != NULL
) {
809 currmap
->match
= xrealloc_vector(currmap
->match
, 4, currmap
->n_matches
);
810 currmap
->match
[currmap
->n_matches
++] = xstrdup(first_word
);
812 /*currmap->n_mappings = 0;*/
813 /*currmap->mapping = NULL;*/
814 /*currmap->script = NULL;*/
816 struct mapping_defn_t
**where
= &defn
->mappings
;
817 while (*where
!= NULL
) {
818 where
= &(*where
)->next
;
821 /*currmap->next = NULL;*/
823 debug_noise("Added mapping\n");
825 currently_processing
= MAPPING
;
826 } else if (strcmp(first_word
, "iface") == 0) {
827 static const struct address_family_t
*const addr_fams
[] = {
828 #if ENABLE_FEATURE_IFUPDOWN_IPV4
831 #if ENABLE_FEATURE_IFUPDOWN_IPV6
837 char *address_family_name
;
841 currif
= xzalloc(sizeof(*currif
));
842 iface_name
= next_word(&rest_of_line
);
843 address_family_name
= next_word(&rest_of_line
);
844 method_name
= next_word(&rest_of_line
);
846 if (method_name
== NULL
)
847 bb_error_msg_and_die("too few parameters for line \"%s\"", buf
);
849 /* ship any trailing whitespace */
850 rest_of_line
= skip_whitespace(rest_of_line
);
852 if (rest_of_line
[0] != '\0' /* && rest_of_line[0] != '#' */)
853 bb_error_msg_and_die("too many parameters \"%s\"", buf
);
855 currif
->iface
= xstrdup(iface_name
);
857 currif
->address_family
= get_address_family(addr_fams
, address_family_name
);
858 if (!currif
->address_family
)
859 bb_error_msg_and_die("unknown address type \"%s\"", address_family_name
);
861 currif
->method
= get_method(currif
->address_family
, method_name
);
863 bb_error_msg_and_die("unknown method \"%s\"", method_name
);
865 for (iface_list
= defn
->ifaces
; iface_list
; iface_list
= iface_list
->link
) {
866 struct interface_defn_t
*tmp
= (struct interface_defn_t
*) iface_list
->data
;
867 if ((strcmp(tmp
->iface
, currif
->iface
) == 0)
868 && (tmp
->address_family
== currif
->address_family
)
870 bb_error_msg_and_die("duplicate interface \"%s\"", tmp
->iface
);
873 llist_add_to_end(&(defn
->ifaces
), (char*)currif
);
875 debug_noise("iface %s %s %s\n", currif
->iface
, address_family_name
, method_name
);
876 currently_processing
= IFACE
;
877 } else if (strcmp(first_word
, "auto") == 0) {
878 while ((first_word
= next_word(&rest_of_line
)) != NULL
) {
880 /* Check the interface isnt already listed */
881 if (llist_find_str(defn
->autointerfaces
, first_word
)) {
882 bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf
);
885 /* Add the interface to the list */
886 llist_add_to_end(&(defn
->autointerfaces
), xstrdup(first_word
));
887 debug_noise("\nauto %s\n", first_word
);
889 currently_processing
= NONE
;
891 switch (currently_processing
) {
893 if (rest_of_line
[0] == '\0')
894 bb_error_msg_and_die("option with empty value \"%s\"", buf
);
896 if (strcmp(first_word
, "post-up") == 0)
897 first_word
+= 5; /* "up" */
898 else if (strcmp(first_word
, "pre-down") == 0)
899 first_word
+= 4; /* "down" */
901 /* If not one of "up", "down",... words... */
902 if (index_in_strings(keywords_up_down
, first_word
) < 0) {
904 for (i
= 0; i
< currif
->n_options
; i
++) {
905 if (strcmp(currif
->option
[i
].name
, first_word
) == 0)
906 bb_error_msg_and_die("duplicate option \"%s\"", buf
);
909 debug_noise("\t%s=%s\n", first_word
, rest_of_line
);
910 currif
->option
= xrealloc_vector(currif
->option
, 4, currif
->n_options
);
911 currif
->option
[currif
->n_options
].name
= xstrdup(first_word
);
912 currif
->option
[currif
->n_options
].value
= xstrdup(rest_of_line
);
916 #if ENABLE_FEATURE_IFUPDOWN_MAPPING
917 if (strcmp(first_word
, "script") == 0) {
918 if (currmap
->script
!= NULL
)
919 bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf
);
920 currmap
->script
= xstrdup(next_word(&rest_of_line
));
921 } else if (strcmp(first_word
, "map") == 0) {
922 currmap
->mapping
= xrealloc_vector(currmap
->mapping
, 2, currmap
->n_mappings
);
923 currmap
->mapping
[currmap
->n_mappings
] = xstrdup(next_word(&rest_of_line
));
924 currmap
->n_mappings
++;
926 bb_error_msg_and_die("misplaced option \"%s\"", buf
);
932 bb_error_msg_and_die("misplaced option \"%s\"", buf
);
936 } /* while (fgets) */
938 if (ferror(f
) != 0) {
939 /* ferror does NOT set errno! */
940 bb_error_msg_and_die("%s: I/O error", filename
);
947 static char *setlocalenv(const char *format
, const char *name
, const char *value
)
954 result
= xasprintf(format
, name
, value
);
956 for (dst
= src
= result
; (c
= *src
) != '=' && c
; src
++) {
959 if (c
>= 'a' && c
<= 'z')
961 if (isalnum(c
) || c
== '_')
964 overlapping_strcpy(dst
, src
);
969 static void set_environ(struct interface_defn_t
*iface
, const char *mode
, const char *opt
)
974 if (G
.my_environ
!= NULL
) {
975 for (pp
= G
.my_environ
; *pp
; pp
++) {
981 /* note: last element will stay NULL: */
982 G
.my_environ
= xzalloc(sizeof(char *) * (iface
->n_options
+ 7));
985 for (i
= 0; i
< iface
->n_options
; i
++) {
986 if (index_in_strings(keywords_up_down
, iface
->option
[i
].name
) >= 0) {
989 *pp
++ = setlocalenv("IF_%s=%s", iface
->option
[i
].name
, iface
->option
[i
].value
);
992 *pp
++ = setlocalenv("%s=%s", "IFACE", iface
->iface
);
993 *pp
++ = setlocalenv("%s=%s", "ADDRFAM", iface
->address_family
->name
);
994 *pp
++ = setlocalenv("%s=%s", "METHOD", iface
->method
->name
);
995 *pp
++ = setlocalenv("%s=%s", "MODE", mode
);
996 *pp
++ = setlocalenv("%s=%s", "PHASE", opt
);
998 *pp
++ = setlocalenv("%s=%s", "PATH", G
.startup_PATH
);
1001 static int doit(char *str
)
1003 if (option_mask32
& (OPT_no_act
|OPT_verbose
)) {
1006 if (!(option_mask32
& OPT_no_act
)) {
1012 if (child
< 0) /* failure */
1014 if (child
== 0) { /* child */
1015 execle(G
.shell
, G
.shell
, "-c", str
, (char *) NULL
, G
.my_environ
);
1018 safe_waitpid(child
, &status
, 0);
1019 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0) {
1026 static int execute_all(struct interface_defn_t
*ifd
, const char *opt
)
1030 for (i
= 0; i
< ifd
->n_options
; i
++) {
1031 if (strcmp(ifd
->option
[i
].name
, opt
) == 0) {
1032 if (!doit(ifd
->option
[i
].value
)) {
1038 buf
= xasprintf("run-parts /etc/network/if-%s.d", opt
);
1039 /* heh, we don't bother free'ing it */
1043 static int check(char *str
)
1048 static int iface_up(struct interface_defn_t
*iface
)
1050 if (!iface
->method
->up(iface
, check
)) return -1;
1051 set_environ(iface
, "start", "pre-up");
1052 if (!execute_all(iface
, "pre-up")) return 0;
1053 if (!iface
->method
->up(iface
, doit
)) return 0;
1054 set_environ(iface
, "start", "post-up");
1055 if (!execute_all(iface
, "up")) return 0;
1059 static int iface_down(struct interface_defn_t
*iface
)
1061 if (!iface
->method
->down(iface
,check
)) return -1;
1062 set_environ(iface
, "stop", "pre-down");
1063 if (!execute_all(iface
, "down")) return 0;
1064 if (!iface
->method
->down(iface
, doit
)) return 0;
1065 set_environ(iface
, "stop", "post-down");
1066 if (!execute_all(iface
, "post-down")) return 0;
1070 #if ENABLE_FEATURE_IFUPDOWN_MAPPING
1071 static int popen2(FILE **in
, FILE **out
, char *command
, char *param
)
1073 char *argv
[3] = { command
, param
, NULL
};
1074 struct fd_pair infd
, outfd
;
1085 /* NB: close _first_, then move fds! */
1088 xmove_fd(infd
.rd
, 0);
1089 xmove_fd(outfd
.wr
, 1);
1090 BB_EXECVP_or_die(argv
);
1095 *in
= xfdopen_for_write(infd
.wr
);
1096 *out
= xfdopen_for_read(outfd
.rd
);
1100 static char *run_mapping(char *physical
, struct mapping_defn_t
*map
)
1106 char *logical
= xstrdup(physical
);
1108 /* Run the mapping script. Never fails. */
1109 pid
= popen2(&in
, &out
, map
->script
, physical
);
1111 /* Write mappings to stdin of mapping script. */
1112 for (i
= 0; i
< map
->n_mappings
; i
++) {
1113 fprintf(in
, "%s\n", map
->mapping
[i
]);
1116 safe_waitpid(pid
, &status
, 0);
1118 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 0) {
1119 /* If the mapping script exited successfully, try to
1120 * grab a line of output and use that as the name of the
1121 * logical interface. */
1122 char *new_logical
= xmalloc_fgetline(out
);
1125 /* If we are able to read a line of output from the script,
1126 * remove any trailing whitespace and use this value
1127 * as the name of the logical interface. */
1128 char *pch
= new_logical
+ strlen(new_logical
) - 1;
1130 while (pch
>= new_logical
&& isspace(*pch
))
1134 logical
= new_logical
;
1142 #endif /* FEATURE_IFUPDOWN_MAPPING */
1144 static llist_t
*find_iface_state(llist_t
*state_list
, const char *iface
)
1146 unsigned iface_len
= strlen(iface
);
1147 llist_t
*search
= state_list
;
1150 if ((strncmp(search
->data
, iface
, iface_len
) == 0)
1151 && (search
->data
[iface_len
] == '=')
1155 search
= search
->link
;
1160 /* read the previous state from the state file */
1161 static llist_t
*read_iface_state(void)
1163 llist_t
*state_list
= NULL
;
1164 FILE *state_fp
= fopen_for_read(CONFIG_IFUPDOWN_IFSTATE_PATH
);
1167 char *start
, *end_ptr
;
1168 while ((start
= xmalloc_fgets(state_fp
)) != NULL
) {
1169 /* We should only need to check for a single character */
1170 end_ptr
= start
+ strcspn(start
, " \t\n");
1172 llist_add_to(&state_list
, start
);
1180 int ifupdown_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
1181 int ifupdown_main(int argc UNUSED_PARAM
, char **argv
)
1183 int (*cmds
)(struct interface_defn_t
*);
1184 struct interfaces_file_t
*defn
;
1185 llist_t
*target_list
= NULL
;
1186 const char *interfaces
= "/etc/network/interfaces";
1187 bool any_failures
= 0;
1191 G
.startup_PATH
= getenv("PATH");
1192 G
.shell
= xstrdup(get_shell_name());
1195 if (applet_name
[2] == 'u') {
1200 getopt32(argv
, OPTION_STR
, &interfaces
);
1203 if (DO_ALL
) bb_show_usage();
1205 if (!DO_ALL
) bb_show_usage();
1208 debug_noise("reading %s file:\n", interfaces
);
1209 defn
= read_interfaces(interfaces
);
1210 debug_noise("\ndone reading %s\n\n", interfaces
);
1212 /* Create a list of interfaces to work on */
1214 target_list
= defn
->autointerfaces
;
1216 llist_add_to_end(&target_list
, argv
[0]);
1219 /* Update the interfaces */
1220 while (target_list
) {
1221 llist_t
*iface_list
;
1222 struct interface_defn_t
*currif
;
1229 iface
= xstrdup(target_list
->data
);
1230 target_list
= target_list
->link
;
1232 pch
= strchr(iface
, '=');
1235 liface
= xstrdup(pch
+ 1);
1237 liface
= xstrdup(iface
);
1241 llist_t
*state_list
= read_iface_state();
1242 const llist_t
*iface_state
= find_iface_state(state_list
, iface
);
1244 if (cmds
== iface_up
) {
1247 bb_error_msg("interface %s already configured", iface
);
1253 bb_error_msg("interface %s not configured", iface
);
1257 llist_free(state_list
, free
);
1260 #if ENABLE_FEATURE_IFUPDOWN_MAPPING
1261 if ((cmds
== iface_up
) && !NO_MAPPINGS
) {
1262 struct mapping_defn_t
*currmap
;
1264 for (currmap
= defn
->mappings
; currmap
; currmap
= currmap
->next
) {
1266 for (i
= 0; i
< currmap
->n_matches
; i
++) {
1267 if (fnmatch(currmap
->match
[i
], liface
, 0) != 0)
1270 printf("Running mapping script %s on %s\n", currmap
->script
, liface
);
1272 liface
= run_mapping(iface
, currmap
);
1279 iface_list
= defn
->ifaces
;
1280 while (iface_list
) {
1281 currif
= (struct interface_defn_t
*) iface_list
->data
;
1282 if (strcmp(liface
, currif
->iface
) == 0) {
1283 char *oldiface
= currif
->iface
;
1286 currif
->iface
= iface
;
1288 debug_noise("\nConfiguring interface %s (%s)\n", liface
, currif
->address_family
->name
);
1290 /* Call the cmds function pointer, does either iface_up() or iface_down() */
1291 cmds_ret
= cmds(currif
);
1292 if (cmds_ret
== -1) {
1293 bb_error_msg("don't seem to have all the variables for %s/%s",
1294 liface
, currif
->address_family
->name
);
1296 } else if (cmds_ret
== 0) {
1300 currif
->iface
= oldiface
;
1302 iface_list
= iface_list
->link
;
1308 if (!okay
&& !FORCE
) {
1309 bb_error_msg("ignoring unknown interface %s", liface
);
1311 } else if (!NO_ACT
) {
1312 /* update the state file */
1315 llist_t
*state_list
= read_iface_state();
1316 llist_t
*iface_state
= find_iface_state(state_list
, iface
);
1318 if (cmds
== iface_up
&& !any_failures
) {
1319 char *newiface
= xasprintf("%s=%s", iface
, liface
);
1321 llist_add_to_end(&state_list
, newiface
);
1323 free(iface_state
->data
);
1324 iface_state
->data
= newiface
;
1327 /* Remove an interface from state_list */
1328 llist_unlink(&state_list
, iface_state
);
1329 free(llist_pop(&iface_state
));
1332 /* Actually write the new state */
1333 state_fp
= xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH
);
1337 fprintf(state_fp
, "%s\n", state
->data
);
1339 state
= state
->link
;
1342 llist_free(state_list
, free
);
1349 return any_failures
;