From: Paul Mackerras Date: Tue, 10 Oct 2023 07:13:30 +0000 (+1100) Subject: Merge pull request #436 from martinetd/mkdir_runtime_lock X-Git-Url: https://git.ozlabs.org/?a=commitdiff_plain;h=c268205e1c861b8898c722a499fa4befac490dc4;hp=99cbf5e269994482edaf64624be8b1c806f9587c;p=ppp.git Merge pull request #436 from martinetd/mkdir_runtime_lock Try to create rundir before using it --- diff --git a/pppd/Makefile.am b/pppd/Makefile.am index 7cb3005..c5fe107 100644 --- a/pppd/Makefile.am +++ b/pppd/Makefile.am @@ -20,6 +20,12 @@ utest_pppcrypt_LDFLAGS = check_PROGRAMS += utest_crypto +utest_utils_SOURCES = utils.c utils_utest.c +utest_utils_CPPFLAGS = -DUNIT_TEST +utest_utils_LDFLAGS = + +check_PROGRAMS += utest_utils + if WITH_SRP sbin_PROGRAMS += srp-entry dist_man8_MANS += srp-entry.8 diff --git a/pppd/pppd-private.h b/pppd/pppd-private.h index 2883e46..46ce0c8 100644 --- a/pppd/pppd-private.h +++ b/pppd/pppd-private.h @@ -437,6 +437,7 @@ int sifproxyarp(int, u_int32_t); int cifproxyarp(int, u_int32_t); /* Delete proxy ARP entry for peer */ u_int32_t GetMask(u_int32_t); /* Get appropriate netmask for address */ +int mkdir_recursive(const char *); /* Recursively create directory */ int lock(char *); /* Create lock file for device */ int relock(int); /* Rewrite lock file with new pid */ void unlock(void); /* Delete previously-created lock file */ diff --git a/pppd/tdb.c b/pppd/tdb.c index 8a563f8..6264417 100644 --- a/pppd/tdb.c +++ b/pppd/tdb.c @@ -60,8 +60,11 @@ #include #include #include + +#include "pppd-private.h" #include "tdb.h" #include "spinlock.h" +#include "pathnames.h" #define TDB_MAGIC_FOOD "TDB file\n" #define TDB_VERSION (0x26011967 + 6) @@ -1728,7 +1731,12 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags, goto internal; } +again: if ((tdb->fd = open(name, open_flags, mode)) == -1) { + if ((open_flags & O_CREAT) && errno == ENOENT && + mkdir_recursive(PPP_PATH_VARRUN) == 0) + goto again; + TDB_LOG((tdb, 5, "tdb_open_ex: could not open file %s: %s\n", name, strerror(errno))); goto fail; /* errno set by open(2) */ diff --git a/pppd/utils.c b/pppd/utils.c index c1bdbbb..c47192e 100644 --- a/pppd/utils.c +++ b/pppd/utils.c @@ -781,6 +781,88 @@ complete_read(int fd, void *buf, size_t count) } #endif +/* + * mkdir_check - helper for mkdir_recursive, creates a directory + * but do not error on EEXIST if and only if entry is a directory + * The caller must check for errno == ENOENT if appropriate. + */ +static int +mkdir_check(const char *path) +{ + struct stat statbuf; + + if (mkdir(path, 0755) >= 0) + return 0; + + if (errno == EEXIST) { + if (stat(path, &statbuf) < 0) + /* got raced? */ + return -1; + + if ((statbuf.st_mode & S_IFMT) == S_IFDIR) + return 0; + + /* already exists but not a dir, treat as failure */ + errno = EEXIST; + return -1; + } + + return -1; +} + +/* + * mkdir_parent - helper for mkdir_recursive, modifies the string in place + * Assumes mkdir(path) already failed, so it first creates the parent then + * full path again. + */ +static int +mkdir_parent(char *path) +{ + char *slash; + int rc; + + slash = strrchr(path, '/'); + if (!slash) + return -1; + + *slash = 0; + if (mkdir_check(path) < 0) { + if (errno != ENOENT) { + *slash = '/'; + return -1; + } + if (mkdir_parent(path) < 0) { + *slash = '/'; + return -1; + } + } + *slash = '/'; + + return mkdir_check(path); +} + +/* + * mkdir_recursive - recursively create directory if it didn't exist + */ +int +mkdir_recursive(const char *path) +{ + char *copy; + int rc; + + // optimistically try on full path first to avoid allocation + if (mkdir_check(path) == 0) + return 0; + + copy = strdup(path); + if (!copy) + return -1; + + rc = mkdir_parent(copy); + free(copy); + return rc; +} + /* Procedures for locking the serial device using a lock file. */ static char lock_file[MAXPATHLEN]; diff --git a/pppd/utils_utest.c b/pppd/utils_utest.c new file mode 100644 index 0000000..cdca97e --- /dev/null +++ b/pppd/utils_utest.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include + +#include "pppd-private.h" + +/* globals used in test.c... */ +int debug = 1; +int error_count; +int unsuccess; + +/* check if path exists and returns its type */ +static int +file_type(char *path) +{ + struct stat statbuf; + + if (stat(path, &statbuf) < 0) + return -1; + + return statbuf.st_mode & S_IFMT; +} + +int +test_simple() { + if (mkdir_recursive("dir")) + return -1; + + if (file_type("dir") != S_IFDIR) + return -1; + + rmdir("dir"); + return 0; +} + +int +test_recurse() { + if (mkdir_recursive("dir/subdir/subsubdir")) + return -1; + + if (file_type("dir/subdir/subsubdir") != S_IFDIR) + return -1; + + rmdir("dir/subdir/subsubdir"); + + /* try again with partial existence */ + if (mkdir_recursive("dir/subdir/subsubdir")) + return -1; + + if (file_type("dir/subdir/subsubdir") != S_IFDIR) + return -1; + + rmdir("dir/subdir/subsubdir"); + rmdir("dir/subdir"); + rmdir("dir"); + return 0; +} + +int +test_recurse_multislash() { + if (mkdir_recursive("dir/subdir///subsubdir")) + return -1; + + if (file_type("dir/subdir/subsubdir") != S_IFDIR) + return -1; + + rmdir("dir/subdir/subsubdir"); + rmdir("dir/subdir"); + + /* try again with partial existence */ + if (mkdir_recursive("dir/subdir/subsubdir///")) + return -1; + + if (file_type("dir/subdir/subsubdir") != S_IFDIR) + return -1; + + rmdir("dir/subdir/subsubdir"); + rmdir("dir/subdir"); + rmdir("dir"); + return 0; +} + +int +test_parent_notdir() { + int fd = open("file", O_CREAT, 0600); + if (fd < 0) + return -1; + close(fd); + + if (mkdir_recursive("file") == 0) + return -1; + if (mkdir_recursive("file/dir") == 0) + return -1; + + unlink("file"); + return 0; +} + +int +main() +{ + char *base_dir = strdup("/tmp/ppp_utils_utest.XXXXXX"); + int failure = 0; + + if (mkdtemp(base_dir) == NULL) { + printf("Could not create test directory, aborting\n"); + return 1; + } + + if (chdir(base_dir) < 0) { + printf("Could not enter newly created test dir, aborting\n"); + return 1; + } + + if (test_simple()) { + printf("Could not create simple directory\n"); + failure++; + } + + if (test_recurse()) { + printf("Could not create recursive directory\n"); + failure++; + } + + if (test_recurse_multislash()) { + printf("Could not create recursive directory with multiple slashes\n"); + failure++; + } + + if (test_parent_notdir()) { + printf("Creating over a file appeared to work?\n"); + failure++; + } + + rmdir(base_dir); + free(base_dir); + return failure; +}