chiark / gitweb /
fileio:parse_env_file_internal() fix environment file parsing
[elogind.git] / src / shared / fileio.c
index 96e23c5bbb69c314bdaa65c7ebdef98b81a2780a..3f242edc600a1b0a864820639b3073dbfb309bb4 100644 (file)
@@ -35,9 +35,7 @@ int write_string_file(const char *fn, const char *line) {
                 return -errno;
 
         errno = 0;
-        if (fputs(line, f) < 0)
-                return errno ? -errno : -EIO;
-
+        fputs(line, f);
         if (!endswith(line, "\n"))
                 fputc('\n', f);
 
@@ -64,11 +62,7 @@ int write_string_file_atomic(const char *fn, const char *line) {
         fchmod_umask(fileno(f), 0644);
 
         errno = 0;
-        if (fputs(line, f) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
+        fputs(line, f);
         if (!endswith(line, "\n"))
                 fputc('\n', f);
 
@@ -83,7 +77,6 @@ int write_string_file_atomic(const char *fn, const char *line) {
                         r = 0;
         }
 
-finish:
         if (r < 0)
                 unlink(p);
 
@@ -216,7 +209,9 @@ static int parse_env_file_internal(
                 switch (state) {
 
                 case PRE_KEY:
-                        if (strchr(COMMENTS, c))
+                        if (startswith(p, "export "))
+                                p+=6;
+                        else if (strchr(COMMENTS, c))
                                 state = COMMENT;
                         else if (!strchr(WHITESPACE, c)) {
                                 state = KEY;
@@ -262,7 +257,7 @@ static int parse_env_file_internal(
                         break;
 
                 case PRE_VALUE:
-                        if (strchr(newline, c)) {
+                        if (strchr(newline, c) || strchr(COMMENTS, c)) {
                                 state = PRE_KEY;
                                 key[n_key] = 0;
 
@@ -522,6 +517,37 @@ int load_env_file(const char *fname, const char *newline, char ***rl) {
         return 0;
 }
 
+static void write_env_var(FILE *f, const char *v) {
+        const char *p;
+
+        p = strchr(v, '=');
+        if (!p) {
+                /* Fallback */
+                fputs(v, f);
+                fputc('\n', f);
+                return;
+        }
+
+        p++;
+        fwrite(v, 1, p-v, f);
+
+        if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) {
+                fputc('\"', f);
+
+                for (; *p; p++) {
+                        if (strchr("\'\"\\`$", *p))
+                                fputc('\\', f);
+
+                        fputc(*p, f);
+                }
+
+                fputc('\"', f);
+        } else
+                fputs(p, f);
+
+        fputc('\n', f);
+}
+
 int write_env_file(const char *fname, char **l) {
         char **i;
         char _cleanup_free_ *p = NULL;
@@ -535,19 +561,14 @@ int write_env_file(const char *fname, char **l) {
         fchmod_umask(fileno(f), 0644);
 
         errno = 0;
-        STRV_FOREACH(i, l) {
-                fputs(*i, f);
-                fputc('\n', f);
-        }
+        STRV_FOREACH(i, l)
+                write_env_var(f, *i);
 
         fflush(f);
 
-        if (ferror(f)) {
-                if (errno > 0)
-                        r = -errno;
-                else
-                        r = -EIO;
-        } else {
+        if (ferror(f))
+                r = errno ? -errno : -EIO;
+        else {
                 if (rename(p, fname) < 0)
                         r = -errno;
                 else