3 * Copyright (c) 2002 Glenn McGrath <bug1@optushome.com.au>
5 * Based on ifupdown v 0.6.4 by Anthony Towns
6 * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au>
8 * Changes to upstream version
9 * Remove checks for kernel version, assume kernel version 2.2.0 or better.
10 * Lines in the interfaces file cannot wrap.
11 * To adhere to the FHS, the default state file is /var/run/ifstate.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <sys/utsname.h>
45 #define MAX_OPT_DEPTH 10
46 #define EUNBALBRACK 10001
47 #define EUNDEFVAR 10002
48 #define EUNBALPER 10000
50 typedef struct interface_defn_s interface_defn_t;
52 typedef int (execfn)(char *command);
53 typedef int (command_set)(interface_defn_t *ifd, execfn *e);
55 typedef struct method_s {
61 typedef struct address_family_s {
67 typedef struct mapping_defn_s {
68 struct mapping_defn_s *next;
81 typedef struct variable_s {
86 struct interface_defn_s {
87 struct interface_defn_s *next;
90 address_family_t *address_family;
100 typedef struct interfaces_file_s {
101 llist_t *autointerfaces;
102 interface_defn_t *ifaces;
103 mapping_defn_t *mappings;
106 static char no_act = 0;
107 static char verbose = 0;
108 static char **environ = NULL;
110 static void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t str_length)
112 if (*pos + str_length >= *len) {
115 newbuf = xrealloc(*buf, *len * 2 + str_length + 1);
117 *len = *len * 2 + str_length + 1;
120 while (str_length-- >= 1) {
121 (*buf)[(*pos)++] = *str;
127 static int strncmpz(char *l, char *r, size_t llen)
129 int i = strncmp(l, r, llen);
138 static char *get_var(char *id, size_t idlen, interface_defn_t *ifd)
142 if (strncmpz(id, "iface", idlen) == 0) {
145 for (i = 0; i < ifd->n_options; i++) {
146 if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
147 return (ifd->option[i].value);
155 static char *parse(char *command, interface_defn_t *ifd)
159 size_t pos = 0, len = 0;
160 size_t old_pos[MAX_OPT_DEPTH] = { 0 };
161 int okay[MAX_OPT_DEPTH] = { 1 };
168 addstr(&result, &len, &pos, command, 1);
173 addstr(&result, &len, &pos, command + 1, 1);
176 addstr(&result, &len, &pos, command, 1);
181 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
182 old_pos[opt_depth] = pos;
187 addstr(&result, &len, &pos, "[", 1);
192 if (command[1] == ']' && opt_depth > 1) {
194 if (!okay[opt_depth]) {
195 pos = old_pos[opt_depth];
200 addstr(&result, &len, &pos, "]", 1);
210 nextpercent = strchr(command, '%');
217 varvalue = get_var(command, nextpercent - command, ifd);
220 addstr(&result, &len, &pos, varvalue, xstrlen(varvalue));
222 okay[opt_depth - 1] = 0;
225 command = nextpercent + 1;
246 static int execute(char *command, interface_defn_t *ifd, execfn *exec)
251 out = parse(command, ifd);
262 #ifdef CONFIG_FEATURE_IFUPDOWN_IPX
263 static int static_up_ipx(interface_defn_t *ifd, execfn *exec)
265 if (!execute("ipx_interface add %iface% %frame% %netnum%", ifd, exec)) {
271 static int static_down_ipx(interface_defn_t *ifd, execfn *exec)
273 if (!execute("ipx_interface del %iface% %frame%", ifd, exec)) {
279 static int dynamic_up(interface_defn_t *ifd, execfn *exec)
281 if (!execute("ipx_interface add %iface% %frame%", ifd, exec)) {
287 static int dynamic_down(interface_defn_t *ifd, execfn *exec)
289 if (!execute("ipx_interface del %iface% %frame%", ifd, exec)) {
295 static method_t methods_ipx[] = {
296 { "dynamic", dynamic_up, dynamic_down, },
297 { "static", static_up_ipx, static_down_ipx, },
300 address_family_t addr_ipx = {
302 sizeof(methods_ipx) / sizeof(method_t),
305 #endif /* IFUP_FEATURE_IPX */
307 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
308 static int loopback_up6(interface_defn_t *ifd, execfn *exec)
310 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
311 if (!execute("ip link set %iface% up", ifd, exec))
313 if (!execute("ip addr add ::1 dev %iface%", ifd, exec))
316 if (!execute("ifconfig %iface% add ::1", ifd, exec))
322 static int loopback_down6(interface_defn_t *ifd, execfn *exec)
324 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
325 if (!execute("ip link set %iface% down", ifd, exec))
328 if (!execute("ifconfig %iface% del ::1", ifd, exec))
334 static int static_up6(interface_defn_t *ifd, execfn *exec)
336 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
337 if (!execute("ip link set %iface% up", ifd, exec))
339 if (!execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec))
341 if (!execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec))
344 if (!execute("ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up", ifd, exec)) {
347 if (!execute("ifconfig %iface% add %address%/%netmask%", ifd, exec)) {
350 if (!execute("[[ route -A inet6 add ::/0 gw %gateway% ]]", ifd, exec)) {
357 static int static_down6(interface_defn_t *ifd, execfn *exec)
359 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
360 if (!execute("ip link set %iface% down", ifd, exec))
363 if (!execute("ifconfig %iface% down", ifd, exec)) {
370 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
371 static int v4tunnel_up(interface_defn_t *ifd, execfn *exec)
373 if (!execute("ip tunnel add %iface% mode sit remote %endpoint% [[local %local%]] [[ttl %ttl%]]", ifd, exec)) {
376 if (!execute("ip link set %iface% up", ifd, exec)) {
379 if (!execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec)) {
382 if (!execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec)) {
388 static int v4tunnel_down(interface_defn_t * ifd, execfn * exec)
390 if (!execute("ip tunnel del %iface%", ifd, exec)) {
397 static method_t methods6[] = {
398 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
399 { "v4tunnel", v4tunnel_up, v4tunnel_down, },
401 { "static", static_up6, static_down6, },
402 { "loopback", loopback_up6, loopback_down6, },
405 address_family_t addr_inet6 = {
407 sizeof(methods6) / sizeof(method_t),
410 #endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */
412 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
413 static int loopback_up(interface_defn_t *ifd, execfn *exec)
415 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
416 if (!execute("ip link set %iface% up", ifd, exec))
418 if (!execute("ip addr add 127.0.0.1 dev %iface%", ifd, exec))
421 if (!execute("ifconfig %iface% 127.0.0.1 up", ifd, exec)) {
428 static int loopback_down(interface_defn_t *ifd, execfn *exec)
430 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
431 if (!execute("ip -f inet addr flush dev %iface%", ifd, exec))
433 if (!execute("ip link set %iface% down", ifd, exec))
436 if (!execute("ifconfig %iface% 127.0.0.1 down", ifd, exec)) {
443 static int static_up(interface_defn_t *ifd, execfn *exec)
445 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
446 if (!execute("ip link set %iface% up", ifd, exec))
448 if (!execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec))
450 if (!execute("[[ ip route add default via %gateway% dev %iface% ]]", ifd, exec))
453 if (!execute("ifconfig %iface% %address% netmask %netmask% [[broadcast %broadcast%]] [[pointopoint %pointopoint%]] [[media %media%]] [[mtu %mtu%]] [[hw %hwaddress%]] up",
457 if (!execute("[[ route add default gw %gateway% %iface% ]]", ifd, exec)) {
464 static int static_down(interface_defn_t *ifd, execfn *exec)
466 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
467 if (!execute("[[ ip route del default via %gateway% dev %iface% ]]", ifd, exec))
469 if (!execute("ip -f inet addr flush dev %iface%", ifd, exec))
471 if (!execute("ip link set %iface% down", ifd, exec))
474 if (!execute("[[ route del default gw %gateway% %iface% ]]", ifd, exec)) {
477 if (!execute("ifconfig %iface% down", ifd, exec)) {
484 static int execable(char *program)
487 if (0 == stat(program, &buf)) {
488 if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) {
495 static int dhcp_up(interface_defn_t *ifd, execfn *exec)
497 if (execable("/sbin/dhclient")) {
498 if (!execute("dhclient -pf /var/run/dhclient.%iface%.pid %iface%", ifd, exec)) {
501 } else if (execable("/sbin/pump")) {
502 if (!execute("pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]]", ifd, exec)) {
505 } else if (execable("/sbin/udhcpc")) {
506 if (!execute("udhcpc -n -p /var/run/udhcpc.%iface%.pid -i %iface% [[-H %hostname%]] [[-c %clientid%]]", ifd, exec)) {
509 } else if (execable("/sbin/dhcpcd")) {
510 if (!execute("dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] [[-l %leasetime%]] %iface%", ifd, exec)) {
517 static int dhcp_down(interface_defn_t *ifd, execfn *exec)
519 if (execable("/sbin/dhclient")) {
520 if (!execute("kill -9 `cat /var/run/udhcpc.%iface%.pid`", ifd, exec)) {
523 } else if (execable("/sbin/pump")) {
524 if (!execute("pump -i %iface% -k", ifd, exec)) {
527 } else if (execable("/sbin/udhcpc")) {
528 if (!execute("kill -9 `cat /var/run/udhcpc.%iface%.pid`", ifd, exec)) {
531 } else if (execable("/sbin/dhcpcd")) {
532 if (!execute("dhcpcd -k %iface%", ifd, exec)) {
536 if (!execute("ifconfig %iface% down", ifd, exec)) {
542 static int bootp_up(interface_defn_t *ifd, execfn *exec)
544 if (!execute("bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] [[--hwaddr %hwaddr%]] --returniffail --serverbcast", ifd, exec)) {
550 static int bootp_down(interface_defn_t *ifd, execfn *exec)
552 if (!execute("ifconfig down %iface%", ifd, exec)) {
558 static int ppp_up(interface_defn_t *ifd, execfn *exec)
560 if (!execute("pon [[%provider%]]", ifd, exec)) {
566 static int ppp_down(interface_defn_t *ifd, execfn *exec)
568 if (!execute("poff [[%provider%]]", ifd, exec)) {
574 static int wvdial_up(interface_defn_t *ifd, execfn *exec)
576 if (!execute("/sbin/start-stop-daemon --start -x /usr/bin/wvdial -p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]", ifd, exec)) {
582 static int wvdial_down(interface_defn_t *ifd, execfn *exec)
584 if (!execute ("/sbin/start-stop-daemon --stop -x /usr/bin/wvdial -p /var/run/wvdial.%iface% -s 2", ifd, exec)) {
590 static method_t methods[] = {
591 { "wvdial", wvdial_up, wvdial_down, },
592 { "ppp", ppp_up, ppp_down, },
593 { "static", static_up, static_down, },
594 { "bootp", bootp_up, bootp_down, },
595 { "dhcp", dhcp_up, dhcp_down, },
596 { "loopback", loopback_up, loopback_down, },
599 address_family_t addr_inet = {
601 sizeof(methods) / sizeof(method_t),
605 #endif /* ifdef CONFIG_FEATURE_IFUPDOWN_IPV4 */
607 static char *next_word(char *buf, char *word, int maxlen)
614 while (!isspace(*buf) && *buf) {
623 while (isspace(*buf) && *buf) {
630 static address_family_t *get_address_family(address_family_t *af[], char *name)
634 for (i = 0; af[i]; i++) {
635 if (strcmp(af[i]->name, name) == 0) {
642 static method_t *get_method(address_family_t *af, char *name)
646 for (i = 0; i < af->n_methods; i++) {
647 if (strcmp(af->method[i].name, name) == 0) {
648 return &af->method[i];
654 static int duplicate_if(interface_defn_t *ifa, interface_defn_t *ifb)
656 if (strcmp(ifa->iface, ifb->iface) != 0) {
659 if (ifa->address_family != ifb->address_family) {
665 static const llist_t *find_list_string(const llist_t *list, const char *string)
668 if (strcmp(list->data, string) == 0) {
676 static interfaces_file_t *read_interfaces(char *filename)
678 interface_defn_t *currif = NULL;
679 interfaces_file_t *defn;
680 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
681 mapping_defn_t *currmap = NULL;
689 enum { NONE, IFACE, MAPPING } currently_processing = NONE;
691 defn = xmalloc(sizeof(interfaces_file_t));
692 // defn->max_autointerfaces = defn->n_autointerfaces = 0;
693 defn->autointerfaces = NULL;
694 defn->mappings = NULL;
696 f = fopen(filename, "r");
701 while ((buf = get_line_from_file(f)) != NULL) {
707 end = last_char_is(buf, '\n');
711 while ((end = last_char_is(buf, ' ')) != NULL) {
714 rest = next_word(buf, firstword, 80);
716 continue; /* blank line */
719 if (strcmp(firstword, "mapping") == 0) {
720 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
721 currmap = xmalloc(sizeof(mapping_defn_t));
722 currmap->max_matches = 0;
723 currmap->n_matches = 0;
724 currmap->match = NULL;
726 while ((rest = next_word(rest, firstword, 80))) {
727 if (currmap->max_matches == currmap->n_matches) {
728 currmap->max_matches = currmap->max_matches * 2 + 1;
729 currmap->match = xrealloc(currmap->match, sizeof(currmap->match) * currmap->max_matches);
732 currmap->match[currmap->n_matches++] = xstrdup(firstword);
734 currmap->max_mappings = 0;
735 currmap->n_mappings = 0;
736 currmap->mapping = NULL;
737 currmap->script = NULL;
739 mapping_defn_t **where = &defn->mappings;
740 while (*where != NULL) {
741 where = &(*where)->next;
744 currmap->next = NULL;
747 currently_processing = MAPPING;
748 } else if (strcmp(firstword, "iface") == 0) {
751 char address_family_name[80];
752 char method_name[80];
753 address_family_t *addr_fams[] = {
754 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
757 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
760 #ifdef CONFIG_FEATURE_IFUPDOWN_IPX
766 currif = xmalloc(sizeof(interface_defn_t));
768 rest = next_word(rest, iface_name, 80);
769 rest = next_word(rest, address_family_name, 80);
770 rest = next_word(rest, method_name, 80);
773 error_msg("too few parameters for line \"%s\"", buf);
777 if (rest[0] != '\0') {
778 error_msg("too many parameters \"%s\"", buf);
782 currif->iface = xstrdup(iface_name);
784 currif->address_family = get_address_family(addr_fams, address_family_name);
785 if (!currif->address_family) {
786 error_msg("unknown address type \"%s\"", buf);
790 currif->method = get_method(currif->address_family, method_name);
791 if (!currif->method) {
792 error_msg("unknown method \"%s\"", buf);
796 currif->automatic = 1;
797 currif->max_options = 0;
798 currif->n_options = 0;
799 currif->option = NULL;
803 interface_defn_t **where = &defn->ifaces;
805 while (*where != NULL) {
806 if (duplicate_if(*where, currif)) {
807 error_msg("duplicate interface \"%s\"", buf);
810 where = &(*where)->next;
817 currently_processing = IFACE;
818 } else if (strcmp(firstword, "auto") == 0) {
819 while ((rest = next_word(rest, firstword, 80))) {
821 /* Check the interface isnt already listed */
822 if (find_list_string(defn->autointerfaces, firstword)) {
823 perror_msg_and_die("interface declared auto twice \"%s\"", buf);
826 /* Add the interface to the list */
827 defn->autointerfaces = llist_add_to(defn->autointerfaces, strdup(firstword));
829 currently_processing = NONE;
831 switch (currently_processing) {
836 if (xstrlen(rest) == 0) {
837 error_msg("option with empty value \"%s\"", buf);
841 if (strcmp(firstword, "up") != 0
842 && strcmp(firstword, "down") != 0
843 && strcmp(firstword, "pre-up") != 0
844 && strcmp(firstword, "post-down") != 0) {
845 for (i = 0; i < currif->n_options; i++) {
846 if (strcmp(currif->option[i].name, firstword) == 0) {
847 error_msg("duplicate option \"%s\"", buf);
853 if (currif->n_options >= currif->max_options) {
856 currif->max_options = currif->max_options + 10;
857 opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
858 currif->option = opt;
860 currif->option[currif->n_options].name = xstrdup(firstword);
861 currif->option[currif->n_options].value = xstrdup(rest);
862 if (!currif->option[currif->n_options].name) {
866 if (!currif->option[currif->n_options].value) {
873 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
874 if (strcmp(firstword, "script") == 0) {
875 if (currmap->script != NULL) {
876 error_msg("duplicate script in mapping \"%s\"", buf);
879 currmap->script = xstrdup(rest);
881 } else if (strcmp(firstword, "map") == 0) {
882 if (currmap->max_mappings == currmap->n_mappings) {
883 currmap->max_mappings = currmap->max_mappings * 2 + 1;
884 currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
886 currmap->mapping[currmap->n_mappings] = xstrdup(rest);
887 currmap->n_mappings++;
889 error_msg("misplaced option \"%s\"", buf);
896 error_msg("misplaced option \"%s\"", buf);
901 if (ferror(f) != 0) {
902 perror_msg("%s", filename);
910 static int check(char *str)
912 return (str != NULL);
915 static char *setlocalenv(char *format, char *name, char *value)
921 result = xmalloc(xstrlen(format) + xstrlen(name) + xstrlen(value) + 1);
923 sprintf(result, format, name, value);
925 for (here = there = result; *there != '=' && *there; there++) {
929 *there = toupper(*there);
931 if (isalnum(*there) || *there == '_') {
936 memmove(here, there, xstrlen(there) + 1);
941 static void set_environ(interface_defn_t *iface, char *mode)
945 const int n_env_entries = iface->n_options + 5;
948 if (environ != NULL) {
949 for (ppch = environ; *ppch; ppch++) {
956 environ = xmalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
957 environend = environ;
960 for (i = 0; i < iface->n_options; i++) {
961 if (strcmp(iface->option[i].name, "up") == 0
962 || strcmp(iface->option[i].name, "down") == 0
963 || strcmp(iface->option[i].name, "pre-up") == 0
964 || strcmp(iface->option[i].name, "post-down") == 0) {
967 *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
971 *(environend++) = setlocalenv("%s=%s", "IFACE", iface->iface);
973 *(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
975 *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
977 *(environend++) = setlocalenv("%s=%s", "MODE", mode);
979 *(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
983 static int doit(char *str)
985 if (verbose || no_act) {
986 error_msg("%s", str);
993 switch (child = fork()) {
994 case -1: /* failure */
997 execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
1000 waitpid(child, &status, 0);
1001 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
1008 static int execute_all(interface_defn_t *ifd, execfn *exec, const char *opt)
1013 for (i = 0; i < ifd->n_options; i++) {
1014 if (strcmp(ifd->option[i].name, opt) == 0) {
1015 if (!(*exec) (ifd->option[i].value)) {
1021 buf = xmalloc(xstrlen(opt) + 19);
1022 sprintf(buf, "/etc/network/if-%s.d", opt);
1028 static int iface_up(interface_defn_t *iface)
1030 if (!iface->method->up(iface, check)) {
1034 set_environ(iface, "start");
1035 if (!execute_all(iface, doit, "pre-up")) {
1038 if (!iface->method->up(iface, doit)) {
1041 if (!execute_all(iface, doit, "up")) {
1048 static int iface_down(interface_defn_t *iface)
1050 if (!iface->method->down(iface, check)) {
1053 set_environ(iface, "stop");
1054 if (!execute_all(iface, doit, "down")) {
1057 if (!iface->method->down(iface, doit)) {
1060 if (!execute_all(iface, doit, "post-down")) {
1066 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
1067 static int popen2(FILE **in, FILE **out, char *command, ...)
1070 char *argv[11] = { command };
1072 int infd[2], outfd[2];
1076 va_start(ap, command);
1077 while ((argc < 10) && (argv[argc] = va_arg(ap, char *))) {
1080 argv[argc] = NULL; /* make sure */
1083 if (pipe(infd) != 0) {
1087 if (pipe(outfd) != 0) {
1094 switch (pid = fork()) {
1095 case -1: /* failure */
1108 execvp(command, argv);
1110 default: /* parent */
1111 *in = fdopen(infd[1], "w");
1112 *out = fdopen(outfd[0], "r");
1120 static int run_mapping(char *physical, char *logical, int len, mapping_defn_t * map)
1127 pid = popen2(&in, &out, map->script, physical, NULL);
1131 for (i = 0; i < map->n_mappings; i++) {
1132 fprintf(in, "%s\n", map->mapping[i]);
1135 waitpid(pid, &status, 0);
1136 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1137 if (fgets(logical, len, out)) {
1138 char *pch = logical + xstrlen(logical) - 1;
1140 while (pch >= logical && isspace(*pch))
1148 #endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */
1150 static llist_t *find_iface_state(llist_t *state_list, const char *iface)
1152 unsigned short iface_len = xstrlen(iface);
1153 llist_t *search = state_list;
1156 if ((strncmp(search->data, iface, iface_len) == 0) &&
1157 (search->data[iface_len] == '=')) {
1160 search = search->link;
1165 extern int ifupdown_main(int argc, char **argv)
1167 int (*cmds) (interface_defn_t *) = NULL;
1168 interfaces_file_t *defn;
1169 FILE *state_fp = NULL;
1170 llist_t *state_list = NULL;
1171 llist_t *target_list = NULL;
1172 char *interfaces = "/etc/network/interfaces";
1173 const char *statefile = "/var/run/ifstate";
1175 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
1176 int run_mappings = 1;
1182 if (applet_name[2] == 'u') {
1186 /* ifdown command */
1190 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
1191 while ((i = getopt(argc, argv, "i:hvnamf")) != -1) {
1193 while ((i = getopt(argc, argv, "i:hvnaf")) != -1) {
1196 case 'i': /* interfaces */
1197 interfaces = xstrdup(optarg);
1199 case 'v': /* verbose */
1205 case 'n': /* no-act */
1208 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
1209 case 'm': /* no-mappings */
1213 case 'f': /* force */
1222 if (argc - optind > 0) {
1232 defn = read_interfaces(interfaces);
1234 error_msg_and_die("couldn't read interfaces file \"%s\"", interfaces);
1238 state_fp = fopen(statefile, "r");
1240 state_fp = xfopen(statefile, "a+");
1243 /* Read the previous state from the state file */
1244 if (state_fp != NULL) {
1246 while ((start = get_line_from_file(state_fp)) != NULL) {
1248 /* We should only need to check for a single character */
1249 end_ptr = start + strcspn(start, " \t\n");
1251 state_list = llist_add_to(state_list, start);
1255 /* Create a list of interfaces to work on */
1257 if (cmds == iface_up) {
1258 target_list = defn->autointerfaces;
1259 } else if (cmds == iface_down) {
1260 const llist_t *list = state_list;
1262 target_list = llist_add_to(target_list, strdup(list->data));
1267 target_list = llist_add_to(target_list, argv[optind]);
1271 /* Update the interfaces */
1272 while (target_list) {
1273 interface_defn_t *currif;
1279 iface = strdup(target_list->data);
1280 target_list = target_list->link;
1282 pch = strchr(iface, '=');
1285 liface = strdup(pch + 1);
1287 liface = strdup(iface);
1291 const llist_t *iface_state = find_iface_state(state_list, iface);
1293 if (cmds == iface_up) {
1296 error_msg("interface %s already configured", iface);
1301 if (iface_state == NULL) {
1302 error_msg("interface %s not configured", iface);
1305 pch = strchr(iface_state->data, '=');
1306 liface = strdup(pch + 1);
1310 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
1311 if ((cmds == iface_up) && run_mappings) {
1312 mapping_defn_t *currmap;
1314 for (currmap = defn->mappings; currmap; currmap = currmap->next) {
1316 for (i = 0; i < currmap->n_matches; i++) {
1317 if (fnmatch(currmap->match[i], liface, 0) != 0)
1320 error_msg("Running mapping script %s on %s", currmap->script, liface);
1322 run_mapping(iface, liface, sizeof(liface), currmap);
1329 for (currif = defn->ifaces; currif; currif = currif->next) {
1330 if (strcmp(liface, currif->iface) == 0) {
1331 char *oldiface = currif->iface;
1334 currif->iface = iface;
1337 error_msg("Configuring interface %s=%s (%s)", iface, liface, currif->address_family->name);
1340 /* Call the cmds function pointer, does either iface_up() or iface_down() */
1341 if (cmds(currif) == -1) {
1343 ("Don't seem to be have all the variables for %s/%s.\n",
1344 liface, currif->address_family->name);
1347 currif->iface = oldiface;
1351 if (!okay && !force) {
1352 error_msg("Ignoring unknown interface %s=%s.", iface, liface);
1354 llist_t *iface_state = find_iface_state(state_list, iface);
1356 if (cmds == iface_up) {
1357 char *newiface = xmalloc(xstrlen(iface) + 1 + xstrlen(liface) + 1);
1358 sprintf(newiface, "%s=%s", iface, liface);
1359 if (iface_state == NULL) {
1360 state_list = llist_add_to(state_list, newiface);
1362 free(iface_state->data);
1363 iface_state->data = newiface;
1365 } else if (cmds == iface_down) {
1366 /* Remove an interface from the linked list */
1368 /* This needs to be done better */
1369 free(iface_state->data);
1370 free(iface_state->link);
1371 if (iface_state->link) {
1372 iface_state->data = iface_state->link->data;
1373 iface_state->link = iface_state->link->link;
1375 iface_state->data = NULL;
1376 iface_state->link = NULL;
1383 /* Actually write the new state */
1384 if (state_fp != NULL && !no_act) {
1385 if (ftruncate(fileno(state_fp), 0) < 0) {
1386 error_msg_and_die("failed to truncate statefile %s: %s", statefile, strerror(errno));
1391 while (state_list) {
1392 if (state_list->data) {
1393 fputs(state_list->data, state_fp);
1394 fputc('\n', state_fp);
1396 state_list = state_list->link;
1402 if (state_fp != NULL) {