xref: /openbsd-src/usr.bin/cvs/status.c (revision 4dcde51379711c241d4d9b93f9d4e9eae2d51f3d)
1*4dcde513Sjoris /*	$OpenBSD: status.c,v 1.100 2017/06/01 08:08:24 joris Exp $	*/
26036ca11Sjfb /*
33ad3fb45Sjoris  * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
4f736e780Sxsa  * Copyright (c) 2005-2008 Xavier Santolaria <xsa@openbsd.org>
56036ca11Sjfb  *
63ad3fb45Sjoris  * Permission to use, copy, modify, and distribute this software for any
73ad3fb45Sjoris  * purpose with or without fee is hereby granted, provided that the above
83ad3fb45Sjoris  * copyright notice and this permission notice appear in all copies.
96036ca11Sjfb  *
103ad3fb45Sjoris  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113ad3fb45Sjoris  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123ad3fb45Sjoris  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133ad3fb45Sjoris  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143ad3fb45Sjoris  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153ad3fb45Sjoris  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163ad3fb45Sjoris  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176036ca11Sjfb  */
186036ca11Sjfb 
19aaa6eb81Sjoris #include <stdlib.h>
201f8531bdSotto #include <string.h>
216534056aStobias #include <time.h>
221f8531bdSotto #include <unistd.h>
236036ca11Sjfb 
246036ca11Sjfb #include "cvs.h"
259fac60a5Sjoris #include "remote.h"
266036ca11Sjfb 
273ad3fb45Sjoris void	cvs_status_local(struct cvs_file *);
286036ca11Sjfb 
29f5174622Sxsa static int show_sym = 0;
30f5174622Sxsa 
31e4276007Sjfb struct cvs_cmd cvs_cmd_status = {
32f331ff59Stobias 	CVS_OP_STATUS, CVS_USE_WDIR, "status",
33e4276007Sjfb 	{ "st", "stat" },
34e4276007Sjfb 	"Display status information on checked out files",
35e4276007Sjfb 	"[-lRv]",
36f5174622Sxsa 	"lRv",
37e4276007Sjfb 	NULL,
383ad3fb45Sjoris 	cvs_status
3916cfc147Sjoris };
406036ca11Sjfb 
413ad3fb45Sjoris #define CVS_STATUS_SEP	\
423ad3fb45Sjoris 	"==================================================================="
4316cfc147Sjoris 
443ad3fb45Sjoris const char *status_tab[] = {
453ad3fb45Sjoris 	"Unknown",
463ad3fb45Sjoris 	"Locally Added",
473ad3fb45Sjoris 	"Locally Removed",
483ad3fb45Sjoris 	"Locally Modified",
493ad3fb45Sjoris 	"Up-to-date",
503ad3fb45Sjoris 	"Needs Checkout",
513ad3fb45Sjoris 	"Needs Checkout",
523ad3fb45Sjoris 	"Needs Merge",
533ad3fb45Sjoris 	"Needs Patch",
543ad3fb45Sjoris 	"Entry Invalid",
553ad3fb45Sjoris 	"Unresolved Conflict",
563ad3fb45Sjoris 	"Classifying error",
573ad3fb45Sjoris };
583ad3fb45Sjoris 
593ad3fb45Sjoris int
cvs_status(int argc,char ** argv)603ad3fb45Sjoris cvs_status(int argc, char **argv)
616036ca11Sjfb {
621890abdaSjoris 	int ch, flags;
633ad3fb45Sjoris 	char *arg = ".";
643ad3fb45Sjoris 	struct cvs_recursion cr;
656036ca11Sjfb 
669fac60a5Sjoris 	flags = CR_RECURSE_DIRS;
671890abdaSjoris 
683ad3fb45Sjoris 	while ((ch = getopt(argc, argv, cvs_cmd_status.cmd_opts)) != -1) {
696036ca11Sjfb 		switch (ch) {
70a922347aSjfb 		case 'l':
711890abdaSjoris 			flags &= ~CR_RECURSE_DIRS;
72a922347aSjfb 			break;
73a922347aSjfb 		case 'R':
74bcf22459Stobias 			flags |= CR_RECURSE_DIRS;
75a922347aSjfb 			break;
76a922347aSjfb 		case 'v':
77f5174622Sxsa 			show_sym = 1;
78a922347aSjfb 			break;
796036ca11Sjfb 		default:
803ad3fb45Sjoris 			fatal("%s", cvs_cmd_status.cmd_synopsis);
816036ca11Sjfb 		}
826036ca11Sjfb 	}
836036ca11Sjfb 
843ad3fb45Sjoris 	argc -= optind;
853ad3fb45Sjoris 	argv += optind;
866036ca11Sjfb 
873ad3fb45Sjoris 	cr.enterdir = NULL;
883ad3fb45Sjoris 	cr.leavedir = NULL;
899fac60a5Sjoris 
90*4dcde513Sjoris 	if (cvsroot_is_local()) {
919fac60a5Sjoris 		flags |= CR_REPO;
92bc5d89feSjoris 		cr.fileproc = cvs_status_local;
939fac60a5Sjoris 	} else {
9480f6ca9bSjoris 		cvs_client_connect_to_server();
959fac60a5Sjoris 		if (!(flags & CR_RECURSE_DIRS))
969fac60a5Sjoris 			cvs_client_send_request("Argument -l");
979fac60a5Sjoris 		if (show_sym)
989fac60a5Sjoris 			cvs_client_send_request("Argument -v");
999fac60a5Sjoris 		cr.fileproc = cvs_client_sendfile;
1009fac60a5Sjoris 	}
1019fac60a5Sjoris 
1021890abdaSjoris 	cr.flags = flags;
103b6207e53Sxsa 
1043ad3fb45Sjoris 	if (argc > 0)
1053ad3fb45Sjoris 		cvs_file_run(argc, argv, &cr);
106b5f0ecd9Sjfb 	else
1073ad3fb45Sjoris 		cvs_file_run(1, &arg, &cr);
108235ffbbdSjfb 
109*4dcde513Sjoris 	if (cvsroot_is_remote()) {
1109fac60a5Sjoris 		cvs_client_send_files(argv, argc);
1119fac60a5Sjoris 		cvs_client_senddir(".");
1129fac60a5Sjoris 		cvs_client_send_request("status");
1139fac60a5Sjoris 		cvs_client_get_responses();
1149fac60a5Sjoris 	}
1159fac60a5Sjoris 
1167e393898Sjoris 	return (0);
117235ffbbdSjfb }
118235ffbbdSjfb 
1193ad3fb45Sjoris void
cvs_status_local(struct cvs_file * cf)1203ad3fb45Sjoris cvs_status_local(struct cvs_file *cf)
121235ffbbdSjfb {
1223ad3fb45Sjoris 	size_t len;
123aaa6eb81Sjoris 	RCSNUM *head, *brev;
1243ad3fb45Sjoris 	const char *status;
125d433019cSstsp 	struct rcs_delta *rdp;
126b9fc9a72Sderaadt 	char buf[PATH_MAX + CVS_REV_BUFSZ + 128];
1277d7c52beSmillert 	char timebuf[CVS_TIME_BUFSZ], revbuf[CVS_REV_BUFSZ];
128f5174622Sxsa 	struct rcs_sym *sym;
129235ffbbdSjfb 
1303ad3fb45Sjoris 	cvs_log(LP_TRACE, "cvs_status_local(%s)", cf->file_path);
1313ad3fb45Sjoris 
13251ef6581Sjoris 	cvs_file_classify(cf, cvs_directory_tag);
1333ad3fb45Sjoris 
1343ad3fb45Sjoris 	if (cf->file_type == CVS_DIR) {
1357d73e7b0Sxsa 		if (verbosity > 1)
1363ad3fb45Sjoris 			cvs_log(LP_NOTICE, "Examining %s", cf->file_path);
1373ad3fb45Sjoris 		return;
1387d73e7b0Sxsa 	}
139235ffbbdSjfb 
1405cf15c45Sjoris 	if (cf->file_status == FILE_UPTODATE &&
1415cf15c45Sjoris 	    !(cf->file_flags & FILE_ON_DISK) &&
14298902223Sjoris 	    !(cf->file_flags & FILE_USER_SUPPLIED))
143fd5737cbSjoris 		return;
144fd5737cbSjoris 
145e28eda4eStobias 	if (cf->file_rcs != NULL)
1462d6bc62cSjoris 		head = cf->file_rcsrev;
147e28eda4eStobias 	else
148725515b2Sjoris 		head = NULL;
1499af0ab72Stobias 
1503ad3fb45Sjoris 	cvs_printf("%s\n", CVS_STATUS_SEP);
1516036ca11Sjfb 
152e28eda4eStobias 	if (cf->file_rcs != NULL && head == NULL)
153e28eda4eStobias 		status = status_tab[FILE_UNKNOWN];
154e28eda4eStobias 	else
1553ad3fb45Sjoris 		status = status_tab[cf->file_status];
156e28eda4eStobias 
1573ad3fb45Sjoris 	if (cf->file_status == FILE_MODIFIED &&
1583ad3fb45Sjoris 	    cf->file_ent->ce_conflict != NULL)
1593ad3fb45Sjoris 		status = "File had conflicts on merge";
1606036ca11Sjfb 
1615cf15c45Sjoris 	if (!(cf->file_flags & FILE_ON_DISK)) {
162c486465dSxsa 		(void)xsnprintf(buf, sizeof(buf), "no file %s\t",
163c486465dSxsa 		    cf->file_name);
164fd443860Sxsa 	} else
165fd443860Sxsa 		if (strlcpy(buf, cf->file_name, sizeof(buf)) >= sizeof(buf))
166fd443860Sxsa 			fatal("cvs_status_local: overflow");
167fd443860Sxsa 
168fd443860Sxsa 	cvs_printf("File: %-17s\tStatus: %s\n\n", buf, status);
169553914b8Sxsa 
1703ad3fb45Sjoris 	if (cf->file_ent == NULL) {
171c486465dSxsa 		(void)xsnprintf(buf, sizeof(buf),
1723ad3fb45Sjoris 		    "No entry for %s", cf->file_name);
173e28eda4eStobias 	} else if (cf->file_ent->ce_status == CVS_ENT_ADDED) {
1743ad3fb45Sjoris 		len = strlcpy(buf, "New file!", sizeof(buf));
1753ad3fb45Sjoris 		if (len >= sizeof(buf))
1763ad3fb45Sjoris 			fatal("cvs_status_local: truncation");
177d32a75e7Sjfb 	} else {
1783ad3fb45Sjoris 		rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
1790b9511b4Sxsa 
1803ad3fb45Sjoris 		if (cf->file_ent->ce_conflict == NULL) {
18101d427ddSjoris 			if (cvs_server_active == 0) {
182694b1da3Sstsp 				(void)strlcpy(timebuf, cf->file_ent->ce_time,
183694b1da3Sstsp 				    sizeof(timebuf));
1843ad3fb45Sjoris 			} else {
18501d427ddSjoris 				timebuf[0] = '\0';
18601d427ddSjoris 			}
18701d427ddSjoris 		} else {
1883ad3fb45Sjoris 			len = strlcpy(timebuf, cf->file_ent->ce_conflict,
1893ad3fb45Sjoris 			    sizeof(timebuf));
1903ad3fb45Sjoris 			if (len >= sizeof(timebuf))
1913ad3fb45Sjoris 				fatal("cvs_status_local: truncation");
1920b9511b4Sxsa 		}
1933ad3fb45Sjoris 
1940d508764Sxsa 		(void)strlcpy(buf, revbuf, sizeof(buf));
1950d508764Sxsa 		if (cvs_server_active == 0) {
1960d508764Sxsa 			(void)strlcat(buf, "\t", sizeof(buf));
1970d508764Sxsa 			(void)strlcat(buf, timebuf, sizeof(buf));
1980d508764Sxsa 		}
199d32a75e7Sjfb 	}
200d32a75e7Sjfb 
2014b74b9b9Sxsa 	cvs_printf("   Working revision:\t%s\n", buf);
202d12f10c0Sxsa 
2033ad3fb45Sjoris 	buf[0] = '\0';
204e28eda4eStobias 	if (cf->file_rcs == NULL) {
2053ad3fb45Sjoris 		len = strlcat(buf, "No revision control file", sizeof(buf));
2063ad3fb45Sjoris 		if (len >= sizeof(buf))
2073ad3fb45Sjoris 			fatal("cvs_status_local: truncation");
208e28eda4eStobias 	} else if (head == NULL) {
209e28eda4eStobias 		len = strlcat(buf, "No head revision", sizeof(buf));
210e28eda4eStobias 		if (len >= sizeof(buf))
211e28eda4eStobias 			fatal("cvs_status_local: truncation");
212d12f10c0Sxsa 	} else {
213570941ffSjoris 		rcsnum_tostr(head, revbuf, sizeof(revbuf));
214c486465dSxsa 		(void)xsnprintf(buf, sizeof(buf), "%s\t%s", revbuf,
2153ad3fb45Sjoris 		    cf->file_rpath);
216ce2fed3bSjoris 	}
217ce2fed3bSjoris 
218d12f10c0Sxsa 	cvs_printf("   Repository revision:\t%s\n", buf);
219d12f10c0Sxsa 
220d433019cSstsp 	if (cf->file_rcs != NULL && head != NULL) {
221d433019cSstsp 		rdp = rcs_findrev(cf->file_rcs, head);
222d433019cSstsp 		if (rdp == NULL) {
223d433019cSstsp 			fatal("cvs_status_local: No head revision delta");
224d433019cSstsp 		}
225d433019cSstsp 
226d433019cSstsp 		cvs_printf("   Commit Identifier:\t%s\n",
227d433019cSstsp 		    (rdp->rd_commitid != NULL) ? rdp->rd_commitid : "(none)");
228d433019cSstsp 	}
229d433019cSstsp 
2303ad3fb45Sjoris 	if (cf->file_ent != NULL) {
231aaa6eb81Sjoris 		if (cf->file_ent->ce_tag != NULL) {
232aaa6eb81Sjoris 			if ((brev = rcs_sym_getrev(cf->file_rcs,
233aaa6eb81Sjoris 			    cf->file_ent->ce_tag)) == NULL) {
234aaa6eb81Sjoris 				(void)strlcpy(buf, "- MISSING from RCS file!",
235aaa6eb81Sjoris 				    sizeof(buf));
236aaa6eb81Sjoris 			} else {
237aaa6eb81Sjoris 				rcsnum_tostr(brev, revbuf, sizeof(revbuf));
238d884564eSjoris 				if (RCSNUM_ISBRANCH(brev)) {
239d884564eSjoris 					xsnprintf(buf, sizeof(buf),
240aaa6eb81Sjoris 					    "(branch: %s)", revbuf);
241d884564eSjoris 				} else {
242d884564eSjoris 					xsnprintf(buf, sizeof(buf),
243d884564eSjoris 					    "(revision: %s)", revbuf);
244d884564eSjoris 				}
245aaa6eb81Sjoris 				free(brev);
246aaa6eb81Sjoris 			}
247aaa6eb81Sjoris 
248aaa6eb81Sjoris 			cvs_printf("   Sticky Tag:\t\t%s %s\n",
249aaa6eb81Sjoris 			    cf->file_ent->ce_tag, buf);
250aaa6eb81Sjoris 		} else if (verbosity > 0) {
25102ae6043Sxsa 			cvs_printf("   Sticky Tag:\t\t(none)\n");
252aaa6eb81Sjoris 		}
25302ae6043Sxsa 
254f736e780Sxsa 		if (cf->file_ent->ce_date != -1) {
2556534056aStobias 			struct tm datetm;
256f736e780Sxsa 			char datetmp[CVS_TIME_BUFSZ];
257f736e780Sxsa 
2586534056aStobias 			gmtime_r(&(cf->file_ent->ce_date), &datetm);
259f736e780Sxsa                         (void)strftime(datetmp, sizeof(datetmp),
2606534056aStobias 			    CVS_DATE_FMT, &datetm);
261f736e780Sxsa 
262f736e780Sxsa 			cvs_printf("   Sticky Date:\t\t%s\n", datetmp);
263f736e780Sxsa 		} else if (verbosity > 0)
264f736e780Sxsa 			cvs_printf("   Sticky Date:\t\t(none)\n");
265f736e780Sxsa 
2663ad3fb45Sjoris 		if (cf->file_ent->ce_opts != NULL)
2673ad3fb45Sjoris 			cvs_printf("   Sticky Options:\t%s\n",
2683ad3fb45Sjoris 			    cf->file_ent->ce_opts);
26902ae6043Sxsa 		else if (verbosity > 0)
27002ae6043Sxsa 			cvs_printf("   Sticky Options:\t(none)\n");
271077dcb78Sxsa 	}
272077dcb78Sxsa 
2737e3fae51Sjoris 	if (cf->file_rcs != NULL && show_sym == 1) {
274f5174622Sxsa 		cvs_printf("\n");
275f5174622Sxsa 		cvs_printf("   Existing Tags:\n");
276f5174622Sxsa 
277f5174622Sxsa 		if (!TAILQ_EMPTY(&(cf->file_rcs->rf_symbols))) {
278f5174622Sxsa 			TAILQ_FOREACH(sym,
279f5174622Sxsa 			    &(cf->file_rcs->rf_symbols), rs_list) {
280f5174622Sxsa 				(void)rcsnum_tostr(sym->rs_num, revbuf,
281f5174622Sxsa 				    sizeof(revbuf));
282f5174622Sxsa 
283f5174622Sxsa 				cvs_printf("\t%-25s\t(%s: %s)\n", sym->rs_name,
284f5174622Sxsa 				    RCSNUM_ISBRANCH(sym->rs_num) ? "branch" :
285f5174622Sxsa 				    "revision", revbuf);
286f5174622Sxsa 			 }
287f5174622Sxsa 		} else
288f5174622Sxsa 			cvs_printf("\tNo Tags Exist\n");
289f5174622Sxsa 	}
290f5174622Sxsa 
291f0c47733Sxsa 	cvs_printf("\n");
2926036ca11Sjfb }
293