int diff (int argc, char **argv) { char tmp[50]; int c, err = 0; int local = 0; int which; int option_index; is_rcs = (strcmp (command_name, "rcsfile") == 0); if (argc == -1) usage (diff_usage); have_rev1_label = have_rev2_label = 0; /* * Note that we catch all the valid arguments here, so that we can * intercept the -r arguments for doing revision diffs; and -l/-R for a * non-recursive/recursive diff. */ /* Clean out our global variables (multiroot can call us multiple times and the server can too, if the client sends several diff commands). */ if (opts == NULL) { opts_allocated = 1; opts = (char*)xmalloc (opts_allocated); } opts[0] = '\0'; diff_rev1 = NULL; diff_rev2 = NULL; diff_date1 = NULL; diff_date2 = NULL; optind = 0; while ((c = getopt_long (argc, argv, "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:", longopts, &option_index)) != -1) { switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'i': case 'n': case 'p': case 's': case 't': case 'u': case 'w': case 'y': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'B': case 'H': case 'T': (void) sprintf (tmp, " -%c", (char) c); allocate_and_strcat (&opts, &opts_allocated, tmp); break; case 'L': if (have_rev1_label++) if (have_rev2_label++) { error (0, 0, "extra -L arguments ignored"); break; } allocate_and_strcat (&opts, &opts_allocated, " -L"); allocate_and_strcat (&opts, &opts_allocated, optarg); break; case 'C': case 'F': case 'I': case 'U': case 'V': case 'W': (void) sprintf (tmp, " -%c", (char) c); allocate_and_strcat (&opts, &opts_allocated, tmp); allocate_and_strcat (&opts, &opts_allocated, optarg); break; case 131: /* --ifdef. */ allocate_and_strcat (&opts, &opts_allocated, " --ifdef="); allocate_and_strcat (&opts, &opts_allocated, optarg); break; case 129: case 130: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: allocate_and_strcat (&opts, &opts_allocated, " --"); allocate_and_strcat (&opts, &opts_allocated, longopts[option_index].name); if (longopts[option_index].has_arg == 1 || (longopts[option_index].has_arg == 2 && optarg != NULL)) { allocate_and_strcat (&opts, &opts_allocated, "="); allocate_and_strcat (&opts, &opts_allocated, optarg); } break; case 'R': local = 0; break; case 'l': local = 1; break; case 'k': if (options) xfree (options); options = RCS_check_kflag (optarg,true,true); break; case 'r': if (diff_rev2 != NULL || diff_date2 != NULL) error (1, 0, "no more than two revisions/dates can be specified"); if (diff_rev1 != NULL || diff_date1 != NULL) diff_rev2 = optarg; else diff_rev1 = optarg; break; case 'D': if (diff_rev2 != NULL || diff_date2 != NULL) error (1, 0, "no more than two revisions/dates can be specified"); if (diff_rev1 != NULL || diff_date1 != NULL) diff_date2 = Make_Date (optarg); else diff_date1 = Make_Date (optarg); break; case 'N': empty_files = 1; break; case '?': default: usage (diff_usage); break; } } argc -= optind; argv += optind; /* make sure options is non-null */ if (!options) options = xstrdup (""); if (!is_rcs && current_parsed_root->isremote) { if (local) send_arg("-l"); if (empty_files) send_arg("-N"); send_option_string (opts); if (options[0] != '\0') option_with_arg ("-k", options); if (diff_rev1) option_with_arg ("-r", diff_rev1); if (diff_date1) client_senddate (diff_date1); if (diff_rev2) option_with_arg ("-r", diff_rev2); if (diff_date2) client_senddate (diff_date2); send_arg("--"); /* Send the current files unless diffing two revs from the archive */ if (diff_rev2 == NULL && diff_date2 == NULL) send_files (argc, argv, local, 0, 0); else send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server ("diff\n", 0); err = get_responses_and_close (); xfree (options); options = NULL; return (err); } if(is_rcs) { int n; if(!argc) usage(diff_usage); for(n=0; n<argc; n++) { struct file_info finfo = {0}; const char *name; char *tmp = find_rcs_filename(argv[n]); if(!tmp) error(1,ENOENT,"%s",argv[n]); finfo.fullname=fullpathname(tmp, &name); finfo.file = xstrdup(name); char *ff = xstrdup(finfo.fullname); finfo.update_dir = ff; ff[(name-finfo.fullname)-1]='\0'; finfo.rcs = RCS_fopen(finfo.fullname); if(finfo.rcs) { ff = (char*)finfo.fullname; ff[strlen(finfo.fullname)-2]='\0'; ff = (char*)finfo.file; ff[strlen(finfo.file)-2]='\0'; err+=diff_fileproc(NULL,&finfo); freercsnode(&finfo.rcs); } else { error(1,ENOENT,"%s",tmp); err++; } xfree(finfo.fullname); xfree(finfo.file); xfree(finfo.update_dir); xfree(tmp); } } else { if (diff_rev1 != NULL) tag_check_valid (diff_rev1, argc, argv, local, 0, ""); if (diff_rev2 != NULL) tag_check_valid (diff_rev2, argc, argv, local, 0, ""); which = W_LOCAL; if (diff_rev1 != NULL || diff_date1 != NULL) which |= W_REPOS; /* start the recursion processor */ err = start_recursion (diff_fileproc, diff_filesdoneproc, (PREDIRENTPROC) NULL, diff_dirproc, diff_dirleaveproc, NULL, argc, argv, local, which, 0, 1, (char *) NULL, NULL, 1, verify_read, diff_rev1); } /* clean up */ xfree (options); options = NULL; if (diff_date1 != NULL) xfree (diff_date1); if (diff_date2 != NULL) xfree (diff_date2); return (err); }
int cvsstatus (int argc, char **argv) { int c; int err = 0; supress_extra_fields = compat[compat_level].hide_extended_status; if (argc == -1) usage (status_usage); optind = 0; while ((c = getopt (argc, argv, "+vlRqxX")) != -1) { switch (c) { case 'v': long_format = 1; break; case 'l': local = 1; break; case 'R': local = 0; break; case 'q': quick++; break; case 'x': supress_extra_fields = 0; break; case 'X': supress_extra_fields = 1; break; case '?': default: usage (status_usage); break; } } argc -= optind; argv += optind; if (current_parsed_root->isremote) { if (long_format) send_arg("-v"); if (local) send_arg("-l"); if (supress_extra_fields) send_arg("-X"); for(c=0; c<quick; c++) send_arg("-q"); send_arg("--"); /* For a while, we tried setting SEND_NO_CONTENTS here so this could be a fast operation. That prevents the server from updating our timestamp if the timestamp is changed but the file is unmodified. Worse, it is user-visible (shows "locally modified" instead of "up to date" if timestamp is changed but file is not). And there is no good workaround (you might not want to run "cvs update"; "cvs -n update" doesn't update CVS/Entries; "cvs diff --brief" or something perhaps could be made to work but somehow that seems nonintuitive to me even if so). Given that timestamps seem to have the potential to get munged for any number of reasons, it seems better to not rely too much on them. */ send_files (argc, argv, local, 0, 0); send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server ("status\n", 0); err = get_responses_and_close (); return err; } /* start the recursion processor */ err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, status_dirproc, (DIRLEAVEPROC) NULL, NULL, argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, NULL, 1, verify_read); return (err); }
int release (int argc, char **argv) { int i, c; char *repository; char *thisarg; int arg_start_idx; int err = 0; short delete_flag = 0; short export_flag = 0; short yes_flag=0; struct saved_cwd cwd; #ifdef SERVER_SUPPORT if (server_active) return release_server (argc, argv); #endif /* Everything from here on is client or local. */ if (argc == -1) usage (release_usage); optind = 0; while ((c = getopt (argc, argv, "+Qdeqfy")) != -1) { switch (c) { case 'Q': case 'q': error (1, 0, "-q or -Q must be specified before \"%s\"", command_name); break; case 'd': delete_flag++; break; case 'f': force_delete++; break; case 'e': export_flag++; break; case 'y': yes_flag=1; break; case '?': default: usage (release_usage); break; } } argc -= optind; argv += optind; /* Remember the directory where "cvs release" was invoked because all args are relative to this directory and we chdir around. */ if (save_cwd (&cwd)) error_exit (); arg_start_idx = 0; for (i = arg_start_idx; i < argc; i++) { thisarg = argv[i]; if (isdir (thisarg)) { if (CVS_CHDIR (thisarg) < 0) { if (!really_quiet) error (0, errno, "can't chdir to: %s", thisarg); continue; } if (!isdir (CVSADM)) { if (!really_quiet) error (0, 0, "no repository directory: %s", thisarg); if (restore_cwd (&cwd, NULL)) error_exit (); continue; } } else { if (!really_quiet) error (0, 0, "no such directory: %s", thisarg); continue; } repository = Name_Repository ((char *) NULL, (char *) NULL); if (!really_quiet) { char *tmp; modified_files = 0; start_recursion (release_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, (void *) NULL, 0, NULL, 0, W_LOCAL, 0, 0, (char *) NULL, NULL, 0, NULL, NULL); tmp=(char*)xmalloc(strlen(thisarg)+1024); if(modified_files) sprintf (tmp,"You have [%d] altered files in this repository.\n", modified_files); else *tmp='\0'; sprintf(tmp+strlen(tmp),"Are you sure you want to release %sdirectory '%s': ", delete_flag ? "(and delete) " : export_flag?"(and export) " : "", thisarg); if(!yes_flag) c=yesno_prompt(tmp,"Modified files",0); else { printf("%sy\n",tmp); c='y'; } xfree(tmp); if (c!='y') /* "No" */ { (void) fprintf (stderr, "** `%s' aborted by user choice.\n", command_name); xfree (repository); if (restore_cwd (&cwd, NULL)) error_exit (); continue; } } if (!(current_parsed_root->isremote && (!supported_request ("noop") || !supported_request ("Notify"))) ) { /* We are chdir'ed into the directory in question. So don't pass args to unedit. */ int argc = 1; char *argv[3]; argv[0] = "dummy"; argv[1] = NULL; err += unedit (argc, argv); /* Unedit will have killed our lockserver connection */ if(!current_parsed_root->isremote) lock_register_client(CVS_Username,current_parsed_root->directory); } if (current_parsed_root->isremote) { send_to_server ("Argument ", 0); send_to_server (thisarg, 0); send_to_server ("\n", 1); send_to_server ("release\n", 0); } else { history_write ('F', thisarg, "", thisarg, "", NULL, NULL); /* F == Free */ } xfree (repository); if (restore_cwd (&cwd, NULL)) error_exit (); if(!noexec) { if(delete_flag) { start_recursion (release_delete_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, (DIRENTPROC) NULL, release_delete_dirleaveproc, (void *) NULL, 1, &thisarg, 0, W_LOCAL, 0, 0, (char *) NULL, NULL, 0, NULL, NULL); } else if(export_flag) { start_recursion (NULL, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, (DIRENTPROC) NULL, release_export_dirleaveproc, (void *) NULL, 1, &thisarg, 0, W_LOCAL, 0, 0, (char *) NULL, NULL, 0, NULL, NULL); } } if (current_parsed_root->isremote) err += get_server_responses (); } if (restore_cwd (&cwd, NULL)) error_exit (); free_cwd (&cwd); if (current_parsed_root->isremote) { /* Unfortunately, client.c doesn't offer a way to close the connection without waiting for responses. The extra network turnaround here is quite unnecessary other than that.... */ send_to_server ("noop\n", 0); err += get_responses_and_close (); } return err; }
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 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 = (char*)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; }
static int ls_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile, int shorten, int local, char *mname, char *msg) { char *repository; int err = 0; int which; char *where; int i; if (is_rls) { char *myargv[2]; if (!quiet) error (0, 0, "Listing module: `%s'", strcmp (mname, "") ? mname : "."); repository = 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 = 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 = Xasprintf ("%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[1] = mfile; argc = 2; argv = myargv; } free (path); } /* cd to the starting repository */ if (CVS_CHDIR (repository) < 0) { error (0, errno, "cannot chdir to %s", repository); free (repository); free (where); return 1; } which = W_REPOS; } else /* !is_rls */ { repository = NULL; where = NULL; which = W_LOCAL | W_REPOS; } if (show_tag || show_date || show_dead_revs) which |= W_ATTIC; if (show_tag != NULL && !tag_validated) { tag_check_valid (show_tag, argc - 1, argv + 1, local, 0, repository, false); tag_validated = true; } /* Loop on argc so that we are guaranteed that any directory passed to * ls_direntproc should be processed if its parent is not yet in DIRS. */ if (argc == 1) { List *dirs = getlist (); err = start_recursion (ls_fileproc, NULL, ls_direntproc, ls_dirleaveproc, dirs, 0, NULL, local, which, 0, CVS_LOCK_READ, where, 1, repository); walklist (dirs, ls_print_dir, NULL); dellist (&dirs); } else { for (i = 1; i < argc; i++) { List *dirs = getlist (); err = start_recursion (ls_fileproc, NULL, ls_direntproc, NULL, dirs, 1, argv + i, local, which, 0, CVS_LOCK_READ, where, 1, repository); walklist (dirs, ls_print_dir, NULL); dellist (&dirs); } } if (!(which & W_LOCAL)) free (repository); if (where) free (where); return err; }
int chacl (int argc, char **argv) { int c; int local = 1; int err = 0; int is_rchacl = !strcmp(command_name,"rchacl"); if (argc == 1 || argc == -1) usage (is_rchacl?rchacl_usage:chacl_usage); memset(&parms,0,sizeof(parms)); optind = 0; while ((c = getopt (argc, argv, "+a:dnRr:u:m:j:p:")) != -1) { switch (c) { case 'a': if(parms.del) error(1,0,"Cannot combine -a and -d"); parms.access = xstrdup(optarg); break; case 'd': if(parms.access) error(1,0,"Cannot combine -a and -d"); parms.del = 1; break; case 'j': parms.merge=xstrdup(optarg); break; case 'm': parms.message=xstrdup(optarg); break; case 'n': parms.noinherit=1; break; case 'p': parms.priority=xstrdup(optarg); break; case 'r': if(parms.branch) error(1,0,"Cannot have multiple -r options"); parms.branch = xstrdup(optarg); break; case 'R': local = 0; break; case 'u': if(parms.user) error(1,0,"Cannot have multiple -u options"); parms.user = xstrdup(optarg); break; case '?': default: usage (chacl_usage); break; } } argc -= optind; argv += optind; if (argc < 0) usage (is_rchacl?rchacl_usage:chacl_usage); if (current_parsed_root->isremote) { if(is_rchacl) { if (!supported_request ("rchacl2")) error (1, 0, "server does not support rchacl"); } else { if (!supported_request ("chacl2")) error (1, 0, "server does not support v2 chacl"); } if(parms.branch) { send_arg("-r"); send_arg(parms.branch); } if(parms.user) { send_arg("-u"); send_arg(parms.user); } if(parms.del) send_arg("-d"); if(parms.noinherit) send_arg("-n"); if(parms.access) { send_arg("-a"); send_arg(parms.access); } if(parms.message) { send_arg("-m"); send_arg(parms.message); } if(parms.merge) { send_arg("-j"); send_arg(parms.merge); } if(parms.priority) { send_arg("-p"); send_arg(parms.priority); } if(!local) { send_arg("-R"); } send_arg("--"); if (is_rchacl) { int i; for (i = 0; i < argc; i++) send_arg (argv[i]); send_to_server ("rchacl2\n", 0); } else { send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("chacl2\n", 0); } return get_responses_and_close (); } if(!acl_mode) error(1,0,"Access control is disabled on this repository."); if (is_rchacl) { DBM *db; int i; db = open_module (); for (i = 0; i < argc; i++) { err += do_module (db, argv[i], MISC, "Changing", rchacl_proc, (char *) NULL, 0, local, 0, 0, (char *) NULL); } close_module (db); } else { current_date = date_from_time_t(global_session_time_t); err = start_recursion(chacl_fileproc, NULL, (PREDIRENTPROC) NULL, chacl_dirproc, chacl_dirleaveproc, (void*)NULL, argc, argv, local, W_LOCAL, 0, 0, (char*)NULL, NULL, 1, verify_control, parms.branch); xfree(current_date); } return (err); }
int cvsremove (int argc, char **argv) { int c, err; if (argc == -1) usage (remove_usage); optind = 0; while ((c = getopt (argc, argv, "+flR")) != -1) { switch (c) { case 'f': force = 1; break; case 'l': local = 1; break; case 'R': local = 0; break; case '?': default: usage (remove_usage); break; } } argc -= optind; argv += optind; if (current_parsed_root->isremote) { /* Call expand_wild so that the local removal of files will work. It's ok to do it always because we have to send the file names expanded anyway. */ expand_wild (argc, argv, &argc, &argv); if (force) { if (!noexec) { start_recursion (remove_force_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, (void *) NULL, argc, argv, local, W_LOCAL, 0, 0, (char *) NULL, NULL, 0, NULL, NULL); } /* else FIXME should probably act as if the file doesn't exist in doing the following checks. */ } if (local) send_arg("-l"); send_arg("--"); /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */ send_files (argc, argv, local, 0, 0); send_file_names (argc, argv, 0); free_names (&argc, argv); send_to_server ("remove\n", 0); return get_responses_and_close (); } /* start the recursion processor */ err = start_recursion (remove_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, remove_dirproc, (DIRLEAVEPROC) NULL, NULL, argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, NULL, 1, verify_create, NULL); if (removed_files && !really_quiet) error (0, 0, "use '%s commit' to remove %s permanently", program_name, (removed_files == 1) ? "this file" : "these files"); if (existing_files) { error (0, 0, ((existing_files == 1) ? "%d file exists; remove it first" : "%d files exist; remove them first"), existing_files); err=1; } if(bad_files) err=1; return (err); }