3
0

ifupdown.c 33 KB

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