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>
This commit is contained in:
parent
ec1ea16337
commit
3720a61daf
@ -56,6 +56,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS
|
#define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS
|
||||||
|
#define IFSTATE_FILE_PATH CONFIG_IFUPDOWN_IFSTATE_PATH
|
||||||
|
|
||||||
#define debug_noise(args...) /*fprintf(stderr, args)*/
|
#define debug_noise(args...) /*fprintf(stderr, args)*/
|
||||||
|
|
||||||
@ -1200,7 +1201,7 @@ static llist_t *find_iface_state(llist_t *state_list, const char *iface)
|
|||||||
static llist_t *read_iface_state(void)
|
static llist_t *read_iface_state(void)
|
||||||
{
|
{
|
||||||
llist_t *state_list = NULL;
|
llist_t *state_list = NULL;
|
||||||
FILE *state_fp = fopen_for_read(CONFIG_IFUPDOWN_IFSTATE_PATH);
|
FILE *state_fp = fopen_for_read(IFSTATE_FILE_PATH);
|
||||||
|
|
||||||
if (state_fp) {
|
if (state_fp) {
|
||||||
char *start, *end_ptr;
|
char *start, *end_ptr;
|
||||||
@ -1215,6 +1216,38 @@ static llist_t *read_iface_state(void)
|
|||||||
return state_list;
|
return state_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read the previous state from the state file */
|
||||||
|
static FILE *open_new_state_file(void)
|
||||||
|
{
|
||||||
|
int fd, flags, cnt;
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
flags = (O_WRONLY | O_CREAT | O_EXCL);
|
||||||
|
for (;;) {
|
||||||
|
fd = open(IFSTATE_FILE_PATH".new", flags, 0666);
|
||||||
|
if (fd >= 0)
|
||||||
|
break;
|
||||||
|
if (errno != EEXIST
|
||||||
|
|| flags == (O_WRONLY | O_CREAT | O_TRUNC)
|
||||||
|
) {
|
||||||
|
bb_perror_msg_and_die("can't open '%s'",
|
||||||
|
IFSTATE_FILE_PATH".new");
|
||||||
|
}
|
||||||
|
/* Someone else created the .new file */
|
||||||
|
if (cnt > 30 * 1000) {
|
||||||
|
/* Waited for 30*30/2 = 450 milliseconds, still EEXIST.
|
||||||
|
* Assuming a stale file, rewriting it.
|
||||||
|
*/
|
||||||
|
flags = (O_WRONLY | O_CREAT | O_TRUNC);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
usleep(cnt);
|
||||||
|
cnt += 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfdopen_for_write(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||||
int ifupdown_main(int argc UNUSED_PARAM, char **argv)
|
int ifupdown_main(int argc UNUSED_PARAM, char **argv)
|
||||||
@ -1348,7 +1381,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
any_failures = 1;
|
any_failures = 1;
|
||||||
} else if (!NO_ACT) {
|
} else if (!NO_ACT) {
|
||||||
/* update the state file */
|
/* update the state file */
|
||||||
FILE *state_fp;
|
FILE *new_state_fp = open_new_state_file();
|
||||||
llist_t *state;
|
llist_t *state;
|
||||||
llist_t *state_list = read_iface_state();
|
llist_t *state_list = read_iface_state();
|
||||||
llist_t *iface_state = find_iface_state(state_list, iface);
|
llist_t *iface_state = find_iface_state(state_list, iface);
|
||||||
@ -1368,15 +1401,15 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Actually write the new state */
|
/* Actually write the new state */
|
||||||
state_fp = xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH);
|
|
||||||
state = state_list;
|
state = state_list;
|
||||||
while (state) {
|
while (state) {
|
||||||
if (state->data) {
|
if (state->data) {
|
||||||
fprintf(state_fp, "%s\n", state->data);
|
fprintf(new_state_fp, "%s\n", state->data);
|
||||||
}
|
}
|
||||||
state = state->link;
|
state = state->link;
|
||||||
}
|
}
|
||||||
fclose(state_fp);
|
fclose(new_state_fp);
|
||||||
|
xrename(IFSTATE_FILE_PATH".new", IFSTATE_FILE_PATH);
|
||||||
llist_free(state_list, free);
|
llist_free(state_list, free);
|
||||||
}
|
}
|
||||||
next:
|
next:
|
||||||
|
Loading…
Reference in New Issue
Block a user