[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