version 1.56, 2006/04/14 02:45:35 |
version 1.57, 2006/05/27 03:30:31 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* |
/* |
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> |
* Copyright (c) 2006 Joris Vink <joris@openbsd.org> |
* Copyright (c) 2005 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 "includes.h" |
|
|
#include "log.h" |
#include "log.h" |
#include "proto.h" |
#include "proto.h" |
|
|
|
int cvs_status(int, char **); |
|
void cvs_status_local(struct cvs_file *); |
|
|
#define CVS_STATUS_SEP \ |
|
"===================================================================" |
|
|
|
/* Keep this sorted as it is now. See file.h for status values. */ |
|
const char *cvs_statstr[] = { |
|
"Unknown", |
|
"Up-to-date", |
|
"Locally Modified", |
|
"Locally Added", |
|
"Locally Removed", |
|
"Unresolved Conflict", |
|
"Patched", |
|
"Needs Checkout", |
|
}; |
|
|
|
|
|
static int cvs_status_init (struct cvs_cmd *, int, char **, int *); |
|
static int cvs_status_remote (CVSFILE *, void *); |
|
static int cvs_status_local (CVSFILE *, void *); |
|
static int cvs_status_pre_exec (struct cvsroot *); |
|
|
|
struct cvs_cmd cvs_cmd_status = { |
struct cvs_cmd cvs_cmd_status = { |
CVS_OP_STATUS, CVS_REQ_STATUS, "status", |
CVS_OP_STATUS, CVS_REQ_STATUS, "status", |
{ "st", "stat" }, |
{ "st", "stat" }, |
"Display status information on checked out files", |
"Display status information on checked out files", |
"[-lRv]", |
"[-lRv]", |
"lRv", |
"lRv:", |
NULL, |
NULL, |
CF_SORT | CF_IGNORE | CF_RECURSE, |
cvs_status |
cvs_status_init, |
|
cvs_status_pre_exec, |
|
cvs_status_remote, |
|
cvs_status_local, |
|
NULL, |
|
NULL, |
|
CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2 |
|
}; |
}; |
|
|
static int verbose = 0; |
#define CVS_STATUS_SEP \ |
|
"===================================================================" |
|
|
static int |
const char *status_tab[] = { |
cvs_status_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) |
"Unknown", |
|
"Locally Added", |
|
"Locally Removed", |
|
"Locally Modified", |
|
"Up-to-date", |
|
"Needs Checkout", |
|
"Needs Checkout", |
|
"Needs Merge", |
|
"Needs Patch", |
|
"Entry Invalid", |
|
"Unresolved Conflict", |
|
"Classifying error", |
|
}; |
|
|
|
int |
|
cvs_status(int argc, char **argv) |
{ |
{ |
int ch; |
int ch; |
|
char *arg = "."; |
|
struct cvs_recursion cr; |
|
|
while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { |
while ((ch = getopt(argc, argv, cvs_cmd_status.cmd_opts)) != -1) { |
switch (ch) { |
switch (ch) { |
case 'l': |
case 'l': |
cmd->file_flags &= ~CF_RECURSE; |
|
break; |
break; |
case 'R': |
case 'R': |
cmd->file_flags |= CF_RECURSE; |
|
break; |
break; |
case 'v': |
case 'v': |
verbose = 1; |
|
break; |
break; |
default: |
default: |
return (CVS_EX_USAGE); |
fatal("%s", cvs_cmd_status.cmd_synopsis); |
} |
} |
} |
} |
|
|
*arg = optind; |
argc -= optind; |
return (0); |
argv += optind; |
} |
|
|
|
static int |
cr.enterdir = NULL; |
cvs_status_pre_exec(struct cvsroot *root) |
cr.leavedir = NULL; |
{ |
cr.local = cvs_status_local; |
if (root->cr_method != CVS_METHOD_LOCAL) { |
cr.remote = NULL; |
if (verbose == 1) |
|
cvs_sendarg(root, "-v", 0); |
|
} |
|
|
|
|
if (argc > 0) |
|
cvs_file_run(argc, argv, &cr); |
|
else |
|
cvs_file_run(1, &arg, &cr); |
|
|
return (0); |
return (0); |
} |
} |
|
|
/* |
void |
* cvs_status_remote() |
cvs_status_local(struct cvs_file *cf) |
* |
|
* Get the status of a single file. |
|
*/ |
|
static int |
|
cvs_status_remote(CVSFILE *cfp, void *arg) |
|
{ |
{ |
char fpath[MAXPATHLEN]; |
int l; |
struct cvsroot *root; |
size_t len; |
|
const char *status; |
|
char buf[128], timebuf[32], revbuf[32]; |
|
|
root = CVS_DIR_ROOT(cfp); |
cvs_log(LP_TRACE, "cvs_status_local(%s)", cf->file_path); |
|
|
if (cfp->cf_type == DT_DIR) { |
cvs_file_classify(cf); |
if (cfp->cf_cvstat == CVS_FST_UNKNOWN) |
|
cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); |
|
else |
|
cvs_senddir(root, cfp); |
|
return (0); |
|
} |
|
|
|
cvs_file_getpath(cfp, fpath, sizeof(fpath)); |
if (cf->file_type == CVS_DIR) { |
|
|
cvs_sendentry(root, cfp); |
|
|
|
switch (cfp->cf_cvstat) { |
|
case CVS_FST_UNKNOWN: |
|
cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); |
|
break; |
|
case CVS_FST_UPTODATE: |
|
cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name); |
|
break; |
|
case CVS_FST_ADDED: |
|
case CVS_FST_MODIFIED: |
|
cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name); |
|
cvs_sendfile(root, fpath); |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
return (0); |
|
} |
|
|
|
static int |
|
cvs_status_local(CVSFILE *cf, void *arg) |
|
{ |
|
size_t n; |
|
char buf[MAXNAMLEN], fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; |
|
char numbuf[64], timebuf[32]; |
|
RCSFILE *rf; |
|
struct rcs_sym *sym; |
|
|
|
if (cf->cf_type == DT_DIR) { |
|
if (verbosity > 1) |
if (verbosity > 1) |
cvs_log(LP_NOTICE, "Examining %s", cf->cf_name); |
cvs_log(LP_NOTICE, "Examining %s", cf->file_path); |
return (0); |
return; |
} |
} |
|
|
cvs_file_getpath(cf, fpath, sizeof(fpath)); |
cvs_printf("%s\n", CVS_STATUS_SEP); |
cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)); |
|
|
|
rf = NULL; |
status = status_tab[cf->file_status]; |
if (cf->cf_cvstat != CVS_FST_UNKNOWN && |
if (cf->file_status == FILE_MODIFIED && |
cf->cf_cvstat != CVS_FST_ADDED) { |
cf->file_ent->ce_conflict != NULL) |
if ((rf = rcs_open(rcspath, RCS_READ)) == NULL) |
status = "File had conflicts on merge"; |
fatal("cvs_status_local: rcs_open `%s': %s", rcspath, |
|
rcs_errstr(rcs_errno)); |
|
} |
|
|
|
buf[0] = '\0'; |
cvs_printf("File: %-17s\tStatus: %s\n\n", cf->file_name, status); |
|
|
if (cf->cf_cvstat == CVS_FST_UNKNOWN) |
if (cf->file_ent == NULL) { |
cvs_log(LP_WARN, "nothing known about %s", cf->cf_name); |
l = snprintf(buf, sizeof(buf), |
|
"No entry for %s", cf->file_name); |
if (cf->cf_cvstat == CVS_FST_LOST || cf->cf_cvstat == CVS_FST_UNKNOWN) |
if (l == -1 || l >= (int)sizeof(buf)) |
strlcpy(buf, "no file ", sizeof(buf)); |
fatal("cvs_status_local: overflow"); |
strlcat(buf, cf->cf_name, sizeof(buf)); |
} else if (cf->file_status == FILE_ADDED) { |
|
len = strlcpy(buf, "New file!", sizeof(buf)); |
cvs_printf(CVS_STATUS_SEP "\nFile: %-17s\tStatus: %s\n\n", |
if (len >= sizeof(buf)) |
buf, cvs_statstr[cf->cf_cvstat]); |
fatal("cvs_status_local: truncation"); |
|
|
if (cf->cf_cvstat == CVS_FST_UNKNOWN) { |
|
strlcpy(buf, "No entry for ", sizeof(buf)); |
|
strlcat(buf, cf->cf_name, sizeof(buf)); |
|
} else if (cf->cf_cvstat == CVS_FST_ADDED) { |
|
strlcpy(buf, "New file!", sizeof(buf)); |
|
} else { |
} else { |
rcsnum_tostr(cf->cf_lrev, numbuf, sizeof(numbuf)); |
rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf)); |
strlcpy(buf, numbuf, sizeof(buf)); |
|
|
|
/* Display etime in local mode only. */ |
if (cf->file_ent->ce_conflict == NULL) { |
if (cvs_cmdop != CVS_OP_SERVER) { |
ctime_r(&(cf->file_ent->ce_mtime), timebuf); |
strlcat(buf, "\t", sizeof(buf)); |
if (timebuf[strlen(timebuf) - 1] == '\n') |
|
timebuf[strlen(timebuf) - 1] = '\0'; |
ctime_r(&(cf->cf_etime), timebuf); |
} else { |
n = strlen(timebuf); |
len = strlcpy(timebuf, cf->file_ent->ce_conflict, |
if (n > 0 && timebuf[n - 1] == '\n') |
sizeof(timebuf)); |
timebuf[--n] = '\0'; |
if (len >= sizeof(timebuf)) |
|
fatal("cvs_status_local: truncation"); |
strlcat(buf, timebuf, sizeof(buf)); |
|
} |
} |
|
|
|
l = snprintf(buf, sizeof(buf), "%s\t%s", revbuf, timebuf); |
|
if (l == -1 || l >= (int)sizeof(buf)) |
|
fatal("cvs_status_local: overflow"); |
} |
} |
|
|
cvs_printf(" Working revision:\t%s\n", buf); |
cvs_printf(" Working revision:\t%s\n", buf); |
|
|
if (cf->cf_cvstat == CVS_FST_UNKNOWN || |
buf[0] = '\0'; |
cf->cf_cvstat == CVS_FST_ADDED) { |
if (cf->file_rcs == NULL) { |
strlcpy(buf, "No revision control file", sizeof(buf)); |
len = strlcat(buf, "No revision control file", sizeof(buf)); |
|
if (len >= sizeof(buf)) |
|
fatal("cvs_status_local: truncation"); |
} else { |
} else { |
strlcpy(buf, rcsnum_tostr(rf->rf_head, numbuf, sizeof(numbuf)), |
rcsnum_tostr(cf->file_rcs->rf_head, revbuf, sizeof(revbuf)); |
sizeof(buf)); |
l = snprintf(buf, sizeof(buf), "%s\t%s", revbuf, |
strlcat(buf, "\t", sizeof(buf)); |
cf->file_rpath); |
strlcat(buf, rcspath, sizeof(buf)); |
if (l == -1 || l >= (int)sizeof(buf)) |
|
fatal("cvs_status_local: overflow"); |
} |
} |
|
|
cvs_printf(" Repository revision:\t%s\n", buf); |
cvs_printf(" Repository revision:\t%s\n", buf); |
|
|
/* If the file is unknown, no other output is needed after this. */ |
if (cf->file_ent != NULL) { |
if (cf->cf_cvstat == CVS_FST_UNKNOWN) { |
if (cf->file_ent->ce_tag != NULL) |
cvs_printf("\n"); |
cvs_printf(" Sticky Tag:\t%s\n", |
return (0); |
cf->file_ent->ce_tag); |
|
if (cf->file_ent->ce_opts != NULL) |
|
cvs_printf(" Sticky Options:\t%s\n", |
|
cf->file_ent->ce_opts); |
} |
} |
|
|
if (cf->cf_tag != NULL) |
|
cvs_printf(" Sticky Tag:\t\t%s\n", cf->cf_tag); |
|
else if (verbosity > 0) |
|
cvs_printf(" Sticky Tag:\t\t(none)\n"); |
|
|
|
/* XXX */ |
|
if (verbosity > 0) |
|
cvs_printf(" Sticky Date:\t\t%s\n", "(none)"); |
|
|
|
if (cf->cf_opts != NULL) |
|
cvs_printf(" Sticky Options:\t%s\n", cf->cf_opts); |
|
else if (verbosity > 0) |
|
cvs_printf(" Sticky Options:\t(none)\n"); |
|
|
|
if (verbose == 1) { |
|
cvs_printf("\n"); |
|
cvs_printf(" Existing Tags:\n"); |
|
|
|
if (!TAILQ_EMPTY(&(rf->rf_symbols))) { |
|
TAILQ_FOREACH(sym, &(rf->rf_symbols), rs_list) { |
|
rcsnum_tostr(sym->rs_num, numbuf, |
|
sizeof(numbuf)); |
|
|
|
cvs_printf("\t%-25s\t(%s: %s)\n", |
|
sym->rs_name, |
|
RCSNUM_ISBRANCH(sym->rs_num) ? "branch" : |
|
"revision", numbuf); |
|
} |
|
} else { |
|
cvs_printf("\tNo Tags Exist\n"); |
|
} |
|
} |
|
|
|
cvs_printf("\n"); |
cvs_printf("\n"); |
|
|
if (rf != NULL) |
|
rcs_close(rf); |
|
|
|
return (0); |
|
} |
} |