diff --git a/CHANGELOG b/CHANGELOG index 6007086..04d8159 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ - fix get_query_dn not looking in subtree for LDAP search (missed second occurance). - allow additional common LDAP attributes in map dn. +- deal with changed semantics of mkdir in 2.6.19. 1/9/2006 autofs-5.0.1 rc2 ------------------------- diff --git a/daemon/automount.c b/daemon/automount.c index 343fd68..ccb8021 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -72,33 +72,70 @@ static int umount_all(struct autofs_poin extern pthread_mutex_t master_mutex; extern struct master *master_list; +static int do_mkdir(const char *parent, const char *path, mode_t mode) +{ + int status; + struct stat st; + struct statfs fs; + + /* If path exists we're done */ + status = stat(path, &st); + if (status == 0) { + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return 0; + } + return 1; + } + + /* + * If we're trying to create a directory within an autofs fs + * of the path is contained in a localy mounted fs go ahead. + */ + status = -1; + if (*parent) + status = statfs(parent, &fs); + if ((status != -1 && fs.f_type == AUTOFS_SUPER_MAGIC) || + contained_in_local_fs(path)) { + if (mkdir(path, mode) == -1) { + if (errno == EEXIST) + return 1; + return 0; + } + return 1; + } + + return 0; +} + int mkdir_path(const char *path, mode_t mode) { char *buf = alloca(strlen(path) + 1); + char *parent = alloca(strlen(path) + 1); const char *cp = path, *lcp = path; - char *bp = buf; + char *bp = buf, *pp = parent; + + *parent = '\0'; do { if (cp != path && (*cp == '/' || *cp == '\0')) { memcpy(bp, lcp, cp - lcp); bp += cp - lcp; - lcp = cp; *bp = '\0'; - if (mkdir(buf, mode) == -1) { - /* If it already exists, make sure it's a directory */ - if (errno == EEXIST) { - struct stat st; - - if (stat(buf, &st) == 0 && !S_ISDIR(st.st_mode)) - errno = ENOTDIR; - else { - /* last component, return -1 */ - if (*cp != '\0') - continue; - } + if (!do_mkdir(parent, buf, mode)) { + if (*cp != '\0') { + memcpy(pp, lcp, cp - lcp); + pp += cp - lcp; + *pp = '\0'; + lcp = cp; + continue; } return -1; } + memcpy(pp, lcp, cp - lcp); + pp += cp - lcp; + *pp = '\0'; + lcp = cp; } } while (*cp++ != '\0'); diff --git a/daemon/indirect.c b/daemon/indirect.c index 608f37b..492cbbb 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -171,7 +171,7 @@ static int do_mount_autofs_indirect(stru if (mkdir_path(ap->path, 0555) < 0) { if (errno != EEXIST && errno != EROFS) { crit(ap->logopt, - "failed to create iautofs directory %s", + "failed to create autofs directory %s", ap->path); goto out_err; } diff --git a/include/automount.h b/include/automount.h index 9c2de00..798cc50 100644 --- a/include/automount.h +++ b/include/automount.h @@ -322,6 +322,7 @@ #define MNTS_AUTOFS 0x0004 struct mnt_list { char *path; + char *fs_name; char *fs_type; char *opts; pid_t owner; @@ -350,6 +351,7 @@ char *make_mnt_name_string(char *path); struct mnt_list *get_mnt_list(const char *table, const char *path, int include); struct mnt_list *reverse_mnt_list(struct mnt_list *list); void free_mnt_list(struct mnt_list *list); +int contained_in_local_fs(const char *path); int is_mounted(const char *table, const char *path, unsigned int type); int has_fstab_option(const char *opt); char *find_mnt_ino(const char *table, dev_t dev, ino_t ino); diff --git a/lib/mounts.c b/lib/mounts.c index 46131cd..1e92ca5 100644 --- a/lib/mounts.c +++ b/lib/mounts.c @@ -170,9 +170,16 @@ struct mnt_list *get_mnt_list(const char } strcpy(ent->path, mnt->mnt_dir); + ent->fs_name = malloc(strlen(mnt->mnt_fsname) + 1); + if (!ent->fs_name) { + endmntent(tab); + free_mnt_list(list); + return NULL; + } + strcpy(ent->fs_name, mnt->mnt_fsname); + ent->fs_type = malloc(strlen(mnt->mnt_type) + 1); if (!ent->fs_type) { - free(ent->path); endmntent(tab); free_mnt_list(list); return NULL; @@ -181,8 +188,6 @@ struct mnt_list *get_mnt_list(const char ent->opts = malloc(strlen(mnt->mnt_opts) + 1); if (!ent->opts) { - free(ent->fs_type); - free(ent->path); endmntent(tab); free_mnt_list(list); return NULL; @@ -240,6 +245,9 @@ void free_mnt_list(struct mnt_list *list if (this->path) free(this->path); + if (this->fs_name) + free(this->fs_name); + if (this->fs_type) free(this->fs_type); @@ -250,6 +258,43 @@ void free_mnt_list(struct mnt_list *list } } +int contained_in_local_fs(const char *path) +{ + struct mnt_list *mnts, *this; + size_t pathlen = strlen(path); + int ret; + + if (!path || !pathlen || pathlen > PATH_MAX) + return 0; + + mnts = get_mnt_list(_PATH_MOUNTED, "/", 1); + if (!mnts) + return 0; + + ret = 0; + + for (this = mnts; this != NULL; this = this->next) { + size_t len = strlen(this->path); + + if (!strncmp(path, this->path, len)) { + if (len > 1 && pathlen > len && path[len] != '/') + continue; + else if (this->fs_name[0] == '/') { + if (strlen(this->fs_name) > 1) { + if (this->fs_name[1] != '/') + ret = 1; + } else + ret = 1; + } + break; + } + } + + free_mnt_list(mnts); + + return ret; +} + int is_mounted(const char *table, const char *path, unsigned int type) { struct mntent *mnt; @@ -497,6 +542,7 @@ void tree_free_mnt_tree(struct mnt_list list_del(&this->self); free(this->path); + free(this->fs_name); free(this->fs_type); if (this->opts) @@ -506,6 +552,7 @@ void tree_free_mnt_tree(struct mnt_list } free(tree->path); + free(tree->fs_name); free(tree->fs_type); if (tree->opts) @@ -570,9 +617,21 @@ struct mnt_list *tree_make_mnt_tree(cons } strcpy(ent->path, mnt->mnt_dir); + ent->fs_name = malloc(strlen(mnt->mnt_fsname) + 1); + if (!ent->fs_name) { + free(ent->path); + free(ent); + endmntent(tab); + tree_free_mnt_tree(tree); + return NULL; + } + strcpy(ent->fs_name, mnt->mnt_fsname); + ent->fs_type = malloc(strlen(mnt->mnt_type) + 1); if (!ent->fs_type) { + free(ent->fs_name); free(ent->path); + free(ent); endmntent(tab); tree_free_mnt_tree(tree); return NULL; @@ -582,7 +641,9 @@ struct mnt_list *tree_make_mnt_tree(cons ent->opts = malloc(strlen(mnt->mnt_opts) + 1); if (!ent->opts) { free(ent->fs_type); + free(ent->fs_name); free(ent->path); + free(ent); endmntent(tab); tree_free_mnt_tree(tree); return NULL;