diff options
| -rw-r--r-- | networking/ifupdown.c | 207 |
1 files changed, 104 insertions, 103 deletions
diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 3e18df19e..37185327b 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c | |||
| @@ -1,12 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * ifupdown for busybox | 2 | * ifupdown for busybox |
| 3 | * Based on ifupdown by Anthony Towns | 3 | * Copyright (c) 2002 Glenn McGrath <bug1@optushome.com.au> |
| 4 | * | ||
| 5 | * Based on ifupdown v 0.6.4 by Anthony Towns | ||
| 4 | * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au> | 6 | * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au> |
| 5 | * | 7 | * |
| 6 | * Changes to upstream version | 8 | * Changes to upstream version |
| 7 | * Remove checks for kernel version, assume kernel version 2.2.0 or better | 9 | * Remove checks for kernel version, assume kernel version 2.2.0 or better. |
| 8 | * Lines in the interfaces file cannot wrap. | 10 | * Lines in the interfaces file cannot wrap. |
| 9 | * The default state file is moved to /var/run/ifstate | 11 | * To adhere to the FHS, the default state file is /var/run/ifstate. |
| 10 | * | 12 | * |
| 11 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
| @@ -39,10 +41,11 @@ | |||
| 39 | #include <unistd.h> | 41 | #include <unistd.h> |
| 40 | 42 | ||
| 41 | #include "libbb.h" | 43 | #include "libbb.h" |
| 42 | //#include "busybox.h" | ||
| 43 | //#include "config.h" | ||
| 44 | 44 | ||
| 45 | #define IFUPDOWN_VERSION "0.6.4" | 45 | #define MAX_OPT_DEPTH 10 |
| 46 | #define EUNBALBRACK 10001 | ||
| 47 | #define EUNDEFVAR 10002 | ||
| 48 | #define EUNBALPER 10000 | ||
| 46 | 49 | ||
| 47 | typedef struct interface_defn_s interface_defn_t; | 50 | typedef struct interface_defn_s interface_defn_t; |
| 48 | 51 | ||
| @@ -95,22 +98,13 @@ struct interface_defn_s { | |||
| 95 | }; | 98 | }; |
| 96 | 99 | ||
| 97 | typedef struct interfaces_file_s { | 100 | typedef struct interfaces_file_s { |
| 98 | int max_autointerfaces; | 101 | llist_t *autointerfaces; |
| 99 | int n_autointerfaces; | ||
| 100 | char **autointerfaces; | ||
| 101 | |||
| 102 | interface_defn_t *ifaces; | 102 | interface_defn_t *ifaces; |
| 103 | mapping_defn_t *mappings; | 103 | mapping_defn_t *mappings; |
| 104 | } interfaces_file_t; | 104 | } interfaces_file_t; |
| 105 | 105 | ||
| 106 | #define MAX_OPT_DEPTH 10 | 106 | static char no_act = 0; |
| 107 | #define EUNBALBRACK 10001 | 107 | static char verbose = 0; |
| 108 | #define EUNDEFVAR 10002 | ||
| 109 | #define MAX_VARNAME 32 | ||
| 110 | #define EUNBALPER 10000 | ||
| 111 | |||
| 112 | static int no_act = 0; | ||
| 113 | static int verbose = 0; | ||
| 114 | static char **environ = NULL; | 108 | static char **environ = NULL; |
| 115 | 109 | ||
| 116 | static void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t str_length) | 110 | static void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t str_length) |
| @@ -608,6 +602,17 @@ static int duplicate_if(interface_defn_t *ifa, interface_defn_t *ifb) | |||
| 608 | return(1); | 602 | return(1); |
| 609 | } | 603 | } |
| 610 | 604 | ||
| 605 | static const llist_t *find_list_string(const llist_t *list, const char *string) | ||
| 606 | { | ||
| 607 | while (list) { | ||
| 608 | if (strcmp(list->data, string) == 0) { | ||
| 609 | return(list); | ||
| 610 | } | ||
| 611 | list = list->link; | ||
| 612 | } | ||
| 613 | return(NULL); | ||
| 614 | } | ||
| 615 | |||
| 611 | static interfaces_file_t *read_interfaces(char *filename) | 616 | static interfaces_file_t *read_interfaces(char *filename) |
| 612 | { | 617 | { |
| 613 | interface_defn_t *currif = NULL; | 618 | interface_defn_t *currif = NULL; |
| @@ -624,7 +629,7 @@ static interfaces_file_t *read_interfaces(char *filename) | |||
| 624 | enum { NONE, IFACE, MAPPING } currently_processing = NONE; | 629 | enum { NONE, IFACE, MAPPING } currently_processing = NONE; |
| 625 | 630 | ||
| 626 | defn = xmalloc(sizeof(interfaces_file_t)); | 631 | defn = xmalloc(sizeof(interfaces_file_t)); |
| 627 | defn->max_autointerfaces = defn->n_autointerfaces = 0; | 632 | // defn->max_autointerfaces = defn->n_autointerfaces = 0; |
| 628 | defn->autointerfaces = NULL; | 633 | defn->autointerfaces = NULL; |
| 629 | defn->mappings = NULL; | 634 | defn->mappings = NULL; |
| 630 | defn->ifaces = NULL; | 635 | defn->ifaces = NULL; |
| @@ -752,26 +757,14 @@ static interfaces_file_t *read_interfaces(char *filename) | |||
| 752 | currently_processing = IFACE; | 757 | currently_processing = IFACE; |
| 753 | } else if (strcmp(firstword, "auto") == 0) { | 758 | } else if (strcmp(firstword, "auto") == 0) { |
| 754 | while ((rest = next_word(rest, firstword, 80))) { | 759 | while ((rest = next_word(rest, firstword, 80))) { |
| 755 | int i; | ||
| 756 | |||
| 757 | for (i = 0; i < defn->n_autointerfaces; i++) { | ||
| 758 | if (strcmp(firstword, defn->autointerfaces[i]) == 0) { | ||
| 759 | perror_msg("interface declared auto twice \"%s\"", buf); | ||
| 760 | return NULL; | ||
| 761 | } | ||
| 762 | } | ||
| 763 | |||
| 764 | if (defn->n_autointerfaces == defn->max_autointerfaces) { | ||
| 765 | char **tmp; | ||
| 766 | 760 | ||
| 767 | defn->max_autointerfaces *= 2; | 761 | /* Check the interface isnt already listed */ |
| 768 | defn->max_autointerfaces++; | 762 | if (find_list_string(defn->autointerfaces, firstword)) { |
| 769 | tmp = xrealloc(defn->autointerfaces, sizeof(*tmp) * defn->max_autointerfaces); | 763 | perror_msg_and_die("interface declared auto twice \"%s\"", buf); |
| 770 | defn->autointerfaces = tmp; | ||
| 771 | } | 764 | } |
| 772 | 765 | ||
| 773 | defn->autointerfaces[defn->n_autointerfaces] = xstrdup(firstword); | 766 | /* Add the interface to the list */ |
| 774 | defn->n_autointerfaces++; | 767 | defn->autointerfaces = llist_add_to(defn->autointerfaces, strdup(firstword)); |
| 775 | } | 768 | } |
| 776 | currently_processing = NONE; | 769 | currently_processing = NONE; |
| 777 | } else { | 770 | } else { |
| @@ -1095,29 +1088,19 @@ static int run_mapping(char *physical, char *logical, int len, mapping_defn_t * | |||
| 1095 | } | 1088 | } |
| 1096 | #endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */ | 1089 | #endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */ |
| 1097 | 1090 | ||
| 1098 | static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) | 1091 | static llist_t *find_iface_state(llist_t *state_list, const char *iface) |
| 1099 | { | 1092 | { |
| 1100 | int i; | 1093 | unsigned short iface_len = xstrlen(iface); |
| 1094 | llist_t *search = state_list; | ||
| 1101 | 1095 | ||
| 1102 | for (i = 0; i < n_ifaces; i++) { | 1096 | while (search) { |
| 1103 | if (strncmp(iface, ifaces[i], xstrlen(iface)) == 0) { | 1097 | if ((strncmp(search->data, iface, iface_len) == 0) && |
| 1104 | if (ifaces[i][xstrlen(iface)] == '=') { | 1098 | (search->data[iface_len] == '=')) { |
| 1105 | return i; | 1099 | return(search); |
| 1106 | } | ||
| 1107 | } | 1100 | } |
| 1101 | search = search->link; | ||
| 1108 | } | 1102 | } |
| 1109 | 1103 | return(NULL); | |
| 1110 | return(-1); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, char *new_iface) | ||
| 1114 | { | ||
| 1115 | if (*max_ifaces == *n_ifaces) { | ||
| 1116 | *max_ifaces = (*max_ifaces * 2) + 1; | ||
| 1117 | *ifaces = xrealloc(*ifaces, sizeof(**ifaces) * *max_ifaces); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | (*ifaces)[(*n_ifaces)++] = new_iface; | ||
| 1121 | } | 1104 | } |
| 1122 | 1105 | ||
| 1123 | extern int ifupdown_main(int argc, char **argv) | 1106 | extern int ifupdown_main(int argc, char **argv) |
| @@ -1125,19 +1108,16 @@ extern int ifupdown_main(int argc, char **argv) | |||
| 1125 | int (*cmds) (interface_defn_t *) = NULL; | 1108 | int (*cmds) (interface_defn_t *) = NULL; |
| 1126 | interfaces_file_t *defn; | 1109 | interfaces_file_t *defn; |
| 1127 | FILE *state_fp = NULL; | 1110 | FILE *state_fp = NULL; |
| 1128 | char **target_iface = NULL; | 1111 | llist_t *state_list = NULL; |
| 1129 | char **state = NULL; /* list of iface=liface */ | 1112 | llist_t *target_list = NULL; |
| 1130 | char *interfaces = "/etc/network/interfaces"; | 1113 | char *interfaces = "/etc/network/interfaces"; |
| 1131 | char *statefile = "/var/run/ifstate"; | 1114 | const char *statefile = "/var/run/ifstate"; |
| 1132 | 1115 | ||
| 1133 | #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING | 1116 | #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING |
| 1134 | int run_mappings = 1; | 1117 | int run_mappings = 1; |
| 1135 | #endif | 1118 | #endif |
| 1136 | int do_all = 0; | 1119 | int do_all = 0; |
| 1137 | int force = 0; | 1120 | int force = 0; |
| 1138 | int n_target_ifaces = 0; | ||
| 1139 | int n_state = 0; | ||
| 1140 | int max_state = 0; | ||
| 1141 | int i; | 1121 | int i; |
| 1142 | 1122 | ||
| 1143 | if (applet_name[2] == 'u') { | 1123 | if (applet_name[2] == 'u') { |
| @@ -1195,11 +1175,13 @@ extern int ifupdown_main(int argc, char **argv) | |||
| 1195 | error_msg_and_die("couldn't read interfaces file \"%s\"", interfaces); | 1175 | error_msg_and_die("couldn't read interfaces file \"%s\"", interfaces); |
| 1196 | } | 1176 | } |
| 1197 | 1177 | ||
| 1198 | state_fp = fopen(statefile, no_act ? "r" : "a+"); | 1178 | if (no_act) { |
| 1199 | if (state_fp == NULL && !no_act) { | 1179 | state_fp = fopen(statefile, "r"); |
| 1200 | perror_msg_and_die("failed to open statefile %s", statefile); | 1180 | } else { |
| 1181 | state_fp = xfopen(statefile, "a+"); | ||
| 1201 | } | 1182 | } |
| 1202 | 1183 | ||
| 1184 | /* Read the previous state from the state file */ | ||
| 1203 | if (state_fp != NULL) { | 1185 | if (state_fp != NULL) { |
| 1204 | char *start; | 1186 | char *start; |
| 1205 | while ((start = get_line_from_file(state_fp)) != NULL) { | 1187 | while ((start = get_line_from_file(state_fp)) != NULL) { |
| @@ -1207,61 +1189,65 @@ extern int ifupdown_main(int argc, char **argv) | |||
| 1207 | /* We should only need to check for a single character */ | 1189 | /* We should only need to check for a single character */ |
| 1208 | end_ptr = start + strcspn(start, " \t\n"); | 1190 | end_ptr = start + strcspn(start, " \t\n"); |
| 1209 | *end_ptr = '\0'; | 1191 | *end_ptr = '\0'; |
| 1210 | add_to_state(&state, &n_state, &max_state, start); | 1192 | state_list = llist_add_to(state_list, start); |
| 1211 | } | 1193 | } |
| 1212 | } | 1194 | } |
| 1213 | 1195 | ||
| 1196 | /* Create a list of interfaces to work on */ | ||
| 1214 | if (do_all) { | 1197 | if (do_all) { |
| 1215 | if (cmds == iface_up) { | 1198 | if (cmds == iface_up) { |
| 1216 | target_iface = defn->autointerfaces; | 1199 | target_list = defn->autointerfaces; |
| 1217 | n_target_ifaces = defn->n_autointerfaces; | ||
| 1218 | } else if (cmds == iface_down) { | 1200 | } else if (cmds == iface_down) { |
| 1219 | target_iface = state; | 1201 | const llist_t *list = state_list; |
| 1220 | n_target_ifaces = n_state; | 1202 | while (list) { |
| 1203 | target_list = llist_add_to(target_list, strdup(list->data)); | ||
| 1204 | list = list->link; | ||
| 1205 | } | ||
| 1221 | } | 1206 | } |
| 1222 | } else { | 1207 | } else { |
| 1223 | target_iface = argv + optind; | 1208 | target_list = llist_add_to(target_list, argv[optind]); |
| 1224 | n_target_ifaces = argc - optind; | ||
| 1225 | } | 1209 | } |
| 1226 | 1210 | ||
| 1227 | 1211 | ||
| 1228 | for (i = 0; i < n_target_ifaces; i++) { | 1212 | /* Update the interfaces */ |
| 1213 | while (target_list) { | ||
| 1229 | interface_defn_t *currif; | 1214 | interface_defn_t *currif; |
| 1230 | char iface[80]; | 1215 | char *iface; |
| 1231 | char liface[80]; | 1216 | char *liface; |
| 1232 | char *pch; | 1217 | char *pch; |
| 1233 | int okay = 0; | 1218 | int okay = 0; |
| 1234 | 1219 | ||
| 1235 | strncpy(iface, target_iface[i], sizeof(iface)); | 1220 | iface = strdup(target_list->data); |
| 1236 | iface[sizeof(iface) - 1] = '\0'; | 1221 | target_list = target_list->link; |
| 1237 | 1222 | ||
| 1238 | if ((pch = strchr(iface, '='))) { | 1223 | pch = strchr(iface, '='); |
| 1224 | if (pch) { | ||
| 1239 | *pch = '\0'; | 1225 | *pch = '\0'; |
| 1240 | strncpy(liface, pch + 1, sizeof(liface)); | 1226 | liface = strdup(pch + 1); |
| 1241 | liface[sizeof(liface) - 1] = '\0'; | ||
| 1242 | } else { | 1227 | } else { |
| 1243 | strncpy(liface, iface, sizeof(liface)); | 1228 | liface = strdup(iface); |
| 1244 | liface[sizeof(liface) - 1] = '\0'; | ||
| 1245 | } | 1229 | } |
| 1230 | |||
| 1246 | if (!force) { | 1231 | if (!force) { |
| 1247 | int already_up = lookfor_iface(state, n_state, iface);; | 1232 | const llist_t *iface_state = find_iface_state(state_list, iface); |
| 1248 | 1233 | ||
| 1249 | if (cmds == iface_up) { | 1234 | if (cmds == iface_up) { |
| 1250 | /* ifup */ | 1235 | /* ifup */ |
| 1251 | if (already_up != -1) { | 1236 | if (iface_state) { |
| 1252 | error_msg("interface %s already configured", iface); | 1237 | error_msg("interface %s already configured", iface); |
| 1253 | continue; | 1238 | continue; |
| 1254 | } | 1239 | } |
| 1255 | } else { | 1240 | } else { |
| 1256 | /* ifdown */ | 1241 | /* ifdown */ |
| 1257 | if (already_up == -1) { | 1242 | if (iface_state == NULL) { |
| 1258 | error_msg("interface %s not configured", iface); | 1243 | error_msg("interface %s not configured", iface); |
| 1259 | continue; | 1244 | continue; |
| 1260 | } | 1245 | } |
| 1261 | strncpy(liface, strchr(state[already_up], '=') + 1, 80); | 1246 | pch = strchr(iface_state->data, '='); |
| 1262 | liface[79] = 0; | 1247 | liface = strdup(pch + 1); |
| 1263 | } | 1248 | } |
| 1264 | } | 1249 | } |
| 1250 | |||
| 1265 | #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING | 1251 | #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING |
| 1266 | if ((cmds == iface_up) && run_mappings) { | 1252 | if ((cmds == iface_up) && run_mappings) { |
| 1267 | mapping_defn_t *currmap; | 1253 | mapping_defn_t *currmap; |
| @@ -1286,13 +1272,13 @@ extern int ifupdown_main(int argc, char **argv) | |||
| 1286 | char *oldiface = currif->iface; | 1272 | char *oldiface = currif->iface; |
| 1287 | 1273 | ||
| 1288 | okay = 1; | 1274 | okay = 1; |
| 1289 | |||
| 1290 | currif->iface = iface; | 1275 | currif->iface = iface; |
| 1291 | 1276 | ||
| 1292 | if (verbose) { | 1277 | if (verbose) { |
| 1293 | error_msg("Configuring interface %s=%s (%s)", iface, liface, currif->address_family->name); | 1278 | error_msg("Configuring interface %s=%s (%s)", iface, liface, currif->address_family->name); |
| 1294 | } | 1279 | } |
| 1295 | 1280 | ||
| 1281 | /* Call the cmds function pointer, does either iface_up() or iface_down() */ | ||
| 1296 | if (cmds(currif) == -1) { | 1282 | if (cmds(currif) == -1) { |
| 1297 | printf | 1283 | printf |
| 1298 | ("Don't seem to be have all the variables for %s/%s.\n", | 1284 | ("Don't seem to be have all the variables for %s/%s.\n", |
| @@ -1306,39 +1292,54 @@ extern int ifupdown_main(int argc, char **argv) | |||
| 1306 | if (!okay && !force) { | 1292 | if (!okay && !force) { |
| 1307 | error_msg("Ignoring unknown interface %s=%s.", iface, liface); | 1293 | error_msg("Ignoring unknown interface %s=%s.", iface, liface); |
| 1308 | } else { | 1294 | } else { |
| 1309 | int already_up = lookfor_iface(state, n_state, iface); | 1295 | llist_t *iface_state = find_iface_state(state_list, iface); |
| 1310 | 1296 | ||
| 1311 | if (cmds == iface_up) { | 1297 | if (cmds == iface_up) { |
| 1312 | char *newiface = xmalloc(xstrlen(iface) + 1 + xstrlen(liface) + 1); | 1298 | char *newiface = xmalloc(xstrlen(iface) + 1 + xstrlen(liface) + 1); |
| 1313 | sprintf(newiface, "%s=%s", iface, liface); | 1299 | sprintf(newiface, "%s=%s", iface, liface); |
| 1314 | if (already_up == -1) { | 1300 | if (iface_state == NULL) { |
| 1315 | add_to_state(&state, &n_state, &max_state, newiface); | 1301 | state_list = llist_add_to(state_list, newiface); |
| 1316 | } else { | 1302 | } else { |
| 1317 | free(state[already_up]); | 1303 | free(iface_state->data); |
| 1318 | state[already_up] = newiface; | 1304 | iface_state->data = newiface; |
| 1319 | } | 1305 | } |
| 1320 | } else if (cmds == iface_down) { | 1306 | } else if (cmds == iface_down) { |
| 1321 | if (already_up != -1) { | 1307 | /* Remove an interface from the linked list */ |
| 1322 | state[already_up] = state[--n_state]; | 1308 | if (iface_state) { |
| 1309 | /* This needs to be done better */ | ||
| 1310 | free(iface_state->data); | ||
| 1311 | free(iface_state->link); | ||
| 1312 | if (iface_state->link) { | ||
| 1313 | iface_state->data = iface_state->link->data; | ||
| 1314 | iface_state->link = iface_state->link->link; | ||
| 1315 | } else { | ||
| 1316 | iface_state->data = NULL; | ||
| 1317 | iface_state->link = NULL; | ||
| 1318 | } | ||
| 1323 | } | 1319 | } |
| 1324 | } | 1320 | } |
| 1325 | } | 1321 | } |
| 1326 | if (state_fp != NULL && !no_act) { | 1322 | } |
| 1327 | unsigned short j; | ||
| 1328 | 1323 | ||
| 1329 | if (ftruncate(fileno(state_fp), 0) < 0) { | 1324 | /* Actually write the new state */ |
| 1330 | error_msg_and_die("failed to truncate statefile %s: %s", statefile, strerror(errno)); | 1325 | if (state_fp != NULL && !no_act) { |
| 1331 | } | 1326 | if (ftruncate(fileno(state_fp), 0) < 0) { |
| 1327 | error_msg_and_die("failed to truncate statefile %s: %s", statefile, strerror(errno)); | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | rewind(state_fp); | ||
| 1332 | 1331 | ||
| 1333 | rewind(state_fp); | 1332 | while (state_list) { |
| 1334 | for (j = 0; j < n_state; j++) { | 1333 | if (state_list->data) { |
| 1335 | fputs(state[i], state_fp); | 1334 | fputs(state_list->data, state_fp); |
| 1336 | fputc('\n', state_fp); | 1335 | fputc('\n', state_fp); |
| 1337 | } | 1336 | } |
| 1338 | fflush(state_fp); | 1337 | state_list = state_list->link; |
| 1339 | } | 1338 | } |
| 1339 | fflush(state_fp); | ||
| 1340 | } | 1340 | } |
| 1341 | 1341 | ||
| 1342 | /* Cleanup */ | ||
| 1342 | if (state_fp != NULL) { | 1343 | if (state_fp != NULL) { |
| 1343 | fclose(state_fp); | 1344 | fclose(state_fp); |
| 1344 | state_fp = NULL; | 1345 | state_fp = NULL; |
