Currently, conf_write() can be called with a directory name instead of a file name. As far as I see, this can happen for menuconfig, nconfig, gconfig. If it is given with a directory path, conf_write() kindly appends getenv("KCONFIG_CONFIG"), but this ends up with hacky dir/basename handling, and screwed up in corner-cases like "what if KCONFIG_CONFIG is an absolute path?" as discussed before: https://patchwork.kernel.org/patch/9910037/ Since conf_write() is already messed up, I'd say "do not do it". Please pass a file path all the time. If a directory path is specified for the configuration output, conf_write() will simply error out. Now that the tmp file is created in the same directory as the .config, the previously reported "what if KCONFIG_CONFIG points to a different file system?" has been solved.
Unified · Split
| @@ -817,40 +817,31 @@ int conf_write(const char *name) · 816 unmodified lines | ||
| 817 | 817 | FILE *out; |
| 818 | 818 | struct symbol *sym; |
| 819 | 819 | struct menu *menu; |
| 820 | − const char *basename; | |
| 821 | 820 | const char *str; |
| 822 | − char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; | |
| 821 | + char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1]; | |
| 823 | 822 | char *env; |
| 824 | 823 | |
| 825 | − dirname[0] = 0; | |
| 826 | − if (name && name[0]) { | |
| 827 | − char *slash; | |
| 828 | − | |
| 829 | − if (is_dir(name)) { | |
| 830 | − strcpy(dirname, name); | |
| 831 | − strcat(dirname, "/"); | |
| 832 | − basename = conf_get_configname(); | |
| 833 | − } else if ((slash = strrchr(name, '/'))) { | |
| 834 | − int size = slash - name + 1; | |
| 835 | − memcpy(dirname, name, size); | |
| 836 | − dirname[size] = 0; | |
| 837 | − if (slash[1]) | |
| 838 | − basename = slash + 1; | |
| 839 | − else | |
| 840 | − basename = conf_get_configname(); | |
| 841 | − } else | |
| 842 | − basename = name; | |
| 843 | − } else | |
| 844 | − basename = conf_get_configname(); | |
| 845 | − | |
| 846 | − sprintf(newname, "%s%s", dirname, basename); | |
| 824 | + if (!name) | |
| 825 | + name = conf_get_configname(); | |
| 826 | + | |
| 827 | + if (!*name) { | |
| 828 | + fprintf(stderr, "config name is empty\n"); | |
| 829 | + return -1; | |
| 830 | + } | |
| 831 | + | |
| 832 | + if (is_dir(name)) { | |
| 833 | + fprintf(stderr, "%s: Is a directory\n", name); | |
| 834 | + return -1; | |
| 835 | + } | |
| 836 | + | |
| 847 | 837 | env = getenv("KCONFIG_OVERWRITECONFIG"); |
| 848 | − if (!env || !*env) { | |
| 849 | − sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); | |
| 850 | − out = fopen(tmpname, "w"); | |
| 851 | − } else { | |
| 838 | + if (env && *env) { | |
| 852 | 839 | *tmpname = 0; |
| 853 | − out = fopen(newname, "w"); | |
| 840 | + out = fopen(name, "w"); | |
| 841 | + } else { | |
| 842 | + snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp", | |
| 843 | + name, (int)getpid()); | |
| 844 | + out = fopen(tmpname, "w"); | |
| 854 | 845 | } |
| 855 | 846 | if (!out) |
| 856 | 847 | return 1; |
| @@ -897,14 +888,13 @@ next: · 40 unmodified lines | ||
| 897 | 888 | fclose(out); |
| 898 | 889 | |
| 899 | 890 | if (*tmpname) { |
| 900 | − strcat(dirname, basename); | |
| 901 | − strcat(dirname, ".old"); | |
| 902 | − rename(newname, dirname); | |
| 903 | − if (rename(tmpname, newname)) | |
| 891 | + snprintf(oldname, sizeof(oldname), "%s.old", name); | |
| 892 | + rename(name, oldname); | |
| 893 | + if (rename(tmpname, name)) | |
| 904 | 894 | return 1; |
| 905 | 895 | } |
| 906 | 896 | |
| 907 | − conf_message("configuration written to %s", newname); | |
| 897 | + conf_message("configuration written to %s", name); | |
| 908 | 898 | |
| 909 | 899 | sym_set_change_count(0); |
| 910 | 900 | |