Annotation of src/usr.bin/cvs/status.c, Revision 1.48
1.48 ! xsa 1: /* $OpenBSD: status.c,v 1.47 2005/09/05 20:03:22 xsa Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.41 xsa 4: * Copyright (c) 2005 Xavier Santolaria <xsa@openbsd.org>
1.4 tedu 5: * All rights reserved.
1.1 jfb 6: *
1.4 tedu 7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
1.1 jfb 10: *
1.4 tedu 11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
1.1 jfb 13: * 2. The name of the author may not be used to endorse or promote products
1.4 tedu 14: * derived from this software without specific prior written permission.
1.1 jfb 15: *
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
1.4 tedu 25: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 jfb 26: */
27:
28: #include <sys/types.h>
29: #include <sys/stat.h>
30:
31: #include <errno.h>
1.23 xsa 32: #include <fcntl.h>
1.1 jfb 33: #include <stdio.h>
34: #include <stdlib.h>
1.23 xsa 35: #include <string.h>
1.1 jfb 36: #include <unistd.h>
37:
38: #include "cvs.h"
39: #include "log.h"
40: #include "proto.h"
41:
42:
1.15 jfb 43: #define CVS_STATUS_SEP \
44: "==================================================================="
45:
1.31 xsa 46: /* Keep this sorted as it is now. See file.h for status values. */
1.1 jfb 47: const char *cvs_statstr[] = {
48: "Unknown",
1.15 jfb 49: "Up-to-date",
1.1 jfb 50: "Locally Modified",
1.29 xsa 51: "Locally Added",
52: "Locally Removed",
53: "Unresolved Conflict",
1.1 jfb 54: "Patched",
1.16 jfb 55: "Needs Checkout",
1.1 jfb 56: };
1.33 xsa 57:
1.1 jfb 58:
1.41 xsa 59: static int cvs_status_init (struct cvs_cmd *, int, char **, int *);
60: static int cvs_status_remote (CVSFILE *, void *);
61: static int cvs_status_local (CVSFILE *, void *);
1.22 jfb 62: static int cvs_status_pre_exec (struct cvsroot *);
63:
64: struct cvs_cmd cvs_cmd_status = {
65: CVS_OP_STATUS, CVS_REQ_STATUS, "status",
66: { "st", "stat" },
67: "Display status information on checked out files",
68: "[-lRv]",
69: "lRv",
70: NULL,
71: CF_SORT | CF_IGNORE | CF_RECURSE,
72: cvs_status_init,
73: cvs_status_pre_exec,
1.20 jfb 74: cvs_status_remote,
1.22 jfb 75: cvs_status_local,
76: NULL,
77: NULL,
1.10 joris 78: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2
79: };
1.1 jfb 80:
1.10 joris 81: static int verbose = 0;
1.1 jfb 82:
1.22 jfb 83: static int
84: cvs_status_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1 jfb 85: {
1.10 joris 86: int ch;
1.1 jfb 87:
1.22 jfb 88: while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1 jfb 89: switch (ch) {
1.7 jfb 90: case 'l':
1.22 jfb 91: cmd->file_flags &= ~CF_RECURSE;
1.7 jfb 92: break;
93: case 'R':
1.22 jfb 94: cmd->file_flags |= CF_RECURSE;
1.7 jfb 95: break;
96: case 'v':
97: verbose = 1;
98: break;
1.1 jfb 99: default:
1.14 joris 100: return (CVS_EX_USAGE);
1.1 jfb 101: }
102: }
103:
1.10 joris 104: *arg = optind;
105: return (0);
106: }
1.1 jfb 107:
1.22 jfb 108: static int
109: cvs_status_pre_exec(struct cvsroot *root)
1.10 joris 110: {
1.26 xsa 111: if (root->cr_method != CVS_METHOD_LOCAL) {
1.48 ! xsa 112: if ((verbose == 1) && (cvs_sendarg(root, "-v", 0) < 0))
1.26 xsa 113: return (CVS_EX_PROTO);
114: }
115:
1.1 jfb 116: return (0);
117: }
118:
119: /*
1.20 jfb 120: * cvs_status_remote()
1.1 jfb 121: *
122: * Get the status of a single file.
123: */
1.22 jfb 124: static int
1.20 jfb 125: cvs_status_remote(CVSFILE *cfp, void *arg)
1.1 jfb 126: {
1.5 jfb 127: int ret;
1.44 xsa 128: char fpath[MAXPATHLEN];
1.1 jfb 129: struct cvsroot *root;
130:
1.5 jfb 131: ret = 0;
132: root = CVS_DIR_ROOT(cfp);
1.1 jfb 133:
1.6 jfb 134: if (cfp->cf_type == DT_DIR) {
1.15 jfb 135: if (cfp->cf_cvstat == CVS_FST_UNKNOWN)
136: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE,
1.42 joris 137: cfp->cf_name);
1.15 jfb 138: else
139: ret = cvs_senddir(root, cfp);
1.21 joris 140:
141: if (ret == -1)
142: ret = CVS_EX_PROTO;
143:
1.6 jfb 144: return (ret);
145: }
1.1 jfb 146:
1.5 jfb 147: cvs_file_getpath(cfp, fpath, sizeof(fpath));
1.1 jfb 148:
1.21 joris 149: if (cvs_sendentry(root, cfp) < 0)
150: return (CVS_EX_PROTO);
1.15 jfb 151:
152: switch (cfp->cf_cvstat) {
153: case CVS_FST_UNKNOWN:
1.20 jfb 154: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
1.15 jfb 155: break;
156: case CVS_FST_UPTODATE:
1.20 jfb 157: ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
1.15 jfb 158: break;
1.17 joris 159: case CVS_FST_ADDED:
1.15 jfb 160: case CVS_FST_MODIFIED:
1.20 jfb 161: ret = cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name);
1.15 jfb 162: if (ret == 0)
163: ret = cvs_sendfile(root, fpath);
164: default:
165: break;
166: }
167:
1.21 joris 168: if (ret == -1)
169: ret = CVS_EX_PROTO;
170:
1.15 jfb 171: return (ret);
172: }
173:
1.22 jfb 174: static int
175: cvs_status_local(CVSFILE *cf, void *arg)
1.15 jfb 176: {
1.22 jfb 177: int len;
1.35 xsa 178: size_t n;
179: char buf[MAXNAMLEN], fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
180: char numbuf[64], timebuf[32];
1.15 jfb 181: RCSFILE *rf;
1.41 xsa 182: struct rcs_sym *sym;
1.15 jfb 183:
1.33 xsa 184: if (cf->cf_type == DT_DIR) {
185: if (verbosity > 1)
1.43 xsa 186: cvs_log(LP_NOTICE, "Examining %s", cf->cf_name);
1.15 jfb 187: return (0);
1.33 xsa 188: }
1.15 jfb 189:
1.22 jfb 190: cvs_file_getpath(cf, fpath, sizeof(fpath));
1.1 jfb 191:
1.40 xsa 192: if (cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)) == NULL)
1.21 joris 193: return (CVS_EX_DATA);
1.1 jfb 194:
1.46 joris 195: rf = NULL;
1.37 xsa 196: if (cf->cf_cvstat != CVS_FST_UNKNOWN &&
197: cf->cf_cvstat != CVS_FST_ADDED) {
1.30 xsa 198: rf = rcs_open(rcspath, RCS_READ);
199: if (rf == NULL)
200: return (CVS_EX_DATA);
201: }
1.5 jfb 202:
1.16 jfb 203: buf[0] = '\0';
1.47 xsa 204:
205: if (cf->cf_cvstat == CVS_FST_UNKNOWN)
206: cvs_log(LP_WARN, "nothing known about %s", cf->cf_name);
207:
1.30 xsa 208: if (cf->cf_cvstat == CVS_FST_LOST || cf->cf_cvstat == CVS_FST_UNKNOWN)
1.27 xsa 209: strlcpy(buf, "no file ", sizeof(buf));
1.22 jfb 210: strlcat(buf, cf->cf_name, sizeof(buf));
1.16 jfb 211:
1.28 xsa 212: cvs_printf(CVS_STATUS_SEP "\nFile: %-17s\tStatus: %s\n\n",
1.22 jfb 213: buf, cvs_statstr[cf->cf_cvstat]);
1.16 jfb 214:
1.22 jfb 215: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
1.32 joris 216: len = snprintf(buf, sizeof(buf), "No entry for %s",
217: cf->cf_name);
1.37 xsa 218: } else if (cf->cf_cvstat == CVS_FST_ADDED) {
219: len = snprintf(buf, sizeof(buf), "New file!");
1.16 jfb 220: } else {
1.37 xsa 221: rcsnum_tostr(cf->cf_lrev, numbuf, sizeof(numbuf));
222: len = snprintf(buf, sizeof(buf), "%s", numbuf);
1.35 xsa 223:
224: /* Display etime in local mode only. */
225: if (cvs_cmdop != CVS_OP_SERVER) {
226: strlcat(buf, "\t", sizeof(buf));
227:
228: ctime_r(&(cf->cf_etime), timebuf);
229: n = strlen(timebuf);
230: if ((n > 0) && (timebuf[n - 1] == '\n'))
1.36 xsa 231: timebuf[--n] = '\0';
1.35 xsa 232:
233: strlcat(buf, timebuf, sizeof(buf));
234: }
1.16 jfb 235: }
1.32 joris 236:
1.34 joris 237: if (len == -1 || len >= (int)sizeof(buf)) {
238: if (rf != NULL)
239: rcs_close(rf);
1.32 joris 240: return (CVS_EX_DATA);
1.34 joris 241: }
1.15 jfb 242:
1.28 xsa 243: cvs_printf(" Working revision:\t%s\n", buf);
1.30 xsa 244:
1.37 xsa 245: if (cf->cf_cvstat == CVS_FST_UNKNOWN ||
246: cf->cf_cvstat == CVS_FST_ADDED) {
247: len = snprintf(buf, sizeof(buf), "No revision control file");
1.30 xsa 248: } else {
1.34 joris 249: len = snprintf(buf, sizeof(buf), "%s\t%s",
1.30 xsa 250: rcsnum_tostr(rf->rf_head, numbuf, sizeof(numbuf)),
251: rcspath);
1.34 joris 252: }
253:
254: if (len == -1 || len >= (int)sizeof(buf)) {
255: if (rf != NULL)
256: rcs_close(rf);
257: return (CVS_EX_DATA);
1.30 xsa 258: }
259:
260: cvs_printf(" Repository revision:\t%s\n", buf);
261:
262: /* If the file is unknown, no other output is needed after this. */
1.37 xsa 263: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
264: cvs_printf("\n");
1.30 xsa 265: return (0);
1.37 xsa 266: }
1.30 xsa 267:
1.38 xsa 268: if (cf->cf_tag != NULL)
269: cvs_printf(" Sticky Tag:\t\t%s\n", cf->cf_tag);
270: else if (verbosity > 0)
271: cvs_printf(" Sticky Tag:\t\t(none)\n");
272:
273: /* XXX */
274: if (verbosity > 0)
275: cvs_printf(" Sticky Date:\t\t%s\n", "(none)");
276:
277: if (cf->cf_opts != NULL)
278: cvs_printf(" Sticky Options:\t%s\n", cf->cf_opts);
279: else if (verbosity > 0)
280: cvs_printf(" Sticky Options:\t(none)\n");
1.41 xsa 281:
1.48 ! xsa 282: if (verbose == 1) {
1.41 xsa 283: cvs_printf("\n");
284: cvs_printf(" Existing Tags:\n");
285:
286: if (!TAILQ_EMPTY(&(rf->rf_symbols))) {
287: TAILQ_FOREACH(sym, &(rf->rf_symbols), rs_list) {
288: rcsnum_tostr(sym->rs_num, numbuf,
289: sizeof(numbuf));
290:
291: cvs_printf("\t%-25s\t(%s: %s)\n",
1.45 xsa 292: sym->rs_name,
1.41 xsa 293: RCSNUM_ISBRANCH(sym->rs_num) ? "branch" :
294: "revision", numbuf);
295: }
296: } else {
297: cvs_printf("\tNo Tags Exist\n");
298: }
299: }
1.15 jfb 300:
1.25 xsa 301: cvs_printf("\n");
1.46 joris 302:
303: if (rf != NULL)
304: rcs_close(rf);
1.15 jfb 305:
306: return (0);
1.1 jfb 307: }