root/branches/Orange-Elaine-Distr-Dir-Branch/src/apps/admin/pvfs2-mkdir.c @ 8648

Revision 8648, 17.4 KB (checked in by shuangy, 2 years ago)

1. add >InitNumDirdataHandles?< field to fs_config and default value set to 2. 2. add command line options >-n, --init-num-dirdata< to pvfs2-mkdir to set initial number of dirdata handles for a directory. (not yet applied to kernel module.)

Line 
1/*
2 * (C) 2004 Clemson University and The University of Chicago
3 *
4 * Changes by Acxiom Corporation to add support for mode, multiple directory
5 * creation, and parent creation.
6 * Copyright Acxiom Corporation, 2005.
7 *
8 * See COPYING in top-level directory.
9 */
10
11#include <unistd.h>
12#include <stdio.h>
13#include <errno.h>
14#include <string.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17#include <sys/time.h>
18#include <time.h>
19#include <stdlib.h>
20#include <getopt.h>
21#include <libgen.h>
22
23#include "pvfs2.h"
24#include "str-utils.h"
25#include "pint-sysint-utils.h"
26#include "pvfs2-internal.h"
27
28#ifndef PVFS2_VERSION
29#define PVFS2_VERSION "Unknown"
30#endif
31
32/* We need to set some limit, I suppose */
33#define MAX_NUM_DIRECTORIES 100
34
35/* optional parameters, filled in by parse_args() */
36struct options
37{
38    char ** dir_array;  /* array of directories to create */
39    int     numdirs; /* number of directories to create */
40    int     mode;    /* mode of directories */
41    int     init_num_dirdata; /* init num of dirdata handles */
42    int     verbose;
43    int     make_parent_dirs; /* Create missing parents */
44};
45
46/* Function Prototypes */
47static void usage(int argc, char** argv);
48static int parse_args(int argc, char** argv, struct options * opts);
49static void enable_verbose(struct options * opts);
50static void enable_parents(struct options * opts);
51static int read_mode(struct options * opts, const char * buffer);
52static int read_init_num_dirdata(struct options * opts, const char * buffer);
53static int make_directory(PVFS_credentials     * credentials,
54                          const PVFS_fs_id       fs_id,
55                          const int              mode,
56                          const int              init_num_dirdata,
57                          const char           * dir,
58                          const char           * pvfs_path,
59                          const int              make_parent_dirs,
60                          const int              verbose);
61
62int main(int argc, char **argv)
63{
64    int ret = -1, status = 0; /* Get's set if error */
65    int i = 0;
66    char           **pvfs_path = NULL;
67    PVFS_fs_id      *pfs_id = NULL;
68    struct options   user_opts;
69    PVFS_credentials credentials;
70
71    /* Initialize any memory */
72    memset(&user_opts,   0, sizeof(user_opts));
73    memset(&credentials, 0, sizeof(credentials));
74   
75    /* look at command line arguments */
76    ret = parse_args(argc, argv, &user_opts);
77    if(ret < 0)
78    {
79        fprintf(stderr, "Error: failed to parse command line arguments.\n");
80        return (-1);
81    }
82
83    /* Allocate space to hold the relative pvfs2 path & fs_id for each
84     * requested file
85     */
86    pvfs_path = (char **)calloc(user_opts.numdirs, sizeof(char *));
87
88    if(pvfs_path == NULL)
89    {
90        fprintf(stderr, "Unable to allocate memory\n");
91        return(-1);
92    }
93
94    for(i = 0; i < user_opts.numdirs; i++)
95    {
96        pvfs_path[i] = (char *)calloc(PVFS_NAME_MAX, sizeof(char));
97        if(pvfs_path[i] == NULL)
98        {
99            fprintf(stderr, "Unable to allocate memory\n");
100            return(-1);
101        }
102    }
103
104    /* Allocate enough space to hold file system id for each directory */
105    pfs_id = (PVFS_fs_id *)calloc(user_opts.numdirs, sizeof(PVFS_fs_id));
106
107    if(pfs_id == NULL)
108    {
109        fprintf(stderr, "Unable to allocate memory\n");
110        return(-1);
111    }
112 
113    ret = PVFS_util_init_defaults();
114    if (ret < 0)
115    {
116        PVFS_perror("PVFS_util_init_defaults", ret);
117        return (-1);
118    }
119
120    /* Let's verify that all the given files reside on a PVFS2 filesytem */
121    for(i = 0; i < user_opts.numdirs; i++)
122    {
123        ret = PVFS_util_resolve(user_opts.dir_array[i],
124                                &pfs_id[i],
125                                pvfs_path[i],
126                                PVFS_NAME_MAX);
127 
128        if (ret < 0)
129        {
130            fprintf(stderr, "Error: could not find file system for %s\n",
131                    user_opts.dir_array[i]);
132            PVFS_sys_finalize();
133            return(-1);
134       }
135    }
136
137    /* We will re-use the same credentials for each call */
138    PVFS_util_gen_credentials(&credentials);
139
140    for(i = 0; i < user_opts.numdirs; i++)
141    {
142        ret = make_directory(&credentials,
143                             pfs_id[i],
144                             user_opts.mode,
145                             user_opts.init_num_dirdata,
146                             user_opts.dir_array[i],
147                             pvfs_path[i],
148                             user_opts.make_parent_dirs,
149                             user_opts.verbose);
150        if(ret != 0)
151        {
152            fprintf(stderr, "cannot create [%s]\n", user_opts.dir_array[i]);
153            status = -1;
154        }
155    }
156
157    /* TODO: need to free the request descriptions */
158    PVFS_sys_finalize();
159
160    /* Deallocate any allocated memory */
161    if(user_opts.dir_array != NULL)
162    {
163        free(user_opts.dir_array);
164    }
165   
166   
167    if(pvfs_path != NULL)
168    {
169        for(i=0;i<user_opts.numdirs;i++)
170        {
171            if(pvfs_path[i] != NULL)
172            {
173                free(pvfs_path[i]);
174            }
175        }
176   
177        free(pvfs_path);
178    }
179   
180    if(pfs_id != NULL)
181    {
182        free(pfs_id);
183    }
184   
185    return(status);
186}
187
188static int make_directory(PVFS_credentials     * credentials,
189                          const PVFS_fs_id       fs_id,
190                          const int              mode,
191                          const int              init_num_dirdata,
192                          const char           * dir,
193                          const char           * pvfs_path,
194                          const int              make_parent_dirs,
195                          const int              verbose)
196{
197    int ret = 0;
198    char parent_dir[PVFS_NAME_MAX] = "";
199    char base[PVFS_NAME_MAX]  = "";
200    char realpath[PVFS_NAME_MAX]  = "";
201    char * parentdir_ptr = NULL;
202    char * basename_ptr = NULL;
203    PVFS_sys_attr       attr;
204    PVFS_sysresp_lookup resp_lookup;
205    PVFS_object_ref     parent_ref;
206    PVFS_sysresp_mkdir  resp_mkdir;
207
208    /* Initialize any variables */
209    memset(&attr,        0, sizeof(attr));
210    memset(&resp_lookup, 0, sizeof(resp_lookup));
211    memset(&parent_ref,  0, sizeof(parent_ref));
212    memset(&resp_mkdir,  0, sizeof(resp_mkdir));
213
214    /* Copy the file name into structures to be passed to dirname and basename
215    * These calls change the parameter, so we don't want to mess with original
216    * TODO: We need to change the PINT_lookup_parent to a API call, and we 
217    * need to change this to use it
218    */
219    strcpy(parent_dir, pvfs_path);
220    strcpy(base,  pvfs_path);
221   
222    parentdir_ptr = dirname(parent_dir);
223    basename_ptr  = basename(base);
224       
225    /* Make sure we don't try and create the root directory */
226    if( strcmp(basename_ptr, "/") == 0 )
227    {
228        fprintf(stderr, "directory exists\n");
229        return(-1);
230    }
231   
232    /* Set the attributes for the new directory */
233    attr.owner = credentials->uid;
234    attr.group = credentials->gid;
235    attr.perms = mode;
236    attr.mask = (PVFS_ATTR_SYS_ALL_SETABLE);
237    /* sys_attr.dirdata_count is meant to be the total number of dirdata handles.
238     * introduced for pvfs2_fs_dump & pvfs2_fsck.
239     * here it's used to pass the initial number of dirdata handles
240     */
241    attr.dirdata_count = init_num_dirdata;
242       
243    /* Clear out any info from previous calls */
244    memset(&resp_lookup,  0, sizeof(resp_lookup));
245
246    ret = PVFS_sys_lookup(fs_id,
247                          parentdir_ptr,
248                          credentials,
249                          &resp_lookup,
250                          PVFS2_LOOKUP_LINK_FOLLOW, NULL);
251
252    if( ret < 0 &&
253        !make_parent_dirs)
254    {
255        PVFS_perror("PVFS_sys_lookup", ret);
256        return(ret);
257    }
258
259    if( ret < 0         &&
260        make_parent_dirs &&
261        ret != -PVFS_ENOENT)
262    {
263        PVFS_perror("PVFS_sys_lookup", ret);
264        return(ret);
265    }
266   
267    /* The parent directory did not exist. Let's create the parent directory */
268    if(ret == -PVFS_ENOENT &&
269       make_parent_dirs)
270    {
271        strcpy(parent_dir, pvfs_path);
272        strcpy(realpath,  dir);
273
274        ret = make_directory(credentials,
275                             fs_id,
276                             mode,
277                             init_num_dirdata,
278                             dirname(realpath),
279                             dirname(parent_dir),
280                             make_parent_dirs,
281                             verbose);
282                             
283        if(ret == 0)
284        {
285            ret = PVFS_sys_lookup(fs_id,
286                                  parentdir_ptr,
287                                  credentials,
288                                  &resp_lookup,
289                                  PVFS2_LOOKUP_LINK_FOLLOW, NULL);
290       
291            if(ret < 0)
292            {
293                PVFS_perror("PVFS_sys_lookup", ret);
294                return(ret);
295            }
296        }
297        else
298        {
299            return(ret);
300        }
301    }
302   
303    parent_ref.handle = resp_lookup.ref.handle;
304    parent_ref.fs_id  = resp_lookup.ref.fs_id;
305
306    /* Clear out any info from previous calls */
307    memset(&resp_mkdir, 0, sizeof(PVFS_sysresp_mkdir));
308
309    if(verbose)
310    {
311        fprintf(stderr, "Creating Directory\n");
312        fprintf(stderr, "\t basename_ptr    = [%s]\n", basename_ptr);
313        fprintf(stderr, "\t fs_id           = [%d]\n", fs_id);
314        fprintf(stderr, "\t Mode            = [%o]\n", mode);
315        fprintf(stderr, "\t InitNumDirdata  = [%d]\n", init_num_dirdata);
316        fprintf(stderr, "\t DirName         = [%s]\n", dir);
317        fprintf(stderr, "\t pvfs path       = [%s]\n", pvfs_path);
318
319        fprintf(stdout, "Directory Attributes\n");
320        fprintf(stdout, "\t owner [%d]\n",  attr.owner);
321        fprintf(stdout, "\t group [%d]\n",  attr.group);
322        fprintf(stdout, "\t perms [%o]\n",  attr.perms);
323    }
324
325    ret = PVFS_sys_mkdir(basename_ptr,
326                         parent_ref,
327                         attr,
328                         credentials,
329                         &resp_mkdir, NULL);
330
331    if (ret < 0)
332    {
333        PVFS_perror("PVFS_sys_mkdir", ret);
334        return(ret);
335    }
336   
337    return(0);
338}
339
340/* parse_args()
341 *
342 * parses command line arguments
343 *
344 * returns pointer to options structure on success, NULL on failure
345 */
346static int parse_args(int argc, char** argv, struct options * opts)
347{
348    int i = 0, ret = 0,option_index = 0, mode_requested = 0;
349    int init_num_dirdata_requested = 0;
350    const char * cur_option = NULL;
351    char flags[] = "hm:n:pvV";  /* Options available on command line */
352
353    static struct option long_opts[] =
354    {
355        {"help",0,0,0},
356        {"version",0,0,0},
357        {"verbose",0,0,0},
358        {"mode",1,0,0},
359        {"init-num-dirdata",1,0,0},
360        {0,0,0,0}
361    };
362
363    while((ret = getopt_long_only(argc, argv, flags, long_opts, &option_index)) != -1)
364    {
365        switch (ret)
366        {
367            case 0:
368                cur_option = long_opts[option_index].name;
369   
370                if(strcmp("help", cur_option) == 0)
371                {
372                    usage(argc, argv);
373                    exit(0);
374                }
375                else if(strcmp("verbose", cur_option) == 0)
376                {
377                    enable_verbose(opts);
378                }
379                else if(strcmp("parents", cur_option) == 0)
380                {
381                    enable_parents(opts);
382                }
383                else if (strcmp("version", cur_option) == 0)
384                {
385                    printf("%s\n", PVFS2_VERSION);
386                    exit(0);
387                }
388                else if(strcmp("mode", cur_option) == 0)
389                {
390                    ret = read_mode(opts, optarg);
391                    if(ret == 0)
392                    {
393                        fprintf(stderr, "Unable to read mode argument\n");
394                        usage(argc, argv);
395                        return(-1);
396                    }
397                    mode_requested = 1;
398                }
399                else if(strcmp("init-num-dirdata", cur_option) == 0)
400                {
401                    ret = read_init_num_dirdata(opts, optarg);
402                    if(ret == 0)
403                    {
404                        fprintf(stderr, "Unable to read initial number of dirdata handles\n");
405                        usage(argc, argv);
406                        return(-1);
407                    }
408                    init_num_dirdata_requested = 1;
409                }
410                else
411                {
412                    usage(argc, argv);
413                    return -1;
414                }
415                break;
416
417            case 'h': /* --help */
418                usage(argc, argv);
419                exit(0);
420                break;
421
422            case 'm': /* --mode */
423                ret = read_mode(opts, optarg);
424                if(ret == 0)
425                {
426                    fprintf(stderr, "Unable to read mode argument\n");
427                    usage(argc, argv);
428                    return(-1);
429                }
430                mode_requested = 1;
431                break;
432
433            case 'n': /* --init-num-dirdata */
434                ret = read_init_num_dirdata(opts, optarg);
435                if(ret == 0)
436                {
437                    fprintf(stderr, "Unable to read initial number of dirdata handles\n");
438                    usage(argc, argv);
439                    return(-1);
440                }
441                init_num_dirdata_requested = 1;
442                break;
443
444            case 'p': /* --parents */
445                enable_parents(opts);
446                break;
447
448            case 'V': /* --verbose */
449                enable_verbose(opts);
450                break;
451                   
452            case 'v': /* --version */
453                printf("%s\n", PVFS2_VERSION);
454                exit(0);
455                break;
456
457            case '?':
458                usage(argc, argv);
459                return -1;
460           
461            default:
462                usage(argc, argv);
463                return -1;
464        }
465    }
466
467    /* We processed all arguments, so let's figure out how many directories the
468     * user wants to create, and allocate enough space to hold them, barring
469     * they haven't exceeded the limit.
470     */
471    opts->numdirs = argc - optind;
472
473    /* Validation to make sure we have at least one directory to check */
474    if(opts->numdirs <= 0)
475    {
476       fprintf(stderr, "No directories specified(s)\n");
477       usage(argc, argv);
478       return(-1);
479    }
480 
481    /* Validation to make sure we haven't exceeded */
482    if(opts->numdirs > MAX_NUM_DIRECTORIES)
483    {
484       fprintf(stderr, "Directory limit of [%d] exceeded. [%d] directories entered\n",
485               MAX_NUM_DIRECTORIES,
486               opts->numdirs);
487       usage(argc, argv);
488       return(-1);
489    }
490
491    /* Assign a default mode if one is not given */
492    if(!mode_requested)
493    {
494        mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU; /* 0777 */
495        opts->mode = PVFS_util_translate_mode(mode & ~PVFS_util_get_umask(), 0);
496    }
497   
498    if(!init_num_dirdata_requested)
499    {
500        opts->init_num_dirdata = 0;
501    }
502    else if(opts->init_num_dirdata <=0 )
503    {
504        fprintf(stderr, "init-num-dirdata has to be a positive integer!\n");
505        usage(argc, argv);
506        return(-1);
507    }
508
509    /* Allocate memory to hold the filenames */
510    opts->dir_array = (char **)calloc(opts->numdirs, sizeof(char *));
511 
512    if(opts->dir_array == NULL)
513    {
514       fprintf(stderr, "Memory allocation failed\n");
515       return(-1);
516    }
517
518    /* Loop through arguments and capture the directory names */
519    for(i = optind; i < argc; i++)
520    {
521       opts->dir_array[i-optind] = argv[i];
522    }
523
524    if(opts->verbose)
525    {
526        fprintf(stdout, "Options Specified\n");
527        fprintf(stdout, "\t Verbose             [%d]\n", opts->verbose);
528        fprintf(stdout, "\t Mode                [%o]\n", opts->mode);
529        fprintf(stdout, "\t Init Num Dirdata    [%d]\n", opts->init_num_dirdata);
530        fprintf(stdout, "\t Num Dirs            [%d]\n", opts->numdirs);
531        for(i=0; i<opts->numdirs; i++)
532        {
533            fprintf(stdout, "\t Direcotory #%d = [%s]\n", i, opts->dir_array[i]);
534        }   
535    }
536    return(0);
537}
538
539static void usage(int argc, char **argv)
540{
541    fprintf(stderr, "Usage: %s [OPTION] DIRECTORY\n", argv[0]);
542    fprintf(stderr, "Create the DIRECTORY(ies), if they do not already exist.\n\n");
543
544    fprintf(stderr,"  -m, --mode                set permission mode (as in chmod), "
545                                                "not rwxrwxrwx - umask\n");
546    fprintf(stderr,"  -n, --init-num-dirdata    set initial number of dirdata handles for the directory,\n");
547    fprintf(stderr,"  -p, --parents             make parent directories as needed\n");
548    fprintf(stderr,"  -V, --verbose             turns on verbose messages\n");
549    fprintf(stderr,"  -v, --version             output version information and exit\n");
550    fprintf(stderr,"  -h, --help                print help\n");
551    return;
552}
553
554static void enable_verbose(struct options * opts)
555{
556   opts->verbose = 1; 
557}
558
559static void enable_parents(struct options * opts)
560{
561   opts->make_parent_dirs = 1; 
562}
563
564static int read_mode(struct options * opts, const char * buffer)
565{
566    int ret = 0;
567   
568    ret = sscanf(buffer, "%o", &opts->mode);
569   
570    return(ret);
571}
572
573static int read_init_num_dirdata(struct options * opts, const char * buffer)
574{
575    int ret = 0;
576   
577    ret = sscanf(buffer, "%d", &opts->init_num_dirdata);
578   
579    return(ret);
580}
581
582/*
583 * Local variables:
584 *  c-indent-level: 4
585 *  c-basic-offset: 4
586 * End:
587 *
588 * vim: ts=8 sts=4 sw=4 expandtab
589 */
Note: See TracBrowser for help on using the browser.