xref: /openbsd/usr.bin/cvs/getlog.c (revision 84c3cb67)
1*84c3cb67Sxsa /*	$OpenBSD: getlog.c,v 1.25 2005/05/19 15:37:50 xsa Exp $	*/
26c121f58Sjfb /*
36c121f58Sjfb  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
46c121f58Sjfb  * All rights reserved.
56c121f58Sjfb  *
66c121f58Sjfb  * Redistribution and use in source and binary forms, with or without
76c121f58Sjfb  * modification, are permitted provided that the following conditions
86c121f58Sjfb  * are met:
96c121f58Sjfb  *
106c121f58Sjfb  * 1. Redistributions of source code must retain the above copyright
116c121f58Sjfb  *    notice, this list of conditions and the following disclaimer.
126c121f58Sjfb  * 2. The name of the author may not be used to endorse or promote products
136c121f58Sjfb  *    derived from this software without specific prior written permission.
146c121f58Sjfb  *
156c121f58Sjfb  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
166c121f58Sjfb  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
176c121f58Sjfb  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
186c121f58Sjfb  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
196c121f58Sjfb  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
206c121f58Sjfb  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
216c121f58Sjfb  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
226c121f58Sjfb  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
236c121f58Sjfb  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
246c121f58Sjfb  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
256c121f58Sjfb  */
266c121f58Sjfb 
276c121f58Sjfb #include <sys/param.h>
286c121f58Sjfb 
296c121f58Sjfb #include <stdlib.h>
306c121f58Sjfb #include <stdio.h>
316c121f58Sjfb #include <unistd.h>
326c121f58Sjfb #include <errno.h>
336c121f58Sjfb #include <string.h>
346c121f58Sjfb #include <paths.h>
356c121f58Sjfb 
366c121f58Sjfb #include "cvs.h"
376c121f58Sjfb #include "log.h"
38a96bf98bSjfb #include "file.h"
39dc6a6879Sjfb #include "proto.h"
406c121f58Sjfb 
416c121f58Sjfb 
426c121f58Sjfb #define CVS_GLOG_RFONLY    0x01
436c121f58Sjfb #define CVS_GLOG_HDONLY    0x02
446c121f58Sjfb 
456c121f58Sjfb 
466c121f58Sjfb #define CVS_GETLOG_REVSEP   "----------------------------"
476c121f58Sjfb #define CVS_GETLOG_REVEND \
486c121f58Sjfb  "============================================================================="
496c121f58Sjfb 
50874e0b9fSjfb static int cvs_getlog_remote  (CVSFILE *, void *);
519931af54Sjfb static int cvs_getlog_local   (CVSFILE *, void *);
52*84c3cb67Sxsa static int cvs_getlog_options(char *, int, char **, int *);
53*84c3cb67Sxsa static int cvs_getlog_sendflags(struct cvsroot *);
546c121f58Sjfb 
5516cfc147Sjoris struct cvs_cmd_info cvs_getlog = {
5616cfc147Sjoris 	cvs_getlog_options,
57*84c3cb67Sxsa 	cvs_getlog_sendflags,
58874e0b9fSjfb 	cvs_getlog_remote,
5916cfc147Sjoris 	NULL, NULL,
60fcc15918Sjoris 	CF_IGNORE | CF_RECURSE,
6116cfc147Sjoris 	CVS_REQ_LOG,
6216cfc147Sjoris 	CVS_CMD_SENDDIR | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2
6316cfc147Sjoris };
646c121f58Sjfb 
65874e0b9fSjfb static int log_rfonly = 0;
66874e0b9fSjfb static int log_honly = 0;
67*84c3cb67Sxsa static int log_lhonly = 0;
68874e0b9fSjfb static int log_notags = 0;
6916cfc147Sjoris 
70*84c3cb67Sxsa static int
7116cfc147Sjoris cvs_getlog_options(char *opt, int argc, char **argv, int *arg)
726c121f58Sjfb {
7316cfc147Sjoris 	int ch;
746c121f58Sjfb 
7516cfc147Sjoris 	while ((ch = getopt(argc, argv, opt)) != -1) {
7616cfc147Sjoris 		switch (ch) {
77*84c3cb67Sxsa 		case 'b':
78*84c3cb67Sxsa 			break;
796c121f58Sjfb 		case 'd':
806c121f58Sjfb 			break;
816c121f58Sjfb 		case 'h':
82874e0b9fSjfb 			log_honly = 1;
836c121f58Sjfb 			break;
846c121f58Sjfb 		case 'l':
8516cfc147Sjoris 			cvs_getlog.file_flags &= ~CF_RECURSE;
866c121f58Sjfb 			break;
87874e0b9fSjfb 		case 'N':
88874e0b9fSjfb 			log_notags = 1;
89874e0b9fSjfb 			break;
906c121f58Sjfb 		case 'R':
91874e0b9fSjfb 			log_rfonly = 1;
926c121f58Sjfb 			break;
936c121f58Sjfb 		case 'r':
946c121f58Sjfb 			break;
95*84c3cb67Sxsa 		case 's':
96*84c3cb67Sxsa 			break;
97*84c3cb67Sxsa 		case 't':
98*84c3cb67Sxsa 			log_lhonly = 1;
99*84c3cb67Sxsa 			break;
100*84c3cb67Sxsa 		case 'w':
101*84c3cb67Sxsa 			break;
1026c121f58Sjfb 		default:
10331274bbfSjoris 			return (CVS_EX_USAGE);
1046c121f58Sjfb 		}
1056c121f58Sjfb 	}
1066c121f58Sjfb 
10716cfc147Sjoris 	*arg = optind;
1086c121f58Sjfb 	return (0);
1096c121f58Sjfb }
1106c121f58Sjfb 
111*84c3cb67Sxsa static int
112*84c3cb67Sxsa cvs_getlog_sendflags(struct cvsroot *root)
113*84c3cb67Sxsa {
114*84c3cb67Sxsa 	if (log_honly && (cvs_sendarg(root, "-h", 0) < 0))
115*84c3cb67Sxsa 		return (CVS_EX_PROTO);
116*84c3cb67Sxsa 	if (log_notags && (cvs_sendarg(root, "-N", 0) < 0))
117*84c3cb67Sxsa 		return (CVS_EX_PROTO);
118*84c3cb67Sxsa 	if (log_rfonly && (cvs_sendarg(root, "-R", 0) < 0))
119*84c3cb67Sxsa 		return (CVS_EX_PROTO);
120*84c3cb67Sxsa 	if (log_lhonly && (cvs_sendarg(root, "-t", 0) < 0))
121*84c3cb67Sxsa 		return (CVS_EX_PROTO);
122*84c3cb67Sxsa 
123*84c3cb67Sxsa 	return (0);
124*84c3cb67Sxsa }
1256c121f58Sjfb 
126a96bf98bSjfb /*
127874e0b9fSjfb  * cvs_getlog_remote()
128a96bf98bSjfb  *
129a96bf98bSjfb  */
130a96bf98bSjfb static int
131874e0b9fSjfb cvs_getlog_remote(CVSFILE *cf, void *arg)
132a96bf98bSjfb {
13325c4314aSjfb 	int ret;
134c710bc5aSjfb 	char *repo, fpath[MAXPATHLEN];
135a96bf98bSjfb 	struct cvsroot *root;
136df745765Sjfb 
13725c4314aSjfb 	ret = 0;
13825c4314aSjfb 	root = CVS_DIR_ROOT(cf);
13925c4314aSjfb 	repo = CVS_DIR_REPO(cf);
140a96bf98bSjfb 
141b5f0ecd9Sjfb 	if (cf->cf_type == DT_DIR) {
14225c4314aSjfb 		if (cf->cf_cvstat == CVS_FST_UNKNOWN)
14325c4314aSjfb 			ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE,
144c710bc5aSjfb 			    CVS_FILE_NAME(cf));
14525c4314aSjfb 		else
14625c4314aSjfb 			ret = cvs_senddir(root, cf);
14725c4314aSjfb 		return (ret);
148a96bf98bSjfb 	}
149a96bf98bSjfb 
15025c4314aSjfb 	cvs_file_getpath(cf, fpath, sizeof(fpath));
151a96bf98bSjfb 
152bb029937Sjfb 	if (cvs_sendentry(root, cf) < 0) {
1539931af54Sjfb 		return (-1);
154a96bf98bSjfb 	}
155a96bf98bSjfb 
156a96bf98bSjfb 	switch (cf->cf_cvstat) {
15725c4314aSjfb 	case CVS_FST_UNKNOWN:
158874e0b9fSjfb 		ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
15925c4314aSjfb 		break;
160a96bf98bSjfb 	case CVS_FST_UPTODATE:
161874e0b9fSjfb 		ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
162a96bf98bSjfb 		break;
163a96bf98bSjfb 	case CVS_FST_ADDED:
164a96bf98bSjfb 	case CVS_FST_MODIFIED:
165874e0b9fSjfb 		ret = cvs_sendreq(root, CVS_REQ_ISMODIFIED, cf->cf_name);
166a96bf98bSjfb 		break;
167a96bf98bSjfb 	default:
16825c4314aSjfb 		break;
169a96bf98bSjfb 	}
17025c4314aSjfb 
17125c4314aSjfb 	return (ret);
172a96bf98bSjfb }
173df745765Sjfb 
1746c121f58Sjfb 
1759931af54Sjfb 
1769931af54Sjfb static int
1779931af54Sjfb cvs_getlog_local(CVSFILE *cf, void *arg)
1789931af54Sjfb {
1796842d763Sxsa 	int nrev, l;
180874e0b9fSjfb 	char rcspath[MAXPATHLEN], numbuf[64];
1819931af54Sjfb 	char *repo;
1829931af54Sjfb 	RCSFILE *rf;
1839931af54Sjfb 	struct rcs_sym *sym;
1849931af54Sjfb 	struct rcs_delta *rdp;
185874e0b9fSjfb 	struct rcs_access *acp;
1869931af54Sjfb 	struct cvsroot *root;
1879931af54Sjfb 
1889931af54Sjfb 	if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
189874e0b9fSjfb 		cvs_log(LP_WARN, "nothing known about %s", cf->cf_name);
1909931af54Sjfb 		return (0);
1919931af54Sjfb 	}
1929931af54Sjfb 
193874e0b9fSjfb 	if (cf->cf_type == DT_DIR) {
194874e0b9fSjfb 		cvs_log(LP_INFO, "Logging %s", cf->cf_name);
1959931af54Sjfb 		return (0);
196874e0b9fSjfb 	}
1979931af54Sjfb 
1989931af54Sjfb 	nrev = 0;
1999931af54Sjfb 	root = CVS_DIR_ROOT(cf);
2009931af54Sjfb 	repo = CVS_DIR_REPO(cf);
2019931af54Sjfb 
2026842d763Sxsa 	l = snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s",
2039931af54Sjfb 	    root->cr_dir, repo, CVS_FILE_NAME(cf), RCS_FILE_EXT);
2046842d763Sxsa 	if (l == -1 || l >= (int)sizeof(rcspath)) {
2056842d763Sxsa 		errno = ENAMETOOLONG;
2066842d763Sxsa 		 cvs_log(LP_ERRNO, "%s", rcspath);
2076842d763Sxsa 		return (-1);
2086842d763Sxsa 	}
2099931af54Sjfb 
210874e0b9fSjfb 	if (log_rfonly) {
211874e0b9fSjfb 		cvs_printf("%s\n", rcspath);
212874e0b9fSjfb 		return (0);
213874e0b9fSjfb 	}
214874e0b9fSjfb 
2159931af54Sjfb 	rf = rcs_open(rcspath, RCS_READ);
2169931af54Sjfb 	if (rf == NULL)
2179931af54Sjfb 		return (-1);
2189931af54Sjfb 
2199931af54Sjfb 	cvs_printf("\nRCS file: %s\nWorking file: %s\n", rcspath, cf->cf_name);
2209931af54Sjfb 	cvs_printf("head: %s\n",
2219931af54Sjfb 	    rcsnum_tostr(rcs_head_get(rf), numbuf, sizeof(numbuf)));
2229931af54Sjfb 	cvs_printf("branch: %s\n",
2239931af54Sjfb 	    rcsnum_tostr(rcs_branch_get(rf), numbuf, sizeof(numbuf)));
224874e0b9fSjfb 	cvs_printf("locks: %s\n", (rf->rf_flags & RCS_SLOCK) ? "strict" : "");
2259931af54Sjfb 
226874e0b9fSjfb 	cvs_printf("access list:\n");
227874e0b9fSjfb 	TAILQ_FOREACH(acp, &(rf->rf_access), ra_list)
228874e0b9fSjfb 		cvs_printf("\t%s\n", acp->ra_name);
229874e0b9fSjfb 
230874e0b9fSjfb 	if (!log_notags) {
2319931af54Sjfb 		cvs_printf("symbolic names:\n");
232874e0b9fSjfb 		TAILQ_FOREACH(sym, &(rf->rf_symbols), rs_list)
2339931af54Sjfb 			cvs_printf("\t%s: %s\n", sym->rs_name,
2349931af54Sjfb 			    rcsnum_tostr(sym->rs_num, numbuf, sizeof(numbuf)));
2359931af54Sjfb 	}
236874e0b9fSjfb 
2379931af54Sjfb 	cvs_printf("keyword substitution: %s\n", "");
238874e0b9fSjfb 
239874e0b9fSjfb 	if (log_honly)
240874e0b9fSjfb 		cvs_printf("total revisions: %u;\n", rf->rf_ndelta);
241874e0b9fSjfb 	else {
2429931af54Sjfb 		cvs_printf("total revisions: %u;\tselected revisions: %u\n",
2439931af54Sjfb 		    rf->rf_ndelta, nrev);
244874e0b9fSjfb 		cvs_printf("description:\n%s", rf->rf_desc);
2459931af54Sjfb 		TAILQ_FOREACH(rdp, &(rf->rf_delta), rd_list) {
246df745765Sjfb 			rcsnum_tostr(rdp->rd_num, numbuf, sizeof(numbuf));
2479931af54Sjfb 			cvs_printf(CVS_GETLOG_REVSEP "\nrevision %s\n", numbuf);
248874e0b9fSjfb 			cvs_printf("date: %d/%02d/%02d %02d:%02d:%02d;"
249874e0b9fSjfb 		    	    "  author: %s;  state: %s;\n",
250874e0b9fSjfb 			    rdp->rd_date.tm_year + 1900,
251874e0b9fSjfb 			    rdp->rd_date.tm_mon + 1,
2526c121f58Sjfb 			    rdp->rd_date.tm_mday, rdp->rd_date.tm_hour,
2536c121f58Sjfb 			    rdp->rd_date.tm_min, rdp->rd_date.tm_sec,
2546c121f58Sjfb 			    rdp->rd_author, rdp->rd_state);
2559931af54Sjfb 			cvs_printf("%s", rdp->rd_log);
2566c121f58Sjfb 		}
257874e0b9fSjfb 	}
2586c121f58Sjfb 
259a96bf98bSjfb 	cvs_printf(CVS_GETLOG_REVEND "\n");
2609931af54Sjfb 
2619931af54Sjfb 	rcs_close(rf);
2629931af54Sjfb 
2639931af54Sjfb 	return (0);
2646c121f58Sjfb }
265