[PVFS2-CVS] commit by robl in pvfs2-1/src/apps/admin: pvfs2-mkdir.c
CVS commit program
cvs at parl.clemson.edu
Tue Jul 12 12:40:44 EDT 2005
Update of /projects/cvsroot/pvfs2-1/src/apps/admin
In directory parlweb:/tmp/cvs-serv24195/src/apps/admin
Modified Files:
pvfs2-mkdir.c
Log Message:
David Metheny's improvements to pvfs2-mkdir:
- support multiple directories to be specified on the command line
- parent directory creation (mkdir -p)
- the ability to specify an initial mode.
Index: pvfs2-mkdir.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/apps/admin/pvfs2-mkdir.c,v
diff -u -w -p -u -r1.5 -r1.6
--- pvfs2-mkdir.c 28 Jul 2004 14:32:29 -0000 1.5
+++ pvfs2-mkdir.c 12 Jul 2005 15:40:44 -0000 1.6
@@ -1,6 +1,10 @@
/*
* (C) 2004 Clemson University and The University of Chicago
*
+ * Changes by Acxiom Corporation to add support for mode, multiple directory
+ * creation, and parent creation.
+ * Copyright Acxiom Corporation, 2005.
+ *
* See COPYING in top-level directory.
*/
@@ -13,6 +17,8 @@
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
+#include <getopt.h>
+#include <libgen.h>
#include "pvfs2.h"
#include "str-utils.h"
@@ -22,35 +28,81 @@
#define PVFS2_VERSION "Unknown"
#endif
+/* We need to set some limit, I suppose */
+#define MAX_NUM_DIRECTORIES 100
+
/* optional parameters, filled in by parse_args() */
struct options
{
- char* destfile;
+ char ** dir_array; /* array of directories to create */
+ int numdirs; /* number of directories to create */
+ int mode; /* mode of directories */
+ int verbose;
+ int make_parent_dirs; /* Create missing parents */
};
-static struct options* parse_args(int argc, char* argv[]);
+/* Function Prototypes */
static void usage(int argc, char** argv);
+static int parse_args(int argc, char** argv, struct options * opts);
+static void enable_verbose(struct options * opts);
+static void enable_parents(struct options * opts);
+static int read_mode(struct options * opts, const char * buffer);
+static int make_directory(PVFS_credentials * credentials,
+ const PVFS_fs_id fs_id,
+ const int mode,
+ const char * dir,
+ const char * pvfs_path,
+ const int make_parent_dirs,
+ const int verbose);
int main(int argc, char **argv)
{
- int ret = -1;
- char str_buf[PVFS_NAME_MAX] = {0};
- char pvfs_path[PVFS_NAME_MAX] = {0};
- PVFS_fs_id cur_fs;
- PVFS_sysresp_lookup resp_lookup;
- PVFS_sysresp_mkdir resp_mkdir;
- struct options* user_opts = NULL;
- char* entry_name;
- PVFS_object_ref parent_ref;
- PVFS_sys_attr attr;
+ int ret = -1, status = 0; /* Get's set if error */
+ int i = 0;
+ char **pvfs_path = NULL;
+ PVFS_fs_id *pfs_id = NULL;
+ struct options user_opts;
PVFS_credentials credentials;
+ /* Initialize any memory */
+ memset(&user_opts, 0, sizeof(user_opts));
+ memset(&credentials, 0, sizeof(credentials));
+
/* look at command line arguments */
- user_opts = parse_args(argc, argv);
- if(!user_opts)
+ ret = parse_args(argc, argv, &user_opts);
+ if(ret < 0)
+ {
+ fprintf(stderr, "Error: failed to parse command line arguments.\n");
+ return (-1);
+ }
+
+ /* Allocate space to hold the relative pvfs2 path & fs_id for each
+ * requested file
+ */
+ pvfs_path = (char **)calloc(user_opts.numdirs, sizeof(char *));
+
+ if(pvfs_path == NULL)
+ {
+ fprintf(stderr, "Unable to allocate memory\n");
+ return(-1);
+ }
+
+ for(i = 0; i < user_opts.numdirs; i++)
+ {
+ pvfs_path[i] = (char *)calloc(PVFS_NAME_MAX, sizeof(char));
+ if(pvfs_path[i] == NULL)
+ {
+ fprintf(stderr, "Unable to allocate memory\n");
+ return(-1);
+ }
+ }
+
+ /* Allocate enough space to hold file system id for each directory */
+ pfs_id = (PVFS_fs_id *)calloc(user_opts.numdirs, sizeof(PVFS_fs_id));
+
+ if(pfs_id == NULL)
{
- fprintf(stderr, "Error: failed to parse "
- "command line arguments.\n");
+ fprintf(stderr, "Unable to allocate memory\n");
return(-1);
}
@@ -61,108 +113,222 @@ int main(int argc, char **argv)
return(-1);
}
- /* translate local path into pvfs2 relative path */
- ret = PVFS_util_resolve(user_opts->destfile,
- &cur_fs, pvfs_path, PVFS_NAME_MAX);
+ /* Let's verify that all the given files reside on a PVFS2 filesytem */
+ for(i = 0; i < user_opts.numdirs; i++)
+ {
+ ret = PVFS_util_resolve(user_opts.dir_array[i],
+ &pfs_id[i],
+ pvfs_path[i],
+ PVFS_NAME_MAX);
+
if(ret < 0)
{
- PVFS_perror("PVFS_util_resolve", ret);
- ret = -1;
- goto main_out;
+ fprintf(stderr, "Error: could not find file system for %s\n",
+ user_opts.dir_array[i]);
+ PVFS_sys_finalize();
+ return(-1);
+ }
}
+ /* We will re-use the same credentials for each call */
PVFS_util_gen_credentials(&credentials);
- entry_name = str_buf;
- attr.owner = credentials.uid;
- attr.group = credentials.gid;
- attr.perms = PVFS2_translate_mode(0777 & ~PVFS_util_get_umask());
- attr.atime = time(NULL);
- attr.mtime = attr.atime;
- attr.ctime = attr.atime;
- attr.mask = (PVFS_ATTR_SYS_ALL_SETABLE);
-
- /* this if-else statement just pulls apart the pathname into its
- * parts....I think...this should be a function somewhere
- */
- if (strcmp(pvfs_path,"/") == 0)
+ for(i = 0; i < user_opts.numdirs; i++)
{
-
- memset(&resp_lookup, 0, sizeof(PVFS_sysresp_lookup));
- ret = PVFS_sys_lookup(cur_fs, pvfs_path,
- &credentials, &resp_lookup,
- PVFS2_LOOKUP_LINK_FOLLOW);
- if (ret < 0)
+ ret = make_directory(&credentials,
+ pfs_id[i],
+ user_opts.mode,
+ user_opts.dir_array[i],
+ pvfs_path[i],
+ user_opts.make_parent_dirs,
+ user_opts.verbose);
+ if(ret != 0)
{
- PVFS_perror("PVFS_sys_lookup", ret);
- ret = -1;
- goto main_out;
+ fprintf(stderr, "cannot create [%s]\n", user_opts.dir_array[i]);
+ status = -1;
}
- parent_ref.handle = resp_lookup.ref.handle;
- parent_ref.fs_id = resp_lookup.ref.fs_id;
+ }
+
+ /* TODO: need to free the request descriptions */
+ PVFS_sys_finalize();
+ /* Deallocate any allocated memory */
+ if(user_opts.dir_array != NULL)
+ {
+ free(user_opts.dir_array);
}
- else
+
+
+ if(pvfs_path != NULL)
{
- /* get the absolute path on the pvfs2 file system */
- if (PINT_remove_base_dir(pvfs_path,str_buf,PVFS_NAME_MAX))
+ for(i=0;i<user_opts.numdirs;i++)
{
- if (pvfs_path[0] != '/')
+ if(pvfs_path[i] != NULL)
{
- fprintf(stderr, "Error: poorly formatted path.\n");
+ free(pvfs_path[i]);
}
- fprintf(stderr, "Error: cannot retrieve entry name for "
- "creation on %s\n",
- pvfs_path);
- ret = -1;
- goto main_out;
}
- ret = PINT_lookup_parent(pvfs_path, cur_fs, &credentials,
- &parent_ref.handle);
- if(ret < 0)
+ free(pvfs_path);
+ }
+
+ if(pfs_id != NULL)
{
- PVFS_perror("PVFS_util_lookup_parent", ret);
- ret = -1;
- goto main_out;
+ free(pfs_id);
}
- else
+
+ return(status);
+}
+
+static int make_directory(PVFS_credentials * credentials,
+ const PVFS_fs_id fs_id,
+ const int mode,
+ const char * dir,
+ const char * pvfs_path,
+ const int make_parent_dirs,
+ const int verbose)
{
- parent_ref.fs_id = cur_fs;
+ int ret = 0;
+ char parent_dir[PVFS_NAME_MAX] = "";
+ char base[PVFS_NAME_MAX] = "";
+ char realpath[PVFS_NAME_MAX] = "";
+ char * parentdir_ptr = NULL;
+ char * basename_ptr = NULL;
+ PVFS_sys_attr attr;
+ PVFS_sysresp_lookup resp_lookup;
+ PVFS_object_ref parent_ref;
+ PVFS_sysresp_mkdir resp_mkdir;
+
+ /* Initialize any variables */
+ memset(&attr, 0, sizeof(attr));
+ memset(&resp_lookup, 0, sizeof(resp_lookup));
+ memset(&parent_ref, 0, sizeof(parent_ref));
+ memset(&resp_mkdir, 0, sizeof(resp_mkdir));
+
+ /* Copy the file name into structures to be passed to dirname and basename
+ * These calls change the parameter, so we don't want to mess with original
+ * TODO: We need to change the PINT_lookup_parent to a API call, and we
+ * need to change this to use it
+ */
+ strcpy(parent_dir, pvfs_path);
+ strcpy(base, pvfs_path);
+
+ parentdir_ptr = dirname(parent_dir);
+ basename_ptr = basename(base);
+
+ /* Make sure we don't try and create the root directory */
+ if( strcmp(basename_ptr, "/") == 0 )
+ {
+ fprintf(stderr, "directory exists\n");
+ return(-1);
}
+
+ /* Set the attributes for the new directory */
+ attr.owner = credentials->uid;
+ attr.group = credentials->gid;
+ attr.perms = mode;
+ attr.atime = time(NULL);
+ attr.mtime = attr.atime;
+ attr.ctime = attr.atime;
+ attr.mask = (PVFS_ATTR_SYS_ALL_SETABLE);
+
+ /* Clear out any info from previous calls */
+ memset(&resp_lookup, 0, sizeof(resp_lookup));
+
+ ret = PVFS_sys_lookup(fs_id,
+ parentdir_ptr,
+ credentials,
+ &resp_lookup,
+ PVFS2_LOOKUP_LINK_FOLLOW);
+
+ if( ret < 0 &&
+ !make_parent_dirs)
+ {
+ PVFS_perror("PVFS_sys_lookup", ret);
+ return(ret);
}
- memset(&resp_lookup, 0, sizeof(PVFS_sysresp_lookup));
- ret = PVFS_sys_ref_lookup(parent_ref.fs_id, entry_name,
- parent_ref, &credentials, &resp_lookup,
- PVFS2_LOOKUP_LINK_NO_FOLLOW);
- if (ret == 0)
+ if( ret < 0 &&
+ make_parent_dirs &&
+ ret != -PVFS_ENOENT)
{
- fprintf(stderr, "Target '%s' already exists!\n", entry_name);
- ret = -1;
- goto main_out;
+ PVFS_perror("PVFS_sys_lookup", ret);
+ return(ret);
}
- memset(&resp_mkdir, 0, sizeof(PVFS_sysresp_mkdir));
+ /* The parent directory did not exist. Let's create the parent directory */
+ if(ret == -PVFS_ENOENT &&
+ make_parent_dirs)
+ {
+ strcpy(parent_dir, pvfs_path);
+ strcpy(realpath, dir);
+
+ ret = make_directory(credentials,
+ fs_id,
+ mode,
+ dirname(realpath),
+ dirname(parent_dir),
+ make_parent_dirs,
+ verbose);
- ret = PVFS_sys_mkdir(entry_name,parent_ref,attr,
- &credentials,&resp_mkdir);
- if (ret < 0) {
- PVFS_perror("PVFS_sys_mkdir", ret);
- ret = -1;
- goto main_out;
+ if(ret == 0)
+ {
+ ret = PVFS_sys_lookup(fs_id,
+ parentdir_ptr,
+ credentials,
+ &resp_lookup,
+ PVFS2_LOOKUP_LINK_FOLLOW);
+
+ if(ret < 0)
+ {
+ PVFS_perror("PVFS_sys_lookup", ret);
+ return(ret);
+ }
+ }
+ else
+ {
+ return(ret);
+ }
}
- /* TODO: need to free the request descriptions */
- ret = 0;
+ parent_ref.handle = resp_lookup.ref.handle;
+ parent_ref.fs_id = resp_lookup.ref.fs_id;
-main_out:
+ /* Clear out any info from previous calls */
+ memset(&resp_mkdir, 0, sizeof(PVFS_sysresp_mkdir));
- PVFS_sys_finalize();
+ if(verbose)
+ {
+ fprintf(stderr, "Creating Directory\n");
+ fprintf(stderr, "\t basename_ptr = [%s]\n", basename_ptr);
+ fprintf(stderr, "\t fs_id = [%d]\n", fs_id);
+ fprintf(stderr, "\t Mode = [%o]\n", mode);
+ fprintf(stderr, "\t DirName = [%s]\n", dir);
+ fprintf(stderr, "\t pvfs path = [%s]\n", pvfs_path);
+
+ fprintf(stdout, "Directory Attributes\n");
+ fprintf(stdout, "\t owner [%d]\n", attr.owner);
+ fprintf(stdout, "\t group [%d]\n", attr.group);
+ fprintf(stdout, "\t perms [%o]\n", attr.perms);
+ fprintf(stdout, "\t atime [%Lu]\n", Lu(attr.atime));
+ fprintf(stdout, "\t mtime [%Lu]\n", Lu(attr.mtime));
+ fprintf(stdout, "\t ctime [%Lu]\n", Lu(attr.ctime));
+ }
+
+ ret = PVFS_sys_mkdir(basename_ptr,
+ parent_ref,
+ attr,
+ credentials,
+ &resp_mkdir);
+ if (ret < 0)
+ {
+ PVFS_perror("PVFS_sys_mkdir", ret);
return(ret);
}
+ return(0);
+}
/* parse_args()
*
@@ -170,55 +336,195 @@ main_out:
*
* returns pointer to options structure on success, NULL on failure
*/
-static struct options* parse_args(int argc, char* argv[])
+static int parse_args(int argc, char** argv, struct options * opts)
+{
+ int i = 0, ret = 0,option_index = 0, mode_requested = 0;
+ char * cur_option = NULL;
+ char flags[] = "hm:pvV"; /* Options available on command line */
+
+ static struct option long_opts[] =
+ {
+ {"help",0,0,0},
+ {"version",0,0,0},
+ {"verbose",0,0,0},
+ {"mode",1,0,0},
+ {0,0,0,0}
+ };
+
+ while((ret = getopt_long_only(argc, argv, flags, long_opts, &option_index)) != -1)
+ {
+ switch (ret)
+ {
+ case 0:
+ cur_option = (char*)long_opts[option_index].name;
+
+ if(strcmp("help", cur_option) == 0)
{
- /* getopt stuff */
- extern char* optarg;
- extern int optind, opterr, optopt;
- char flags[] = "vs:n:b:";
- int one_opt = 0;
-
- struct options* tmp_opts = NULL;
-
- /* create storage for the command line options */
- tmp_opts = (struct options*)malloc(sizeof(struct options));
- if(!tmp_opts){
- return(NULL);
+ usage(argc, argv);
+ exit(0);
+ }
+ else if(strcmp("verbose", cur_option) == 0)
+ {
+ enable_verbose(opts);
+ }
+ else if(strcmp("parents", cur_option) == 0)
+ {
+ enable_parents(opts);
}
- memset(tmp_opts, 0, sizeof(struct options));
+ else if (strcmp("version", cur_option) == 0)
+ {
+ printf("%s\n", PVFS2_VERSION);
+ exit(0);
+ }
+ else if(strcmp("mode", cur_option) == 0)
+ {
+ ret = read_mode(opts, optarg);
+ if(ret == 0)
+ {
+ fprintf(stderr, "Unable to read mode argument\n");
+ usage(argc, argv);
+ return(-1);
+ }
+ mode_requested = 1;
+ }
+ else
+ {
+ usage(argc, argv);
+ return -1;
+ }
+ break;
- /* look at command line arguments */
- while((one_opt = getopt(argc, argv, flags)) != EOF)
+ case 'h': /* --help */
+ usage(argc, argv);
+ exit(0);
+ break;
+
+ case 'm': /* --mode */
+ ret = read_mode(opts, optarg);
+ if(ret == 0)
{
- switch(one_opt){
- case('v'):
+ fprintf(stderr, "Unable to read mode argument\n");
+ usage(argc, argv);
+ return(-1);
+ }
+ mode_requested = 1;
+ break;
+
+ case 'p': /* --parents */
+ enable_parents(opts);
+ break;
+
+ case 'V': /* --verbose */
+ enable_verbose(opts);
+ break;
+
+ case 'v': /* --version */
printf("%s\n", PVFS2_VERSION);
exit(0);
- case('?'):
+ break;
+
+ case '?':
usage(argc, argv);
- exit(EXIT_FAILURE);
+ return -1;
+
+ default:
+ usage(argc, argv);
+ return -1;
}
}
- if(optind != (argc - 1))
+ /* We processed all arguments, so let's figure out how many directories the
+ * user wants to create, and allocate enough space to hold them, barring
+ * they haven't exceeded the limit.
+ */
+ opts->numdirs = argc - optind;
+
+ /* Validation to make sure we have at least one directory to check */
+ if(opts->numdirs <= 0)
{
+ fprintf(stderr, "No directories specified(s)\n");
usage(argc, argv);
- exit(EXIT_FAILURE);
+ return(-1);
}
- /* TODO: should probably malloc and copy instead */
- tmp_opts->destfile = argv[argc-1];
+ /* Validation to make sure we haven't exceeded */
+ if(opts->numdirs > MAX_NUM_DIRECTORIES)
+ {
+ fprintf(stderr, "Directory limit of [%d] exceeded. [%d] directories entered\n",
+ MAX_NUM_DIRECTORIES,
+ opts->numdirs);
+ usage(argc, argv);
+ return(-1);
+ }
- return(tmp_opts);
+ /* Assign a default mode if one is not given */
+ if(!mode_requested)
+ {
+ mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU; /* 0777 */
+ opts->mode = PVFS2_translate_mode(mode & ~PVFS_util_get_umask());
}
+ /* Allocate memory to hold the filenames */
+ opts->dir_array = (char **)calloc(opts->numdirs, sizeof(char *));
+
+ if(opts->dir_array == NULL)
+ {
+ fprintf(stderr, "Memory allocation failed\n");
+ return(-1);
+ }
+
+ /* Loop through arguments and capture the directory names */
+ for(i = optind; i < argc; i++)
+ {
+ opts->dir_array[i-optind] = argv[i];
+ }
+
+ if(opts->verbose)
+ {
+ fprintf(stdout, "Options Specified\n");
+ fprintf(stdout, "\t Verbose [%d]\n", opts->verbose);
+ fprintf(stdout, "\t Mode [%o]\n", opts->mode);
+ fprintf(stdout, "\t Num Dirs [%d]\n", opts->numdirs);
+ for(i=0; i<opts->numdirs; i++)
+ {
+ fprintf(stdout, "\t Direcotory #%d = [%s]\n", i, opts->dir_array[i]);
+ }
+ }
+ return(0);
+}
static void usage(int argc, char** argv)
{
- fprintf(stderr,"Usage: %s pvfs2_directory\n",argv[0]);
+ fprintf(stderr, "Usage: %s [OPTION] DIRECTORY\n", argv[0]);
+ fprintf(stderr, "Create the DIRECTORY(ies), if they do not already exist.\n\n");
+
+ fprintf(stderr," -m, --mode set permission mode (as in chmod), "
+ "not rwxrwxrwx - umask\n");
+ fprintf(stderr," -p, --parents make parent directories as needed\n");
+ fprintf(stderr," -V, --verbose turns on verbose messages\n");
+ fprintf(stderr," -v, --version output version information and exit\n");
+ fprintf(stderr," -h, --help print help\n");
return;
}
+static void enable_verbose(struct options * opts)
+{
+ opts->verbose = 1;
+}
+
+static void enable_parents(struct options * opts)
+{
+ opts->make_parent_dirs = 1;
+}
+
+static int read_mode(struct options * opts, const char * buffer)
+{
+ int ret = 0;
+
+ ret = sscanf(buffer, "%o", &opts->mode);
+
+ return(ret);
+}
/*
* Local variables:
@@ -228,4 +534,3 @@ static void usage(int argc, char** argv)
*
* vim: ts=8 sts=4 sw=4 expandtab
*/
-
More information about the PVFS2-CVS
mailing list