version 1.33, 2006/05/27 03:30:31 |
version 1.34, 2007/06/26 18:02:43 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* |
/*- |
* Copyright (c) 2005 Xavier Santolaria <xsa@openbsd.org> |
* Copyright (c) 2005-2007 Xavier Santolaria <xsa@openbsd.org> |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Permission to use, copy, modify, and distribute this software for any |
* modification, are permitted provided that the following conditions |
* purpose with or without fee is hereby granted, provided that the above |
* are met: |
* copyright notice and this permission notice appear in all copies. |
* |
* |
* 1. Redistributions of source code must retain the above copyright |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* notice, this list of conditions and the following disclaimer. |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* 2. The name of the author may not be used to endorse or promote products |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* derived from this software without specific prior written permission. |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
|
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
*/ |
|
|
#include "includes.h" |
#include <sys/stat.h> |
|
|
|
#include <string.h> |
|
#include <unistd.h> |
|
|
#include "cvs.h" |
#include "cvs.h" |
#include "log.h" |
#include "remote.h" |
#include "proto.h" |
|
|
|
#define UPDCMD_FLAGS "-n -q -d" |
|
|
|
extern char *__progname; |
extern char *__progname; |
|
|
static int cvs_release_init(struct cvs_cmd *, int, char **, int *); |
void cvs_release_local(struct cvs_file *); |
static int cvs_release_pre_exec(struct cvsroot *); |
|
static int cvs_release_dir(CVSFILE *, void *); |
|
|
|
|
static void release_check_files(struct cvs_file *); |
|
|
|
static int dflag = 0; |
|
static int files_altered = 0; |
|
|
struct cvs_cmd cvs_cmd_release = { |
struct cvs_cmd cvs_cmd_release = { |
CVS_OP_RELEASE, CVS_REQ_RELEASE, "release", |
CVS_OP_RELEASE, 0, "release", |
{ "re", "rel" }, |
{ "re", "rel" }, |
"Release", |
"Indicate that a Module is no longer in use", |
"[-d]", |
"[-d] dir...", |
"d", |
"d", |
NULL, |
NULL, |
CF_NOFILES, |
cvs_release |
cvs_release_init, |
|
cvs_release_pre_exec, |
|
cvs_release_dir, |
|
cvs_release_dir, |
|
NULL, |
|
NULL, |
|
CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC |
|
}; |
}; |
|
|
static int dflag; /* -d option */ |
int |
|
cvs_release(int argc, char **argv) |
static int |
|
cvs_release_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) |
|
{ |
{ |
int ch; |
int ch; |
|
int flags; |
|
struct cvs_recursion cr; |
|
|
while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { |
flags = CR_REPO; |
|
|
|
while ((ch = getopt(argc, argv, cvs_cmd_release.cmd_opts)) != -1) { |
switch (ch) { |
switch (ch) { |
case 'd': |
case 'd': |
dflag = 1; |
dflag = 1; |
break; |
break; |
default: |
default: |
return (CVS_EX_USAGE); |
fatal("%s", cvs_cmd_release.cmd_synopsis); |
} |
} |
} |
} |
|
|
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
*arg = optind; |
|
|
|
if (argc == 0) |
if (argc == 0) |
return (CVS_EX_USAGE); |
fatal("%s", cvs_cmd_release.cmd_synopsis); |
|
|
return (0); |
cr.enterdir = NULL; |
} |
cr.leavedir = NULL; |
|
|
static int |
if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { |
cvs_release_pre_exec(struct cvsroot *root) |
cvs_client_connect_to_server(); |
{ |
cr.fileproc = cvs_client_sendfile; |
if (root->cr_method != CVS_METHOD_LOCAL) { |
|
if (dflag == 1) |
if (dflag == 1) |
cvs_sendarg(root, "-d", 0); |
cvs_client_send_request("Argument -d"); |
|
} else |
|
cr.fileproc = cvs_release_local; |
|
|
|
cr.flags = flags; |
|
|
|
cvs_file_run(argc, argv, &cr); |
|
|
|
if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { |
|
cvs_client_send_files(argv, argc); |
|
cvs_client_senddir("."); |
|
cvs_client_send_request("release"); |
|
cvs_client_get_responses(); |
} |
} |
|
|
return (0); |
return (0); |
} |
} |
|
|
/* |
void |
* cvs_release_dir() |
cvs_release_local(struct cvs_file *cf) |
* |
|
* Release specified directorie(s). |
|
* Returns 0 on success, or -1 on failure. |
|
*/ |
|
static int |
|
cvs_release_dir(CVSFILE *cf, void *arg) |
|
{ |
{ |
FILE *fp; |
|
int j, l; |
|
char *wdir, cwd[MAXPATHLEN]; |
|
char buf[256], dpath[MAXPATHLEN], updcmd[1024]; |
|
struct stat st; |
struct stat st; |
struct cvsroot *root; |
struct cvs_recursion cr; |
|
char *wdir, cwd[MAXPATHLEN]; |
|
char *arg = "."; |
|
int saved_noexec; |
|
|
j = 0; |
if (cf->file_type == CVS_FILE) |
|
return; |
|
|
root = CVS_DIR_ROOT(cf); |
cvs_log(LP_TRACE, "cvs_release_local(%s)", cf->file_path); |
|
|
/* XXX kept for compat reason of `cvs update' output */ |
cvs_file_classify(cf, NULL); |
/* save current working directory for further use */ |
|
|
if (cvs_server_active == 1) { |
|
cvs_history_add(CVS_HISTORY_RELEASE, cf, NULL); |
|
return; |
|
} |
|
|
if ((wdir = getcwd(cwd, sizeof(cwd))) == NULL) |
if ((wdir = getcwd(cwd, sizeof(cwd))) == NULL) |
fatal("getcwd failed"); |
fatal("getcwd failed"); |
|
|
cvs_file_getpath(cf, dpath, sizeof(dpath)); |
if (cf->file_type == CVS_DIR) { |
|
if (!strcmp(cf->file_name, ".")) |
|
return; |
|
|
if (cf->cf_type == DT_DIR) { |
/* chdir before updating the directory. */ |
if (!strcmp(cf->cf_name, ".")) |
cvs_chdir(cf->file_path, 0); |
return (0); |
|
|
|
/* chdir before running the `cvs update' command */ |
if (stat(CVS_PATH_CVSDIR, &st) == -1 || !S_ISDIR(st.st_mode)) { |
cvs_chdir(dpath, 0); |
cvs_log(LP_ERR, "no repository directory: %s", |
|
cf->file_path); |
/* test if dir has CVS/ directory */ |
return; |
if (stat(CVS_PATH_CVSDIR, &st) == -1) { |
|
if (verbosity > 0) |
|
cvs_log(LP_ERR, |
|
"no repository directory: %s", dpath); |
|
return (0); |
|
} |
} |
} else { |
|
if (verbosity > 0) |
|
cvs_log(LP_ERR, "no such directory: %s", dpath); |
|
return (0); |
|
} |
} |
|
|
/* construct `cvs update' command */ |
saved_noexec = cvs_noexec; |
l = snprintf(updcmd, sizeof(updcmd), "%s %s %s update", |
cvs_noexec = 1; |
__progname, UPDCMD_FLAGS, root->cr_str); |
|
if (l == -1 || l >= (int)sizeof(updcmd)) |
|
fatal("cvs_release_dir: `cvs update' command string overflow"); |
|
|
|
/* XXX we should try to avoid a new connection ... */ |
cr.enterdir = NULL; |
cvs_log(LP_TRACE, "cvs_release_dir() popen(%s,r)", updcmd); |
cr.leavedir = NULL; |
if ((fp = popen(updcmd, "r")) == NULL) |
cr.fileproc = cvs_update_local; |
fatal("cannot run command `%s'", updcmd); |
cr.flags = CR_REPO | CR_RECURSE_DIRS; |
|
|
while (fgets(buf, (int)sizeof(buf), fp) != NULL) { |
cvs_file_run(1, &arg, &cr); |
if (strchr("ACMPRU", buf[0])) |
|
j++; |
|
(void)fputs(buf, stdout); |
|
} |
|
|
|
if (pclose(fp) != 0) { |
cvs_noexec = saved_noexec; |
cvs_log(LP_ERR, "unable to release `%s'", dpath); |
|
|
|
/* change back to original working dir */ |
cr.enterdir = NULL; |
cvs_chdir(wdir, 0); |
cr.leavedir = NULL; |
} |
cr.fileproc = release_check_files; |
|
cr.flags = CR_RECURSE_DIRS; |
|
|
printf("You have [%d] altered file%s in this repository.\n", |
cvs_file_run(1, &arg, &cr); |
j, j > 1 ? "s" : ""); |
|
while (fgets(buf, (int)sizeof(buf), fp) != NULL) { |
|
if (strchr("ACMPRU", buf[0])) |
|
j++; |
|
(void)fputs(buf, stdout); |
|
} |
|
|
|
printf("Are you sure you want to release %sdirectory `%s': ", |
(void)printf("You have [%d] altered files in this repository.\n", |
dflag ? "(and delete) " : "", dpath); |
files_altered); |
|
(void)printf("Are you sure you want to release %sdirectory `%s': ", |
|
(dflag == 1) ? "(and delete) " : "", cf->file_path); |
|
|
if (cvs_yesno() == -1) { /* No */ |
if (cvs_yesno() == -1) { |
fprintf(stderr, |
(void)fprintf(stderr, |
"** `%s' aborted by user choice.\n", cvs_command); |
"** `%s' aborted by user choice.\n", cvs_command); |
|
|
/* change back to original working dir */ |
/* change back to original working dir */ |
cvs_chdir(wdir, 0); |
cvs_chdir(wdir, 0); |
|
|
return (-1); |
return; |
} |
} |
|
|
/* change back to original working dir */ |
/* change back to original working dir */ |
cvs_chdir(wdir, 0); |
cvs_chdir(wdir, 0); |
|
|
if (dflag == 1) { |
if (dflag == 1) { |
if (cvs_rmdir(dpath) != 0) |
if (cvs_rmdir(cf->file_path) != 0) |
fatal("cvs_release_dir: cvs_rmdir failed"); |
fatal("cvs_release_local: cvs_rmdir failed"); |
} |
} |
|
} |
|
|
return (0); |
static void |
|
release_check_files(struct cvs_file *cf) |
|
{ |
|
cvs_log(LP_TRACE, "release_check_files(%s)", cf->file_path); |
|
|
|
cvs_file_classify(cf, NULL); |
|
|
|
if (cf->file_status == FILE_MERGE || |
|
cf->file_status == FILE_ADDED || |
|
cf->file_status == FILE_PATCH || |
|
cf->file_status == FILE_CONFLICT) |
|
files_altered++; |
|
return; |
} |
} |