root/trunk/src/apps/admin/pvfs2-mkdir.c @ 7471

Revision 7471, 15.1 KB (checked in by slang, 5 years ago)

merging hints/events code into trunk.

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