Index: apps/app_voicemail.c =================================================================== --- apps/app_voicemail.c (revision 10407) +++ apps/app_voicemail.c (working copy) @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -634,7 +635,7 @@ FILE *configin; FILE *configout; - int linenum=0; + int linenum=0, fdout=-1, i; char inbuf[256]; char orig[256]; char currcontext[256] =""; @@ -647,11 +648,29 @@ snprintf(tmpin, sizeof(tmpin), "%s/voicemail.conf", ast_config_AST_CONFIG_DIR); snprintf(tmpout, sizeof(tmpout), "%s/voicemail.conf.new", ast_config_AST_CONFIG_DIR); - configin = fopen(tmpin,"r"); - if (configin) - configout = fopen(tmpout,"w+"); + /* Open the "out" file first to avoid a race condition */ + + /* Try for 100us to get a lock */ + for (i = 0; i <= 10; i++) { + configout = fopen(tmpout, "w+"); + fdout = fileno(configout); + + if ((fdout != -1) && (!lockf(fdout, F_TLOCK, 0))) + break; + + fclose(configout); + configout = NULL; + if (i == 10) { + ast_log(LOG_WARNING, "Unable to obtain a lock on '%s' for writing: %s\n", tmpout, strerror(errno)); + } else + usleep(10); + } + + if (configout) + configin = fopen(tmpin, "r"); else - configout = NULL; + configin = NULL; + if (!configin || !configout) { if (configin) fclose(configin); @@ -661,7 +680,7 @@ fclose(configout); else ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno)); - return; + return; } while (!feof(configin)) { @@ -751,13 +770,16 @@ } } fclose(configin); - fclose(configout); stat(tmpin, &statbuf); chmod(tmpout, statbuf.st_mode); chown(tmpout, statbuf.st_uid, statbuf.st_gid); - unlink(tmpin); rename(tmpout, tmpin); + + /* Only release the lock when we're done moving the file. This prevents + * a race condition. */ + lockf(fdout, F_ULOCK, 0); + fclose(configout); reset_user_pw(vmu->context, vmu->mailbox, newpassword); ast_copy_string(vmu->password, newpassword, sizeof(vmu->password)); }