Annotation of src/usr.bin/cvs/status.c, Revision 1.43
1.43 ! xsa 1: /* $OpenBSD: status.c,v 1.42 2005/07/22 16:27:29 joris 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) {
112: if (verbose && (cvs_sendarg(root, "-v", 0) < 0))
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.15 jfb 128: char *repo, fpath[MAXPATHLEN];
1.1 jfb 129: RCSFILE *rf;
130: struct cvsroot *root;
131:
1.5 jfb 132: ret = 0;
1.1 jfb 133: rf = NULL;
1.5 jfb 134: root = CVS_DIR_ROOT(cfp);
135: repo = CVS_DIR_REPO(cfp);
1.1 jfb 136:
1.6 jfb 137: if (cfp->cf_type == DT_DIR) {
1.15 jfb 138: if (cfp->cf_cvstat == CVS_FST_UNKNOWN)
139: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE,
1.42 joris 140: cfp->cf_name);
1.15 jfb 141: else
142: ret = cvs_senddir(root, cfp);
1.21 joris 143:
144: if (ret == -1)
145: ret = CVS_EX_PROTO;
146:
1.6 jfb 147: return (ret);
148: }
1.1 jfb 149:
1.5 jfb 150: cvs_file_getpath(cfp, fpath, sizeof(fpath));
1.1 jfb 151:
1.21 joris 152: if (cvs_sendentry(root, cfp) < 0)
153: return (CVS_EX_PROTO);
1.15 jfb 154:
155: switch (cfp->cf_cvstat) {
156: case CVS_FST_UNKNOWN:
1.20 jfb 157: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
1.15 jfb 158: break;
159: case CVS_FST_UPTODATE:
1.20 jfb 160: ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
1.15 jfb 161: break;
1.17 joris 162: case CVS_FST_ADDED:
1.15 jfb 163: case CVS_FST_MODIFIED:
1.20 jfb 164: ret = cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name);
1.15 jfb 165: if (ret == 0)
166: ret = cvs_sendfile(root, fpath);
167: default:
168: break;
169: }
170:
1.21 joris 171: if (ret == -1)
172: ret = CVS_EX_PROTO;
173:
1.15 jfb 174: return (ret);
175: }
176:
1.22 jfb 177: static int
178: cvs_status_local(CVSFILE *cf, void *arg)
1.15 jfb 179: {
1.22 jfb 180: int len;
1.35 xsa 181: size_t n;
182: char buf[MAXNAMLEN], fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
183: char numbuf[64], timebuf[32];
1.15 jfb 184: RCSFILE *rf;
1.41 xsa 185: struct rcs_sym *sym;
1.15 jfb 186:
1.33 xsa 187: if (cf->cf_type == DT_DIR) {
188: if (verbosity > 1)
1.43 ! xsa 189: cvs_log(LP_NOTICE, "Examining %s", cf->cf_name);
1.15 jfb 190: return (0);
1.33 xsa 191: }
1.15 jfb 192:
1.22 jfb 193: cvs_file_getpath(cf, fpath, sizeof(fpath));
1.1 jfb 194:
1.40 xsa 195: if (cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)) == NULL)
1.21 joris 196: return (CVS_EX_DATA);
1.1 jfb 197:
1.37 xsa 198: if (cf->cf_cvstat != CVS_FST_UNKNOWN &&
199: cf->cf_cvstat != CVS_FST_ADDED) {
1.30 xsa 200: rf = rcs_open(rcspath, RCS_READ);
201: if (rf == NULL)
202: return (CVS_EX_DATA);
203: }
1.5 jfb 204:
1.16 jfb 205: buf[0] = '\0';
1.30 xsa 206: if (cf->cf_cvstat == CVS_FST_LOST || cf->cf_cvstat == CVS_FST_UNKNOWN)
1.27 xsa 207: strlcpy(buf, "no file ", sizeof(buf));
1.22 jfb 208: strlcat(buf, cf->cf_name, sizeof(buf));
1.16 jfb 209:
1.28 xsa 210: cvs_printf(CVS_STATUS_SEP "\nFile: %-17s\tStatus: %s\n\n",
1.22 jfb 211: buf, cvs_statstr[cf->cf_cvstat]);
1.16 jfb 212:
1.22 jfb 213: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
1.32 joris 214: len = snprintf(buf, sizeof(buf), "No entry for %s",
215: cf->cf_name);
1.37 xsa 216: } else if (cf->cf_cvstat == CVS_FST_ADDED) {
217: len = snprintf(buf, sizeof(buf), "New file!");
1.16 jfb 218: } else {
1.37 xsa 219: rcsnum_tostr(cf->cf_lrev, numbuf, sizeof(numbuf));
220: len = snprintf(buf, sizeof(buf), "%s", numbuf);
1.35 xsa 221:
222: /* Display etime in local mode only. */
223: if (cvs_cmdop != CVS_OP_SERVER) {
224: strlcat(buf, "\t", sizeof(buf));
225:
226: ctime_r(&(cf->cf_etime), timebuf);
227: n = strlen(timebuf);
228: if ((n > 0) && (timebuf[n - 1] == '\n'))
1.36 xsa 229: timebuf[--n] = '\0';
1.35 xsa 230:
231: strlcat(buf, timebuf, sizeof(buf));
232: }
1.16 jfb 233: }
1.32 joris 234:
1.34 joris 235: if (len == -1 || len >= (int)sizeof(buf)) {
236: if (rf != NULL)
237: rcs_close(rf);
1.32 joris 238: return (CVS_EX_DATA);
1.34 joris 239: }
1.15 jfb 240:
1.28 xsa 241: cvs_printf(" Working revision:\t%s\n", buf);
1.30 xsa 242:
1.37 xsa 243: if (cf->cf_cvstat == CVS_FST_UNKNOWN ||
244: cf->cf_cvstat == CVS_FST_ADDED) {
245: len = snprintf(buf, sizeof(buf), "No revision control file");
1.30 xsa 246: } else {
1.34 joris 247: len = snprintf(buf, sizeof(buf), "%s\t%s",
1.30 xsa 248: rcsnum_tostr(rf->rf_head, numbuf, sizeof(numbuf)),
249: rcspath);
1.34 joris 250: }
251:
252: if (len == -1 || len >= (int)sizeof(buf)) {
253: if (rf != NULL)
254: rcs_close(rf);
255: return (CVS_EX_DATA);
1.30 xsa 256: }
257:
258: cvs_printf(" Repository revision:\t%s\n", buf);
259:
260: /* If the file is unknown, no other output is needed after this. */
1.37 xsa 261: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
262: cvs_printf("\n");
1.30 xsa 263: return (0);
1.37 xsa 264: }
1.30 xsa 265:
1.38 xsa 266: if (cf->cf_tag != NULL)
267: cvs_printf(" Sticky Tag:\t\t%s\n", cf->cf_tag);
268: else if (verbosity > 0)
269: cvs_printf(" Sticky Tag:\t\t(none)\n");
270:
271: /* XXX */
272: if (verbosity > 0)
273: cvs_printf(" Sticky Date:\t\t%s\n", "(none)");
274:
275: if (cf->cf_opts != NULL)
276: cvs_printf(" Sticky Options:\t%s\n", cf->cf_opts);
277: else if (verbosity > 0)
278: cvs_printf(" Sticky Options:\t(none)\n");
1.41 xsa 279:
280: if (verbose) {
281: cvs_printf("\n");
282: cvs_printf(" Existing Tags:\n");
283:
284: if (!TAILQ_EMPTY(&(rf->rf_symbols))) {
285: TAILQ_FOREACH(sym, &(rf->rf_symbols), rs_list) {
286: rcsnum_tostr(sym->rs_num, numbuf,
287: sizeof(numbuf));
288:
289: cvs_printf("\t%-25s\t(%s: %s)\n",
290: sym->rs_name,
291: RCSNUM_ISBRANCH(sym->rs_num) ? "branch" :
292: "revision", numbuf);
293: }
294: } else {
295: cvs_printf("\tNo Tags Exist\n");
296: }
297: }
1.15 jfb 298:
1.25 xsa 299: cvs_printf("\n");
1.15 jfb 300: rcs_close(rf);
301:
302: return (0);
1.1 jfb 303: }