aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-10-09 23:04:16 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-10-09 23:04:16 +0200
commit3720a61daf2e03e42e34902c2636ce3e3d6b8485 (patch)
tree6208f33c94578dbfaf39b5b108f7745190bb2c3b
parentec1ea16337623824e3e71bb5dc0e011259664d7e (diff)
downloadbusybox-w32-3720a61daf2e03e42e34902c2636ce3e3d6b8485.tar.gz
busybox-w32-3720a61daf2e03e42e34902c2636ce3e3d6b8485.tar.bz2
busybox-w32-3720a61daf2e03e42e34902c2636ce3e3d6b8485.zip
ifupdown: rewrite state file atomically
By user's request. Decided to not use fcntl(F_SETLKW) in lieu of problems with locking on networked filesystems. The existence of /var/run/ifstate.new is treated as a write lock. rename() provides atomicity. function old new delta ifupdown_main 1019 1122 +103 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--networking/ifupdown.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index b0bc0d70f..1d0fc53cf 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -56,6 +56,7 @@
56#endif 56#endif
57 57
58#define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS 58#define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS
59#define IFSTATE_FILE_PATH CONFIG_IFUPDOWN_IFSTATE_PATH
59 60
60#define debug_noise(args...) /*fprintf(stderr, args)*/ 61#define debug_noise(args...) /*fprintf(stderr, args)*/
61 62
@@ -1200,7 +1201,7 @@ static llist_t *find_iface_state(llist_t *state_list, const char *iface)
1200static llist_t *read_iface_state(void) 1201static llist_t *read_iface_state(void)
1201{ 1202{
1202 llist_t *state_list = NULL; 1203 llist_t *state_list = NULL;
1203 FILE *state_fp = fopen_for_read(CONFIG_IFUPDOWN_IFSTATE_PATH); 1204 FILE *state_fp = fopen_for_read(IFSTATE_FILE_PATH);
1204 1205
1205 if (state_fp) { 1206 if (state_fp) {
1206 char *start, *end_ptr; 1207 char *start, *end_ptr;
@@ -1215,6 +1216,38 @@ static llist_t *read_iface_state(void)
1215 return state_list; 1216 return state_list;
1216} 1217}
1217 1218
1219/* read the previous state from the state file */
1220static FILE *open_new_state_file(void)
1221{
1222 int fd, flags, cnt;
1223
1224 cnt = 0;
1225 flags = (O_WRONLY | O_CREAT | O_EXCL);
1226 for (;;) {
1227 fd = open(IFSTATE_FILE_PATH".new", flags, 0666);
1228 if (fd >= 0)
1229 break;
1230 if (errno != EEXIST
1231 || flags == (O_WRONLY | O_CREAT | O_TRUNC)
1232 ) {
1233 bb_perror_msg_and_die("can't open '%s'",
1234 IFSTATE_FILE_PATH".new");
1235 }
1236 /* Someone else created the .new file */
1237 if (cnt > 30 * 1000) {
1238 /* Waited for 30*30/2 = 450 milliseconds, still EEXIST.
1239 * Assuming a stale file, rewriting it.
1240 */
1241 flags = (O_WRONLY | O_CREAT | O_TRUNC);
1242 continue;
1243 }
1244 usleep(cnt);
1245 cnt += 1000;
1246 }
1247
1248 return xfdopen_for_write(fd);
1249}
1250
1218 1251
1219int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1252int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1220int ifupdown_main(int argc UNUSED_PARAM, char **argv) 1253int ifupdown_main(int argc UNUSED_PARAM, char **argv)
@@ -1348,7 +1381,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv)
1348 any_failures = 1; 1381 any_failures = 1;
1349 } else if (!NO_ACT) { 1382 } else if (!NO_ACT) {
1350 /* update the state file */ 1383 /* update the state file */
1351 FILE *state_fp; 1384 FILE *new_state_fp = open_new_state_file();
1352 llist_t *state; 1385 llist_t *state;
1353 llist_t *state_list = read_iface_state(); 1386 llist_t *state_list = read_iface_state();
1354 llist_t *iface_state = find_iface_state(state_list, iface); 1387 llist_t *iface_state = find_iface_state(state_list, iface);
@@ -1368,15 +1401,15 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv)
1368 } 1401 }
1369 1402
1370 /* Actually write the new state */ 1403 /* Actually write the new state */
1371 state_fp = xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH);
1372 state = state_list; 1404 state = state_list;
1373 while (state) { 1405 while (state) {
1374 if (state->data) { 1406 if (state->data) {
1375 fprintf(state_fp, "%s\n", state->data); 1407 fprintf(new_state_fp, "%s\n", state->data);
1376 } 1408 }
1377 state = state->link; 1409 state = state->link;
1378 } 1410 }
1379 fclose(state_fp); 1411 fclose(new_state_fp);
1412 xrename(IFSTATE_FILE_PATH".new", IFSTATE_FILE_PATH);
1380 llist_free(state_list, free); 1413 llist_free(state_list, free);
1381 } 1414 }
1382 next: 1415 next: