xref: /openbsd-src/usr.bin/cvs/history.c (revision 66ad965f4873a0970dea06fb53c307b8385e5a94)
1 /*	$OpenBSD: history.c,v 1.35 2008/01/31 10:15:05 tobias Exp $	*/
2 /*
3  * Copyright (c) 2007 Joris Vink <joris@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/stat.h>
19 
20 #include <ctype.h>
21 #include <errno.h>
22 #include <pwd.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "cvs.h"
28 #include "remote.h"
29 
30 void	cvs_history_local(struct cvs_file *);
31 
32 struct cvs_cmd		cvs_cmd_history = {
33 	CVS_OP_HISTORY, CVS_USE_WDIR, "history",
34 	{ "hi", "his" },			/* omghi2you */
35 	"Display history of actions done in the base repository",
36 	"[-ac]",
37 	"ac",
38 	NULL,
39 	cvs_history
40 };
41 
42 /* keep in sync with the defines for history stuff in cvs.h */
43 const char historytab[] = {
44 	'T',
45 	'O',
46 	'E',
47 	'F',
48 	'W',
49 	'U',
50 	'G',
51 	'C',
52 	'M',
53 	'A',
54 	'R',
55 	'\0'
56 };
57 
58 #define HISTORY_ALL_USERS		0x01
59 #define HISTORY_DISPLAY_ARCHIVED	0x02
60 
61 void
62 cvs_history_add(int type, struct cvs_file *cf, const char *argument)
63 {
64 	FILE *fp;
65 	char *cwd;
66 	char revbuf[CVS_REV_BUFSZ], repo[MAXPATHLEN], fpath[MAXPATHLEN];
67 
68 	if (cvs_nolog == 1)
69 		return;
70 
71 	if (cvs_cmdop == CVS_OP_CHECKOUT || cvs_cmdop == CVS_OP_EXPORT) {
72 		if (type != CVS_HISTORY_CHECKOUT &&
73 		    type != CVS_HISTORY_EXPORT)
74 			return;
75 	}
76 
77 	cvs_log(LP_TRACE, "cvs_history_add(`%c', `%s', `%s')",
78 	    historytab[type], (cf != NULL) ? cf->file_name : "", argument);
79 
80 	if (cvs_server_active == 1) {
81 		cwd = "<remote>";
82 	} else {
83 		if ((cwd = getcwd(NULL, MAXPATHLEN)) == NULL)
84 			fatal("cvs_history_add: getcwd: %s", strerror(errno));
85 	}
86 
87 	/* construct repository field */
88 	if (cvs_cmdop != CVS_OP_CHECKOUT && cvs_cmdop != CVS_OP_EXPORT) {
89 		cvs_get_repository_name(".", repo, sizeof(repo));
90 	} else {
91 		strlcpy(repo, argument, sizeof(repo));
92 	}
93 
94 	/* construct revision field */
95 	revbuf[0] = '\0';
96 	if (cvs_cmdop != CVS_OP_CHECKOUT && cvs_cmdop != CVS_OP_EXPORT) {
97 		switch (type) {
98 		case CVS_HISTORY_TAG:
99 			strlcpy(revbuf, argument, sizeof(revbuf));
100 			break;
101 		case CVS_HISTORY_CHECKOUT:
102 		case CVS_HISTORY_EXPORT:
103 			/* copy TAG or DATE to revbuf */
104 			break;
105 		case CVS_HISTORY_UPDATE_MERGED:
106 		case CVS_HISTORY_UPDATE_MERGED_ERR:
107 		case CVS_HISTORY_COMMIT_MODIFIED:
108 		case CVS_HISTORY_COMMIT_ADDED:
109 		case CVS_HISTORY_COMMIT_REMOVED:
110 		case CVS_HISTORY_UPDATE_CO:
111 			rcsnum_tostr(cf->file_rcs->rf_head,
112 			    revbuf, sizeof(revbuf));
113 			break;
114 		}
115 	}
116 
117 	(void)xsnprintf(fpath, sizeof(fpath), "%s/%s",
118 	    current_cvsroot->cr_dir, CVS_PATH_HISTORY);
119 
120 	if ((fp = fopen(fpath, "a")) != NULL) {
121 		fprintf(fp, "%c%x|%s|%s|%s|%s|%s\n",
122 		    historytab[type], time(NULL), getlogin(), cwd, repo,
123 		    revbuf, (cf != NULL) ? cf->file_name : argument);
124 
125 		(void)fclose(fp);
126 	} else {
127 		cvs_log(LP_ERR, "failed to add entry to history file");
128 	}
129 
130 	if (cvs_server_active != 1)
131 		xfree(cwd);
132 }
133 
134 int
135 cvs_history(int argc, char **argv)
136 {
137 	int ch, flags;
138 
139 	flags = 0;
140 
141 	while ((ch = getopt(argc, argv, cvs_cmd_history.cmd_opts)) != -1) {
142 		switch (ch) {
143 		case 'a':
144 			flags |= HISTORY_ALL_USERS;
145 			break;
146 		case 'c':
147 			flags |= HISTORY_DISPLAY_ARCHIVED;
148 			break;
149 		default:
150 			fatal("%s", cvs_cmd_history.cmd_synopsis);
151 		}
152 	}
153 
154 	argc -= optind;
155 	argv += optind;
156 
157 	return (0);
158 }
159