/* * Copyright (c) 1992, Brian Berliner and Jeff Polk * Copyright (c) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License as * specified in the README file that comes with the CVS 1.4 kit. * * lsacl * * Shows the current permissions */ #include "cvs.h" #include "fileattr.h" static int is_rlsacl; static const char *const lsacl_usage[] = { "Usage: %s %s [-d] [-R] [file or directory...]\n", "\t-d\tShow directories only\n", "\t-R\tRecurse unto subdirectories\n", NULL }; static const char *const rlsacl_usage[] = { "Usage: %s %s [-d] [-R] [module...]\n", "\t-d\tShow directories only\n", "\t-R\tRecurse unto subdirectories\n", NULL }; static Dtype lsacl_dirproc (void *callerdat, char *dir, char *repos, char *update_dir, List *entries, const char *virtual_repository, Dtype hint); static int lsacl_fileproc(void *callerdat, struct file_info *finfo); static int rlsacl_proc(int argc, char **argv, const char *xwhere, const char *mwhere, const char *mfile, int shorten, int local_specified, const char *mname, const char *msg); int lsacl (int argc, char **argv) { int c; int err = 0; int local = 1; int directories_only = 0; is_rlsacl = !strcmp(command_name,"rlsacl"); if (argc == -1) usage (is_rlsacl?rlsacl_usage:lsacl_usage); optind = 0; while ((c = getopt(argc, argv, "+dR")) != -1) { switch (c) { case 'd': directories_only = 1; break; case 'R': local = 0; break; case '?': default: usage (lsacl_usage); break; } } argc -= optind; argv += optind; if (argc < 0) usage (is_rlsacl?rlsacl_usage:lsacl_usage); if (current_parsed_root->isremote) { if(is_rlsacl) { if (!supported_request ("rlsacl")) error (1, 0, "server does not support rlsacl"); } else { if (!supported_request ("lsacl")) error (1, 0, "server does not support lsacl"); } if(!local) send_arg("-R"); if(directories_only) send_arg("-d"); send_arg("--"); if (is_rlsacl) { int i; for (i = 0; i < argc; i++) send_arg (argv[i]); send_to_server ("rlsacl\n", 0); } else { send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("lsacl\n", 0); } return get_responses_and_close (); } if(!acl_mode) error(1,0,"Access control is disabled on this repository."); if (is_rlsacl) { DBM *db; int i; db = open_module (); if(!argc) { err += do_module (db, ".", MISC, "Listing", rlsacl_proc, (char *) NULL, 0, local, 0, 0, (char *) NULL); } else { for (i = 0; i < argc; i++) { err += do_module (db, argv[i], MISC, "Listing", rlsacl_proc, (char *) NULL, 0, local, 0, 0, (char *) NULL); } } close_module (db); } else { /* start the recursion processor */ err = start_recursion (directories_only?NULL:lsacl_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, lsacl_dirproc, (DIRLEAVEPROC) NULL, NULL, argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, NULL, 1, NULL); } return (err); } static void acl_details(XmlHandle_t acl,const char *type) { XmlHandle_t h=fileattr_find(acl,type); const char *d,*i; if(h) { d=fileattr_getvalue(h,"@deny"); i=fileattr_getvalue(h,"@inherit"); if(!strcmp(type,"all") && (d && atoi(d))) { type="none"; d=NULL; } printf("\t%s",type); if((d && atoi(d)) || (i && !atoi(i))) { printf("("); if(d && atoi(d)) { printf("deny"); if(i && atoi(i)) printf(","); } if(i&&atoi(i)) { printf("noinherit"); } printf(")"); } printf("\n"); } } static void show_acl(XmlHandle_t acl) { while(acl) { const char *user = fileattr_getvalue(acl,"@user"); const char *branch = fileattr_getvalue(acl,"@branch"); const char *merge = fileattr_getvalue(acl,"@merge"); const char *priority = fileattr_getvalue(acl,"@priority"); const char *message = fileattr_getvalue(acl,"message"); const char *comma=""; printf("\n"); if(user) { printf("user=%s",user); comma=","; } if(branch) { printf("%sbranch=%s",comma,branch); comma=","; } if(merge) { printf("%smerge=%s",comma,merge); } if(!user && !branch && !merge) printf(""); if(priority) printf(",priority=%s",priority); if(message) printf(",message=%s",message); printf("\n"); acl_details(acl,"all"); acl_details(acl,"read"); acl_details(acl,"write"); acl_details(acl,"create"); acl_details(acl,"tag"); acl_details(acl,"control"); acl = fileattr_next(acl); } } /* * Show file ACL */ static Dtype lsacl_dirproc (void *callerdat, char *dir, char *repos, char *update_dir, List *entries, const char *virtual_repository, Dtype hint) { const char *owner; XmlHandle_t acl; if(hint!=R_PROCESS) return hint; owner = fileattr_getvalue(NULL,"directory/owner"); if(is_rlsacl && !strcmp(update_dir,".")) update_dir=""; printf("Directory: %s\n",update_dir); printf("Owner: %s\n",(owner&&*owner)?owner:""); acl = fileattr_find(NULL,"directory/acl"); show_acl(acl); return R_PROCESS; } int lsacl_fileproc(void *callerdat, struct file_info *finfo) { XmlHandle_t acl; acl = fileattr_find(NULL,"file[@name=F'%s']/acl",finfo->file); if(acl) { printf("File: %s\n",finfo->file); show_acl(acl); } return 0; } static int rlsacl_proc(int argc, char **argv, const char *xwhere, const char *mwhere, const char *mfile, int shorten, int local_specified, const char *mname, const char *msg) { /* Begin section which is identical to patch_proc--should this be abstracted out somehow? */ char *myargv[2]; int err = 0; char *repository, *mapped_repository; char *where; repository = (char*)xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); where = (char*)xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) + 1); (void) strcpy (where, argv[0]); /* if mfile isn't null, we need to set up to do only part of the module */ if (mfile != NULL) { char *cp; char *path; /* if the portion of the module is a path, put the dir part on repos */ if ((cp = strrchr (mfile, '/')) != NULL) { *cp = '\0'; (void) strcat (repository, "/"); (void) strcat (repository, mfile); (void) strcat (where, "/"); (void) strcat (where, mfile); mfile = cp + 1; } /* take care of the rest */ path = (char*)xmalloc (strlen (repository) + strlen (mfile) + 5); (void) sprintf (path, "%s/%s", repository, mfile); if (isdir (path)) { /* directory means repository gets the dir tacked on */ (void) strcpy (repository, path); (void) strcat (where, "/"); (void) strcat (where, mfile); } else { myargv[0] = argv[0]; myargv[1] = (char*)mfile; argc = 2; argv = myargv; } xfree (path); } mapped_repository = map_repository(repository); /* cd to the starting repository */ if ( CVS_CHDIR (mapped_repository) < 0) { error (0, errno, "cannot chdir to %s", fn_root(repository)); xfree (repository); xfree (mapped_repository); return (1); } xfree (repository); /* End section which is identical to patch_proc. */ err = start_recursion (lsacl_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, lsacl_dirproc, (DIRLEAVEPROC) NULL, NULL, argc - 1, argv + 1, local_specified, W_REPOS, 0, 1, where, mapped_repository, 1, NULL); xfree (mapped_repository); return err; }