kconfig: remove useless NULL pointer check in conf_write_dep()
[carl9170fw.git] / config / confdata.c
index 7ba857cad240383e2e85fc8f9bb4771171682af1..f6461a6af4bc9a573305b7d1b6e8af5b0997980d 100644 (file)
@@ -1,12 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
  */
 
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -35,6 +37,52 @@ static bool is_dir(const char *path)
        return S_ISDIR(st.st_mode);
 }
 
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+       int fd1, fd2;
+       struct stat st1, st2;
+       void *map1, *map2;
+       bool ret = false;
+
+       fd1 = open(file1, O_RDONLY);
+       if (fd1 < 0)
+               return ret;
+
+       fd2 = open(file2, O_RDONLY);
+       if (fd2 < 0)
+               goto close1;
+
+       ret = fstat(fd1, &st1);
+       if (ret)
+               goto close2;
+       ret = fstat(fd2, &st2);
+       if (ret)
+               goto close2;
+
+       if (st1.st_size != st2.st_size)
+               goto close2;
+
+       map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+       if (map1 == MAP_FAILED)
+               goto close2;
+
+       map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+       if (map2 == MAP_FAILED)
+               goto close2;
+
+       if (bcmp(map1, map2, st1.st_size))
+               goto close2;
+
+       ret = true;
+close2:
+       close(fd2);
+close1:
+       close(fd1);
+
+       return ret;
+}
+
 /*
  * Create the parent directory of the given path.
  *
@@ -74,6 +122,47 @@ static int make_parent_dir(const char *path)
        return 0;
 }
 
+static char depfile_path[PATH_MAX];
+static size_t depfile_prefix_len;
+
+/* touch depfile for symbol 'name' */
+static int conf_touch_dep(const char *name)
+{
+       int fd, ret;
+       const char *s;
+       char *d, c;
+
+       /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
+       if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
+               return -1;
+
+       d = depfile_path + depfile_prefix_len;
+       s = name;
+
+       while ((c = *s++))
+               *d++ = (c == '_') ? '/' : tolower(c);
+       strcpy(d, ".h");
+
+       /* Assume directory path already exists. */
+       fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+       if (fd == -1) {
+               if (errno != ENOENT)
+                       return -1;
+
+               ret = make_parent_dir(depfile_path);
+               if (ret)
+                       return ret;
+
+               /* Try it again. */
+               fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+               if (fd == -1)
+                       return -1;
+       }
+       close(fd);
+
+       return 0;
+}
+
 struct conf_printer {
        void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
        void (*print_comment)(FILE *, const char *, void *);
@@ -186,14 +275,6 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        conf_warning("symbol value '%s' invalid for %s",
                                     p, sym->name);
                return 1;
-       case S_OTHER:
-               if (*p != '"') {
-                       for (p2 = p; *p2 && !isspace(*p2); p2++)
-                               ;
-                       sym->type = S_STRING;
-                       goto done;
-               }
-               /* fall through */
        case S_STRING:
                if (*p++ != '"')
                        break;
@@ -212,7 +293,6 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                /* fall through */
        case S_INT:
        case S_HEX:
-       done:
                if (sym_string_valid(sym, p)) {
                        sym->def[def].val = xstrdup(p);
                        sym->flags |= def_flags;
@@ -393,17 +473,22 @@ load:
                                if (*p2 == '\r')
                                        *p2 = 0;
                        }
-                       if (def == S_DEF_USER) {
-                               sym = sym_find(line + strlen(CONFIG_));
-                               if (!sym) {
+
+                       sym = sym_find(line + strlen(CONFIG_));
+                       if (!sym) {
+                               if (def == S_DEF_AUTO)
+                                       /*
+                                        * Reading from include/config/auto.conf
+                                        * If CONFIG_FOO previously existed in
+                                        * auto.conf but it is missing now,
+                                        * include/config/foo.h must be touched.
+                                        */
+                                       conf_touch_dep(line + strlen(CONFIG_));
+                               else
                                        sym_add_change_count(1);
-                                       continue;
-                               }
-                       } else {
-                               sym = sym_lookup(line + strlen(CONFIG_), 0);
-                               if (sym->type == S_UNKNOWN)
-                                       sym->type = S_OTHER;
+                               continue;
                        }
+
                        if (sym->flags & def_flags) {
                                conf_warning("override: reassigning to symbol %s", sym->name);
                        }
@@ -715,7 +800,6 @@ static void conf_write_symbol(FILE *fp, struct symbol *sym,
        const char *str;
 
        switch (sym->type) {
-       case S_OTHER:
        case S_UNKNOWN:
                break;
        case S_STRING:
@@ -826,40 +910,34 @@ int conf_write(const char *name)
        FILE *out;
        struct symbol *sym;
        struct menu *menu;
-       const char *basename;
        const char *str;
-       char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8];
+       char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
        char *env;
 
-       dirname[0] = 0;
-       if (name && name[0]) {
-               char *slash;
-
-               if (is_dir(name)) {
-                       strcpy(dirname, name);
-                       strcat(dirname, "/");
-                       basename = conf_get_configname();
-               } else if ((slash = strrchr(name, '/'))) {
-                       int size = slash - name + 1;
-                       memcpy(dirname, name, size);
-                       dirname[size] = 0;
-                       if (slash[1])
-                               basename = slash + 1;
-                       else
-                               basename = conf_get_configname();
-               } else
-                       basename = name;
-       } else
-               basename = conf_get_configname();
-
-       sprintf(newname, "%s%s", dirname, basename);
+       if (!name)
+               name = conf_get_configname();
+
+       if (!*name) {
+               fprintf(stderr, "config name is empty\n");
+               return -1;
+       }
+
+       if (is_dir(name)) {
+               fprintf(stderr, "%s: Is a directory\n", name);
+               return -1;
+       }
+
+       if (make_parent_dir(name))
+               return -1;
+
        env = getenv("KCONFIG_OVERWRITECONFIG");
-       if (!env || !*env) {
-               sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
-               out = fopen(tmpname, "w");
-       } else {
+       if (env && *env) {
                *tmpname = 0;
-               out = fopen(newname, "w");
+               out = fopen(name, "w");
+       } else {
+               snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+                        name, (int)getpid());
+               out = fopen(tmpname, "w");
        }
        if (!out)
                return 1;
@@ -906,14 +984,20 @@ next:
        fclose(out);
 
        if (*tmpname) {
-               strcat(dirname, basename);
-               strcat(dirname, ".old");
-               rename(newname, dirname);
-               if (rename(tmpname, newname))
+               if (is_same(name, tmpname)) {
+                       conf_message("No change to %s", name);
+                       unlink(tmpname);
+                       sym_set_change_count(0);
+                       return 0;
+               }
+
+               snprintf(oldname, sizeof(oldname), "%s.old", name);
+               rename(name, oldname);
+               if (rename(tmpname, name))
                        return 1;
        }
 
-       conf_message("configuration written to %s", newname);
+       conf_message("configuration written to %s", name);
 
        sym_set_change_count(0);
 
@@ -926,8 +1010,6 @@ static int conf_write_dep(const char *name)
        struct file *file;
        FILE *out;
 
-       if (!name)
-               name = ".kconfig.d";
        out = fopen("..config.tmp", "w");
        if (!out)
                return 1;
@@ -955,21 +1037,16 @@ static int conf_write_dep(const char *name)
 static int conf_touch_deps(void)
 {
        const char *name;
-       char path[PATH_MAX+1];
-       char *s, *d, c;
        struct symbol *sym;
-       int res, i, fd;
+       int res, i;
+
+       strcpy(depfile_path, "include/generated/");
+       depfile_prefix_len = strlen(depfile_path);
 
        name = conf_get_autoconfig_name();
        conf_read_simple(name, S_DEF_AUTO);
        sym_calc_value(modules_sym);
 
-       if (make_parent_dir("include/generated/foo.h"))
-               return 1;
-       if (chdir("include/generated"))
-               return 1;
-
-       res = 0;
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
                if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
@@ -1021,51 +1098,25 @@ static int conf_touch_deps(void)
                 *      different from 'no').
                 */
 
-               /* Replace all '_' and append ".h" */
-               s = sym->name;
-               d = path;
-               while ((c = *s++)) {
-                       c = tolower(c);
-                       *d++ = (c == '_') ? '/' : c;
-               }
-               strcpy(d, ".h");
-
-               /* Assume directory path already exists. */
-               fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-               if (fd == -1) {
-                       if (errno != ENOENT) {
-                               res = 1;
-                               break;
-                       }
-
-                       if (make_parent_dir(path)) {
-                               res = 1;
-                               goto out;
-                       }
-
-                       /* Try it again. */
-                       fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-                       if (fd == -1) {
-                               res = 1;
-                               break;
-                       }
-               }
-               close(fd);
+               res = conf_touch_dep(sym->name);
+               if (res)
+                       return res;
        }
-out:
-       if (chdir("../.."))
-               return 1;
 
-       return res;
+       return 0;
 }
 
-int conf_write_autoconf(void)
+int conf_write_autoconf(int overwrite)
 {
        struct symbol *sym;
        const char *name;
+       const char *autoconf_name = conf_get_autoconfig_name();
        FILE *out, *tristate, *out_h, *out_c;
        int i;
 
+       if (!overwrite && is_present(autoconf_name))
+               return 0;
+
        sym_clear_all_valid();
 
        conf_write_dep("include/generated/auto.conf.cmd");
@@ -1140,6 +1191,9 @@ int conf_write_autoconf(void)
        if (rename(".tmpconfig_tristate", name))
                return 1;
 
+       if (make_parent_dir(autoconf_name))
+               return 1;
+
        name = getenv("KCONFIG_CMAKE");
        if (!name)
                name = "config.cmake";
@@ -1148,15 +1202,11 @@ int conf_write_autoconf(void)
        if (rename(".tmpconfig.cmake", name))
                return 1;
 
-       name = conf_get_autoconfig_name();
-       if (make_parent_dir(name))
-               return 1;
-
        /*
         * This must be the last step, kbuild has a dependency on auto.conf
         * and this marks the successful completion of the previous steps.
         */
-       if (rename(".tmpconfig", name))
+       if (rename(".tmpconfig", autoconf_name))
                return 1;
 
        return 0;