config: bug: fix truncation of included config files on permissions error
authorGeorge Joseph <george.joseph@fairview5.com>
Wed, 10 Sep 2014 16:07:04 +0000 (16:07 +0000)
committerGeorge Joseph <george.joseph@fairview5.com>
Wed, 10 Sep 2014 16:07:04 +0000 (16:07 +0000)
ast_config_text_file_save() currently truncates include files as they
are processed.  If a subsequent include file or the main config file has
a permissions error that prevents writing, earlier include files are left
truncated resulting in a frantic search for backups.

This patch causes ast_config_text_file_save to check for write access
on all files before it truncates any of them.

Will be applied 1.8 > trunk.

Tested by: George Joseph
Review: https://reviewboard.asterisk.org/r/3986/
........

Merged revisions 422900 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 422903 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 422904 from http://svn.asterisk.org/svn/asterisk/branches/12
........

Merged revisions 422905 from http://svn.asterisk.org/svn/asterisk/branches/13

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@422906 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/config.c

index cd2e8b8..ab9e9c2 100644 (file)
@@ -2067,21 +2067,27 @@ static void inclfile_destroy(void *obj)
        ast_free(o->fname);
 }
 
-
-static struct inclfile *set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset)
+static void make_fn(char *fn, size_t fn_size, const char *file, const char *configfile)
 {
-       struct inclfile lookup;
-       struct inclfile *fi;
-
        if (ast_strlen_zero(file)) {
-               if (configfile[0] == '/')
+               if (configfile[0] == '/') {
                        ast_copy_string(fn, configfile, fn_size);
-               else
+               } else {
                        snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
-       } else if (file[0] == '/')
+               }
+       } else if (file[0] == '/') {
                ast_copy_string(fn, file, fn_size);
-       else
+       } else {
                snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
+       }
+}
+
+static struct inclfile *set_fn(char *fn, size_t fn_size, const char *file, const char *configfile, struct ao2_container *fileset)
+{
+       struct inclfile lookup;
+       struct inclfile *fi;
+
+       make_fn(fn, fn_size, file, configfile);
        lookup.fname = fn;
        fi = ao2_find(fileset, &lookup, OBJ_POINTER);
        if (fi) {
@@ -2190,11 +2196,29 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c
                return -1;
        }
 
-       /* reset all the output flags, in case this isn't our first time saving this data */
+       /* Check all the files for write access before attempting to modify any of them */
        for (incl = cfg->includes; incl; incl = incl->next) {
+               /* reset all the output flags in case this isn't our first time saving this data */
                incl->output = 0;
+               /* now make sure we have write access */
+               if (!incl->exec) {
+                       make_fn(fn, sizeof(fn), incl->included_file, configfile);
+                       if (access(fn, R_OK | W_OK)) {
+                               ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
+                               return -1;
+                       }
+               }
        }
 
+       /* now make sure we have write access to the main config file */
+       make_fn(fn, sizeof(fn), 0, configfile);
+       if (access(fn, R_OK | W_OK)) {
+               ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
+               return -1;
+       }
+
+       /* Now that we know we have write access to all files, it's safe to start truncating them */
+
        /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
           are all truncated to zero bytes and have that nice header*/
        for (incl = cfg->includes; incl; incl = incl->next) {
@@ -2206,8 +2230,7 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c
                                gen_header(f, configfile, fn, generator);
                                fclose(f); /* this should zero out the file */
                        } else {
-                               ast_debug(1, "Unable to open for writing: %s\n", fn);
-                               ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
+                               ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
                        }
                        if (fi) {
                                ao2_ref(fi, -1);
@@ -2240,8 +2263,7 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c
                        fi = set_fn(fn, sizeof(fn), cat->file, configfile, fileset);
                        f = fopen(fn, "a");
                        if (!f) {
-                               ast_debug(1, "Unable to open for writing: %s\n", fn);
-                               ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
+                               ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
                                if (fi) {
                                        ao2_ref(fi, -1);
                                }