From: Zbigniew Jędrzejewski-Szmek Date: Thu, 10 Feb 2022 07:30:08 +0000 (+0100) Subject: basic: do not warn in mkdir_p() when parent directory exists X-Git-Tag: v251-rc1~309 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e01e68e70ae1db9fe61adec3e7bdcced7adc1930;p=thirdparty%2Fsystemd.git basic: do not warn in mkdir_p() when parent directory exists This effectively disables warnings about type/mode/ownership of existing directories when recursively creating parent directories. (Or files. If there's a file in a place we expect a directory, the code will later try to create a file and fail. This follows the general pattern where we do (void)mkdir() if the mkdir() is immediately followed by opening of a file.) I was recently debugging an issue with the fstab-generator [1], and it says: 'Directory "/tmp" already exists, but has mode 0777 that is too permissive (0644 was requested), refusing.' which is very specific but totally wrong in this context. This output was added in 37c1d5e97dbc869edd8fc178427714e2d9428d2b, and I still think it is worth to do it, because if you actually *do* want the directory, if there's something wrong, the precise error message will make it much easier to diagnose. And we can't easily pass the information what failed up the call chain because there are multiple things we check (ownership, permission mask, type)… So passing a param whether to warn or not down into the library code seems like the best solution, despite not being very elegant. [1] https://bugzilla.redhat.com/show_bug.cgi?id=2051285 --- diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 51a0d74e875..d2c6b96a38d 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -51,6 +51,9 @@ int mkdir_safe_internal( _mkdirat); } + if (flags & MKDIR_IGNORE_EXISTING) + return 0; + if (!S_ISDIR(st.st_mode)) return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(ENOTDIR), "Path \"%s\" already exists and is not a directory, refusing.", path); @@ -138,7 +141,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui s[n] = '\0'; if (!prefix || !path_startswith_full(prefix, path, /* accept_dot_dot= */ false)) { - r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdirat); + r = mkdir_safe_internal(path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat); if (r < 0 && r != -EEXIST) return r; } diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h index 34a52275778..c0c0ea6c4f5 100644 --- a/src/basic/mkdir.h +++ b/src/basic/mkdir.h @@ -4,8 +4,9 @@ #include typedef enum MkdirFlags { - MKDIR_FOLLOW_SYMLINK = 1 << 0, - MKDIR_WARN_MODE = 1 << 1, + MKDIR_FOLLOW_SYMLINK = 1 << 0, + MKDIR_IGNORE_EXISTING = 1 << 1, /* Quietly accept a preexisting directory (or file) */ + MKDIR_WARN_MODE = 1 << 2, /* Log at LOG_WARNING when mode doesn't match */ } MkdirFlags; int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode);