/* * Release: "cancel" a checkout in the history log. * * - Don't allow release if anything is active - Don't allow release if not * above or inside repository. - Don't allow release if ./CVS/Repository is * not the same as the directory specified in the module database. * * - Enter a line in the history log indicating the "release". - If asked to, * delete the local working directory. */ #include "cvs.h" #ifndef lint static char rcsid[] = "@(#)release.c 1.21 92/02/29"; #endif #if __STDC__ static void release_delete (char *dir); #else static void release_delete (); #endif /* __STDC__ */ static char *release_usage[] = { "Usage: %s %s [-d] modules...\n", "\t-Q\tReally quiet.\n", "\t-d\tDelete the given directory.\n", "\t-q\tSomewhat quiet.\n", NULL }; static short delete; int release (argc, argv) int argc; char **argv; { FILE *fp; register int i, c; register char *cp; int margc; DBM *db; datum key, val; char *repository, *srepos; char **margv, *modargv[MAXFILEPERDIR], line[PATH_MAX]; if (argc == -1) usage (release_usage); optind = 1; while ((c = gnu_getopt (argc, argv, "Qdq")) != -1) { switch (c) { case 'Q': really_quiet = 1; /* FALL THROUGH */ case 'q': quiet = 1; break; case 'd': delete++; break; case '?': default: usage (release_usage); break; } } argc -= optind; argv += optind; if (!(db = open_module ())) return (1); for (i = 0; i < argc; i++) { /* * If we are in a repository, do it. Else if we are in the parent of * a directory with the same name as the module, "cd" into it and * look for a repository there. */ if (isdir (argv[i])) { if (chdir (argv[i]) < 0) { if (!really_quiet) error (0, 0, "can't chdir to: %s", argv[i]); continue; } if (!isdir (CVSADM) && !isdir (OCVSADM)) { if (!really_quiet) error (0, 0, "no repository module: %s", argv[i]); continue; } } else { if (!really_quiet) error (0, 0, "no such directory/module: %s", argv[i]); continue; } repository = Name_Repository ((char *) NULL, (char *) NULL); srepos = Short_Repository (repository); /* grab module entry from database and check against short repos */ key.dptr = argv[i]; key.dsize = strlen (key.dptr); val = dbm_fetch (db, key); if (!val.dptr) { error (0, 0, "no such module name: %s", argv[i]); continue; } val.dptr[val.dsize] = '\0'; if ((cp = index (val.dptr, '#')) != NULL) /* Strip out a comment */ { do { *cp-- = '\0'; } while (isspace (*cp)); } (void) sprintf (line, "%s %s", key.dptr, val.dptr); line2argv (&margc, modargv, line); margv = modargv; optind = 1; while (gnu_getopt (margc, margv, CVSMODULE_OPTS) != -1) /* do nothing */ ; margc -= optind; margv += optind; if (margc < 1) { error (0, 0, "modules file missing directory for key %s value %s", key.dptr, val.dptr); continue; } if (strcmp (*margv, srepos)) { error (0, 0, "repository mismatch: module[%s], here[%s]", *margv, srepos); free (repository); continue; } if (!really_quiet) { /* * Now see if there is any reason not to allow a "Release" This * is "popen()" instead of "Popen()" since we don't want "-n" to * stop it. */ fp = popen ("cvs -n -q update", "r"); c = 0; while (fgets (line, sizeof (line), fp)) { if (index ("MARCZ", *line)) c++; (void) printf (line); } (void) pclose (fp); (void) printf ("You have [%d] altered files in this repository.\n", c); (void) printf ("Are you sure you want to release %smodule `%s': ", delete ? "(and delete) " : "", argv[i]); c = !yesno (); if (c) /* "No" */ { (void) fprintf (stderr, "** `%s' aborted by user choice.\n", command_name); free (repository); continue; } } /* * So, we've passed all the tests, go ahead and release it. First, * log the release, then attempt to delete it. */ history_write ('F', argv[i], "", argv[i], ""); /* F == Free */ free (repository); if (delete) release_delete (argv[i]); } close_module (db); return (0); } /* We want to "rm -r" the repository, but let us be a little paranoid. */ static void release_delete (dir) char *dir; { struct stat st; ino_t ino; int retcode = 0; (void) stat (".", &st); ino = st.st_ino; (void) chdir (".."); (void) stat (dir, &st); if (ino != st.st_ino) { error (0, 0, "Parent dir on a different disk, delete of %s aborted", dir); return; } run_setup ("%s -r", RM); run_arg (dir); if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) error (0, retcode == -1 ? errno : 0, "deletion of module %s failed.", dir); }