1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3*86d7f5d3SJohn Marino *
4*86d7f5d3SJohn Marino * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5*86d7f5d3SJohn Marino * and others.
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8*86d7f5d3SJohn Marino * Portions Copyright (C) 1989-1992, Brian Berliner
9*86d7f5d3SJohn Marino *
10*86d7f5d3SJohn Marino * You may distribute under the terms of the GNU General Public License as
11*86d7f5d3SJohn Marino * specified in the README file that comes with the CVS kit. */
12*86d7f5d3SJohn Marino
13*86d7f5d3SJohn Marino #include "cvs.h"
14*86d7f5d3SJohn Marino #include "getline.h"
15*86d7f5d3SJohn Marino #include "history.h"
16*86d7f5d3SJohn Marino #include "save-cwd.h"
17*86d7f5d3SJohn Marino
18*86d7f5d3SJohn Marino #ifndef DBLKSIZ
19*86d7f5d3SJohn Marino #define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */
20*86d7f5d3SJohn Marino #endif
21*86d7f5d3SJohn Marino
22*86d7f5d3SJohn Marino static int checkout_file (char *file, char *temp);
23*86d7f5d3SJohn Marino static char *make_tempfile (void);
24*86d7f5d3SJohn Marino static void rename_rcsfile (char *temp, char *real);
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino #ifndef MY_NDBM
27*86d7f5d3SJohn Marino static void rename_dbmfile (char *temp);
28*86d7f5d3SJohn Marino static void write_dbmfile (char *temp);
29*86d7f5d3SJohn Marino #endif /* !MY_NDBM */
30*86d7f5d3SJohn Marino
31*86d7f5d3SJohn Marino /* Structure which describes an administrative file. */
32*86d7f5d3SJohn Marino struct admin_file {
33*86d7f5d3SJohn Marino /* Name of the file, within the CVSROOT directory. */
34*86d7f5d3SJohn Marino char *filename;
35*86d7f5d3SJohn Marino
36*86d7f5d3SJohn Marino /* This is a one line description of what the file is for. It is not
37*86d7f5d3SJohn Marino currently used, although one wonders whether it should be, somehow.
38*86d7f5d3SJohn Marino If NULL, then don't process this file in mkmodules (FIXME?: a bit of
39*86d7f5d3SJohn Marino a kludge; probably should replace this with a flags field). */
40*86d7f5d3SJohn Marino char *errormsg;
41*86d7f5d3SJohn Marino
42*86d7f5d3SJohn Marino /* Contents which the file should have in a new repository. To avoid
43*86d7f5d3SJohn Marino problems with brain-dead compilers which choke on long string constants,
44*86d7f5d3SJohn Marino this is a pointer to an array of char * terminated by NULL--each of
45*86d7f5d3SJohn Marino the strings is concatenated.
46*86d7f5d3SJohn Marino
47*86d7f5d3SJohn Marino If this field is NULL, the file is not created in a new
48*86d7f5d3SJohn Marino repository, but it can be added with "cvs add" (just as if one
49*86d7f5d3SJohn Marino had created the repository with a version of CVS which didn't
50*86d7f5d3SJohn Marino know about the file) and the checked-out copy will be updated
51*86d7f5d3SJohn Marino without having to add it to checkoutlist. */
52*86d7f5d3SJohn Marino const char * const *contents;
53*86d7f5d3SJohn Marino };
54*86d7f5d3SJohn Marino
55*86d7f5d3SJohn Marino static const char *const loginfo_contents[] = {
56*86d7f5d3SJohn Marino "# The \"loginfo\" file controls where \"cvs commit\" log information is\n",
57*86d7f5d3SJohn Marino "# sent. The first entry on a line is a regular expression which must\n",
58*86d7f5d3SJohn Marino "# match the directory that the change is being made to, relative to the\n",
59*86d7f5d3SJohn Marino "# $CVSROOT. If a match is found, then the remainder of the line is a\n",
60*86d7f5d3SJohn Marino "# filter program that should expect log information on its standard input.\n",
61*86d7f5d3SJohn Marino "#\n",
62*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
63*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
64*86d7f5d3SJohn Marino "#\n",
65*86d7f5d3SJohn Marino "# If the name ALL appears as a regular expression it is always used\n",
66*86d7f5d3SJohn Marino "# in addition to the first matching regex or DEFAULT.\n",
67*86d7f5d3SJohn Marino "#\n",
68*86d7f5d3SJohn Marino "# If any format strings are present in the filter, they will be replaced\n",
69*86d7f5d3SJohn Marino "# as follows:\n",
70*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
71*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
72*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
73*86d7f5d3SJohn Marino #endif
74*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
75*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
76*86d7f5d3SJohn Marino "# %{sVv} = attribute list = file name, old version number (pre-checkin),\n",
77*86d7f5d3SJohn Marino "# new version number (post-checkin). When either old or new revision\n",
78*86d7f5d3SJohn Marino "# is unknown, doesn't exist, or isn't applicable, the string \"NONE\"\n",
79*86d7f5d3SJohn Marino "# will be placed on the command line instead.\n",
80*86d7f5d3SJohn Marino "#\n",
81*86d7f5d3SJohn Marino "# Note that %{sVv} is a list operator and not all elements are necessary.\n",
82*86d7f5d3SJohn Marino "# Thus %{sv} is a legal format string, but will only be replaced with\n",
83*86d7f5d3SJohn Marino "# file name and new revision.\n",
84*86d7f5d3SJohn Marino "# It also generates multiple arguments for each file being operated upon.\n",
85*86d7f5d3SJohn Marino "# That is, if two files, file1 & file2, are being commited from 1.1 to\n",
86*86d7f5d3SJohn Marino "# version 1.1.2.1 and from 1.1.2.2 to 1.1.2.3, respectively, %{sVv} will\n",
87*86d7f5d3SJohn Marino "# generate the following six arguments in this order:\n",
88*86d7f5d3SJohn Marino "# file1, 1.1, 1.1.2.1, file2, 1.1.2.2, 1.1.2.3.\n",
89*86d7f5d3SJohn Marino "#\n",
90*86d7f5d3SJohn Marino "# For example:\n",
91*86d7f5d3SJohn Marino "#DEFAULT (echo \"\"; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
92*86d7f5d3SJohn Marino "# or\n",
93*86d7f5d3SJohn Marino "#DEFAULT (echo \"\"; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
94*86d7f5d3SJohn Marino NULL
95*86d7f5d3SJohn Marino };
96*86d7f5d3SJohn Marino
97*86d7f5d3SJohn Marino static const char *const rcsinfo_contents[] = {
98*86d7f5d3SJohn Marino "# The \"rcsinfo\" file is used to control templates with which the editor\n",
99*86d7f5d3SJohn Marino "# is invoked on commit and import.\n",
100*86d7f5d3SJohn Marino "#\n",
101*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
102*86d7f5d3SJohn Marino "# against the directory that the change is being made to, relative to the\n",
103*86d7f5d3SJohn Marino "# $CVSROOT. For the first match that is found, then the remainder of the\n",
104*86d7f5d3SJohn Marino "# line is the name of the file that contains the template.\n",
105*86d7f5d3SJohn Marino "#\n",
106*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
107*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
108*86d7f5d3SJohn Marino "#\n",
109*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
110*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
111*86d7f5d3SJohn Marino NULL
112*86d7f5d3SJohn Marino };
113*86d7f5d3SJohn Marino
114*86d7f5d3SJohn Marino
115*86d7f5d3SJohn Marino
116*86d7f5d3SJohn Marino static const char *const verifymsg_contents[] = {
117*86d7f5d3SJohn Marino "# The \"verifymsg\" file is used to allow verification of logging\n",
118*86d7f5d3SJohn Marino "# information. It works best when a template (as specified in the\n",
119*86d7f5d3SJohn Marino "# rcsinfo file) is provided for the logging procedure. Given a\n",
120*86d7f5d3SJohn Marino "# template with locations for, a bug-id number, a list of people who\n",
121*86d7f5d3SJohn Marino "# reviewed the code before it can be checked in, and an external\n",
122*86d7f5d3SJohn Marino "# process to catalog the differences that were code reviewed, the\n",
123*86d7f5d3SJohn Marino "# following test can be applied to the code:\n",
124*86d7f5d3SJohn Marino "#\n",
125*86d7f5d3SJohn Marino "# Making sure that the entered bug-id number is correct.\n",
126*86d7f5d3SJohn Marino "# Validating that the code that was reviewed is indeed the code being\n",
127*86d7f5d3SJohn Marino "# checked in (using the bug-id number or a seperate review\n",
128*86d7f5d3SJohn Marino "# number to identify this particular code set.).\n",
129*86d7f5d3SJohn Marino "#\n",
130*86d7f5d3SJohn Marino "# If any of the above test failed, then the commit would be aborted.\n",
131*86d7f5d3SJohn Marino "#\n",
132*86d7f5d3SJohn Marino "# Format strings present in the filter will be replaced as follows:\n",
133*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
134*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
135*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
136*86d7f5d3SJohn Marino #endif
137*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
138*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
139*86d7f5d3SJohn Marino "# %l = name of log file to be verified.\n",
140*86d7f5d3SJohn Marino "#\n",
141*86d7f5d3SJohn Marino "# If no format strings are present in the filter, a default \" %l\" will\n",
142*86d7f5d3SJohn Marino "# be appended to the filter, but this usage is deprecated.\n",
143*86d7f5d3SJohn Marino "#\n",
144*86d7f5d3SJohn Marino "# Actions such as mailing a copy of the report to each reviewer are\n",
145*86d7f5d3SJohn Marino "# better handled by an entry in the loginfo file.\n",
146*86d7f5d3SJohn Marino "#\n",
147*86d7f5d3SJohn Marino "# One thing that should be noted is the the ALL keyword is not\n",
148*86d7f5d3SJohn Marino "# supported. There can be only one entry that matches a given\n",
149*86d7f5d3SJohn Marino "# repository.\n",
150*86d7f5d3SJohn Marino NULL
151*86d7f5d3SJohn Marino };
152*86d7f5d3SJohn Marino
153*86d7f5d3SJohn Marino static const char *const commitinfo_contents[] = {
154*86d7f5d3SJohn Marino "# The \"commitinfo\" file is used to control pre-commit checks.\n",
155*86d7f5d3SJohn Marino "# The filter on the right is invoked with the repository and a list \n",
156*86d7f5d3SJohn Marino "# of files to check. A non-zero exit of the filter program will \n",
157*86d7f5d3SJohn Marino "# cause the commit to be aborted.\n",
158*86d7f5d3SJohn Marino "#\n",
159*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
160*86d7f5d3SJohn Marino "# against the directory that the change is being committed to, relative\n",
161*86d7f5d3SJohn Marino "# to the $CVSROOT. For the first match that is found, then the remainder\n",
162*86d7f5d3SJohn Marino "# of the line is the name of the filter to run.\n",
163*86d7f5d3SJohn Marino "#\n",
164*86d7f5d3SJohn Marino "# Format strings present in the filter will be replaced as follows:\n",
165*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
166*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
167*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
168*86d7f5d3SJohn Marino #endif
169*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
170*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
171*86d7f5d3SJohn Marino "# %{s} = file name, file name, ...\n",
172*86d7f5d3SJohn Marino "#\n",
173*86d7f5d3SJohn Marino "# If no format strings are present in the filter string, a default of\n",
174*86d7f5d3SJohn Marino "# \" %r %s\" will be appended to the filter string, but this usage is\n",
175*86d7f5d3SJohn Marino "# deprecated.\n",
176*86d7f5d3SJohn Marino "#\n",
177*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
178*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
179*86d7f5d3SJohn Marino "#\n",
180*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
181*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
182*86d7f5d3SJohn Marino NULL
183*86d7f5d3SJohn Marino };
184*86d7f5d3SJohn Marino
185*86d7f5d3SJohn Marino static const char *const taginfo_contents[] = {
186*86d7f5d3SJohn Marino "# The \"taginfo\" file is used to control pre-tag checks.\n",
187*86d7f5d3SJohn Marino "# The filter on the right is invoked with the following arguments\n",
188*86d7f5d3SJohn Marino "# if no format strings are present:\n",
189*86d7f5d3SJohn Marino "#\n",
190*86d7f5d3SJohn Marino "# $1 -- tagname\n",
191*86d7f5d3SJohn Marino "# $2 -- operation \"add\" for tag, \"mov\" for tag -F, and \"del\" for tag -d\n",
192*86d7f5d3SJohn Marino "# $3 -- tagtype \"?\" on delete, \"T\" for branch, \"N\" for static\n",
193*86d7f5d3SJohn Marino "# $4 -- repository\n",
194*86d7f5d3SJohn Marino "# $5-> file revision [file revision ...]\n",
195*86d7f5d3SJohn Marino "#\n",
196*86d7f5d3SJohn Marino "# If any format strings are present in the filter, they will be replaced\n",
197*86d7f5d3SJohn Marino "# as follows:\n",
198*86d7f5d3SJohn Marino "# %b = branch mode = \"?\" (delete ops - unknown) | \"T\" (branch)\n",
199*86d7f5d3SJohn Marino "# | \"N\" (not branch)\n",
200*86d7f5d3SJohn Marino "# %o = operation = \"add\" | \"mov\" | \"del\"\n",
201*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
202*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
203*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
204*86d7f5d3SJohn Marino #endif
205*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
206*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
207*86d7f5d3SJohn Marino "# %t = tagname\n",
208*86d7f5d3SJohn Marino "# %{sVv} = attribute list = file name, old version tag will be deleted\n",
209*86d7f5d3SJohn Marino "# from, new version tag will be added to (or deleted from, but\n",
210*86d7f5d3SJohn Marino "# this feature is deprecated. When either old or new revision is\n",
211*86d7f5d3SJohn Marino "# unknown, doesn't exist, or isn't applicable, the string \"NONE\"\n",
212*86d7f5d3SJohn Marino "# will be placed on the command line.\n",
213*86d7f5d3SJohn Marino "#\n",
214*86d7f5d3SJohn Marino "# Note that %{sVv} is a list operator and not all elements are necessary.\n",
215*86d7f5d3SJohn Marino "# Thus %{sV} is a legal format string, but will only be replaced with file\n",
216*86d7f5d3SJohn Marino "# name and old revision. it also generates multiple arguments for each file\n",
217*86d7f5d3SJohn Marino "# being operated upon. i.e. if two files, file1 & file2, are having a tag\n",
218*86d7f5d3SJohn Marino "# moved from version 1.1 to version 1.1.2.9, %{sVv} will generate the\n",
219*86d7f5d3SJohn Marino "# following six arguments in this order:\n",
220*86d7f5d3SJohn Marino "# file1, 1.1, 1.1.2.9, file2, 1.1, 1.1.2.9.\n",
221*86d7f5d3SJohn Marino "#\n",
222*86d7f5d3SJohn Marino "# A non-zero exit of the filter program will cause the tag to be aborted.\n",
223*86d7f5d3SJohn Marino "#\n",
224*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
225*86d7f5d3SJohn Marino "# against the directory that the change is being committed to, relative\n",
226*86d7f5d3SJohn Marino "# to the $CVSROOT. For the first match that is found, then the remainder\n",
227*86d7f5d3SJohn Marino "# of the line is the name of the filter to run.\n",
228*86d7f5d3SJohn Marino "#\n",
229*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
230*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
231*86d7f5d3SJohn Marino "#\n",
232*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
233*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
234*86d7f5d3SJohn Marino NULL
235*86d7f5d3SJohn Marino };
236*86d7f5d3SJohn Marino
237*86d7f5d3SJohn Marino static const char *const preproxy_contents[] = {
238*86d7f5d3SJohn Marino "# The \"preproxy\" file is called form the secondary server as soon as\n",
239*86d7f5d3SJohn Marino "# the secondary server determines that it will be proxying a write\n",
240*86d7f5d3SJohn Marino "# command to a primary server and immediately before it opens a\n",
241*86d7f5d3SJohn Marino "# connection to the primary server. This script might, for example, be\n",
242*86d7f5d3SJohn Marino "# used to launch a dial up or VPN connection to the primary server's\n",
243*86d7f5d3SJohn Marino "# network.\n",
244*86d7f5d3SJohn Marino "#\n",
245*86d7f5d3SJohn Marino "# If any format strings are present in the filter, they will be replaced\n",
246*86d7f5d3SJohn Marino "# as follows:\n",
247*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
248*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
249*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
250*86d7f5d3SJohn Marino #endif
251*86d7f5d3SJohn Marino "# %p = path relative to repository (currently always \".\")\n",
252*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
253*86d7f5d3SJohn Marino "#\n",
254*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
255*86d7f5d3SJohn Marino "# against the directory that the change is being committed to, relative\n",
256*86d7f5d3SJohn Marino "# to the $CVSROOT. For the first match that is found, then the remainder\n",
257*86d7f5d3SJohn Marino "# of the line is the name of the filter to run.\n",
258*86d7f5d3SJohn Marino "#\n",
259*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
260*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
261*86d7f5d3SJohn Marino "#\n",
262*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
263*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
264*86d7f5d3SJohn Marino NULL
265*86d7f5d3SJohn Marino };
266*86d7f5d3SJohn Marino
267*86d7f5d3SJohn Marino static const char *const postadmin_contents[] = {
268*86d7f5d3SJohn Marino "# The \"postadmin\" file is called after the \"admin\" command finishes\n",
269*86d7f5d3SJohn Marino "# processing a directory.\n",
270*86d7f5d3SJohn Marino "#\n",
271*86d7f5d3SJohn Marino "# If any format strings are present in the filter, they will be replaced\n",
272*86d7f5d3SJohn Marino "# as follows:\n",
273*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
274*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
275*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
276*86d7f5d3SJohn Marino #endif
277*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
278*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
279*86d7f5d3SJohn Marino "#\n",
280*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
281*86d7f5d3SJohn Marino "# against the directory that the change is being committed to, relative\n",
282*86d7f5d3SJohn Marino "# to the $CVSROOT. For the first match that is found, then the remainder\n",
283*86d7f5d3SJohn Marino "# of the line is the name of the filter to run.\n",
284*86d7f5d3SJohn Marino "#\n",
285*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
286*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
287*86d7f5d3SJohn Marino "#\n",
288*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
289*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
290*86d7f5d3SJohn Marino NULL
291*86d7f5d3SJohn Marino };
292*86d7f5d3SJohn Marino
293*86d7f5d3SJohn Marino static const char *const postproxy_contents[] = {
294*86d7f5d3SJohn Marino "# The \"postproxy\" file is called from a secondary server as soon as\n",
295*86d7f5d3SJohn Marino "# the secondary server closes its connection to the primary server.\n",
296*86d7f5d3SJohn Marino "# This script might, for example, be used to shut down a dial up\n",
297*86d7f5d3SJohn Marino "# or VPN connection to the primary server's network.\n",
298*86d7f5d3SJohn Marino "#\n",
299*86d7f5d3SJohn Marino "# If any format strings are present in the filter, they will be replaced\n",
300*86d7f5d3SJohn Marino "# as follows:\n",
301*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
302*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
303*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
304*86d7f5d3SJohn Marino #endif
305*86d7f5d3SJohn Marino "# %p = path relative to repository (currently always \".\")\n",
306*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
307*86d7f5d3SJohn Marino "#\n",
308*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
309*86d7f5d3SJohn Marino "# against the directory that the change is being committed to, relative\n",
310*86d7f5d3SJohn Marino "# to the $CVSROOT. For the first match that is found, then the remainder\n",
311*86d7f5d3SJohn Marino "# of the line is the name of the filter to run.\n",
312*86d7f5d3SJohn Marino "#\n",
313*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
314*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
315*86d7f5d3SJohn Marino "#\n",
316*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
317*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
318*86d7f5d3SJohn Marino NULL
319*86d7f5d3SJohn Marino };
320*86d7f5d3SJohn Marino
321*86d7f5d3SJohn Marino static const char *const posttag_contents[] = {
322*86d7f5d3SJohn Marino "# The \"posttag\" file is called after the \"tag\" command finishes\n",
323*86d7f5d3SJohn Marino "# processing a directory.\n",
324*86d7f5d3SJohn Marino "#\n",
325*86d7f5d3SJohn Marino "# If any format strings are present in the filter, they will be replaced\n",
326*86d7f5d3SJohn Marino "# as follows:\n",
327*86d7f5d3SJohn Marino "# %b = branch mode = \"?\" (delete ops - unknown) | \"T\" (branch)\n",
328*86d7f5d3SJohn Marino "# | \"N\" (not branch)\n",
329*86d7f5d3SJohn Marino "# %o = operation = \"add\" | \"mov\" | \"del\"\n",
330*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
331*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
332*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
333*86d7f5d3SJohn Marino #endif
334*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
335*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
336*86d7f5d3SJohn Marino "# %t = tagname\n",
337*86d7f5d3SJohn Marino "# %{sVv} = attribute list = file name, old version tag will be deleted\n",
338*86d7f5d3SJohn Marino "# from, new version tag will be added to (or deleted from, but\n",
339*86d7f5d3SJohn Marino "# this feature is deprecated. When either old or new revision is\n",
340*86d7f5d3SJohn Marino "# unknown, doesn't exist, or isn't applicable, the string \"NONE\"\n",
341*86d7f5d3SJohn Marino "# will be placed on the command line.\n",
342*86d7f5d3SJohn Marino "#\n",
343*86d7f5d3SJohn Marino "# Note that %{sVv} is a list operator and not all elements are necessary.\n",
344*86d7f5d3SJohn Marino "# Thus %{sV} is a legal format string, but will only be replaced with file\n",
345*86d7f5d3SJohn Marino "# name and old revision. it also generates multiple arguments for each file\n",
346*86d7f5d3SJohn Marino "# being operated upon. i.e. if two files, file1 & file2, are having a tag\n",
347*86d7f5d3SJohn Marino "# moved from version 1.1 to version 1.1.2.9, %{sVv} will generate the\n",
348*86d7f5d3SJohn Marino "# following six arguments in this order:\n",
349*86d7f5d3SJohn Marino "# file1, 1.1, 1.1.2.9, file2, 1.1, 1.1.2.9.\n",
350*86d7f5d3SJohn Marino "#\n",
351*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
352*86d7f5d3SJohn Marino "# against the directory that the change is being committed to, relative\n",
353*86d7f5d3SJohn Marino "# to the $CVSROOT. For the first match that is found, then the remainder\n",
354*86d7f5d3SJohn Marino "# of the line is the name of the filter to run.\n",
355*86d7f5d3SJohn Marino "#\n",
356*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
357*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
358*86d7f5d3SJohn Marino "#\n",
359*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
360*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
361*86d7f5d3SJohn Marino NULL
362*86d7f5d3SJohn Marino };
363*86d7f5d3SJohn Marino
364*86d7f5d3SJohn Marino static const char *const postwatch_contents[] = {
365*86d7f5d3SJohn Marino "# The \"postwatch\" file is called after any command finishes writing new\n",
366*86d7f5d3SJohn Marino "# file attibute (watch/edit) information in a directory.\n",
367*86d7f5d3SJohn Marino "#\n",
368*86d7f5d3SJohn Marino "# If any format strings are present in the filter, they will be replaced\n",
369*86d7f5d3SJohn Marino "# as follows:\n",
370*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
371*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
372*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
373*86d7f5d3SJohn Marino #endif
374*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
375*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
376*86d7f5d3SJohn Marino "#\n",
377*86d7f5d3SJohn Marino "# The first entry on a line is a regular expression which is tested\n",
378*86d7f5d3SJohn Marino "# against the directory that the change is being committed to, relative\n",
379*86d7f5d3SJohn Marino "# to the $CVSROOT. For the first match that is found, then the remainder\n",
380*86d7f5d3SJohn Marino "# of the line is the name of the filter to run.\n",
381*86d7f5d3SJohn Marino "#\n",
382*86d7f5d3SJohn Marino "# If the repository name does not match any of the regular expressions in this\n",
383*86d7f5d3SJohn Marino "# file, the \"DEFAULT\" line is used, if it is specified.\n",
384*86d7f5d3SJohn Marino "#\n",
385*86d7f5d3SJohn Marino "# If the name \"ALL\" appears as a regular expression it is always used\n",
386*86d7f5d3SJohn Marino "# in addition to the first matching regex or \"DEFAULT\".\n",
387*86d7f5d3SJohn Marino NULL
388*86d7f5d3SJohn Marino };
389*86d7f5d3SJohn Marino
390*86d7f5d3SJohn Marino static const char *const checkoutlist_contents[] = {
391*86d7f5d3SJohn Marino "# The \"checkoutlist\" file is used to support additional version controlled\n",
392*86d7f5d3SJohn Marino "# administrative files in $CVSROOT/CVSROOT, such as template files.\n",
393*86d7f5d3SJohn Marino "#\n",
394*86d7f5d3SJohn Marino "# The first entry on a line is a filename which will be checked out from\n",
395*86d7f5d3SJohn Marino "# the corresponding RCS file in the $CVSROOT/CVSROOT directory.\n",
396*86d7f5d3SJohn Marino "# The remainder of the line is an error message to use if the file cannot\n",
397*86d7f5d3SJohn Marino "# be checked out.\n",
398*86d7f5d3SJohn Marino "#\n",
399*86d7f5d3SJohn Marino "# File format:\n",
400*86d7f5d3SJohn Marino "#\n",
401*86d7f5d3SJohn Marino "# [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>\n",
402*86d7f5d3SJohn Marino "#\n",
403*86d7f5d3SJohn Marino "# comment lines begin with '#'\n",
404*86d7f5d3SJohn Marino NULL
405*86d7f5d3SJohn Marino };
406*86d7f5d3SJohn Marino
407*86d7f5d3SJohn Marino static const char *const cvswrappers_contents[] = {
408*86d7f5d3SJohn Marino "# This file affects handling of files based on their names.\n",
409*86d7f5d3SJohn Marino "#\n",
410*86d7f5d3SJohn Marino #if 0 /* see comments in wrap_add in wrapper.c */
411*86d7f5d3SJohn Marino "# The -t/-f options allow one to treat directories of files\n",
412*86d7f5d3SJohn Marino "# as a single file, or to transform a file in other ways on\n",
413*86d7f5d3SJohn Marino "# its way in and out of CVS.\n",
414*86d7f5d3SJohn Marino "#\n",
415*86d7f5d3SJohn Marino #endif
416*86d7f5d3SJohn Marino "# The -m option specifies whether CVS attempts to merge files.\n",
417*86d7f5d3SJohn Marino "#\n",
418*86d7f5d3SJohn Marino "# The -k option specifies keyword expansion (e.g. -kb for binary).\n",
419*86d7f5d3SJohn Marino "#\n",
420*86d7f5d3SJohn Marino "# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)\n",
421*86d7f5d3SJohn Marino "#\n",
422*86d7f5d3SJohn Marino "# wildcard [option value][option value]...\n",
423*86d7f5d3SJohn Marino "#\n",
424*86d7f5d3SJohn Marino "# where option is one of\n",
425*86d7f5d3SJohn Marino "# -f from cvs filter value: path to filter\n",
426*86d7f5d3SJohn Marino "# -t to cvs filter value: path to filter\n",
427*86d7f5d3SJohn Marino "# -m update methodology value: MERGE or COPY\n",
428*86d7f5d3SJohn Marino "# -k expansion mode value: b, o, kkv, &c\n",
429*86d7f5d3SJohn Marino "#\n",
430*86d7f5d3SJohn Marino "# and value is a single-quote delimited value.\n",
431*86d7f5d3SJohn Marino "# For example:\n",
432*86d7f5d3SJohn Marino "#*.gif -k 'b'\n",
433*86d7f5d3SJohn Marino NULL
434*86d7f5d3SJohn Marino };
435*86d7f5d3SJohn Marino
436*86d7f5d3SJohn Marino static const char *const notify_contents[] = {
437*86d7f5d3SJohn Marino "# The \"notify\" file controls where notifications from watches set by\n",
438*86d7f5d3SJohn Marino "# \"cvs watch add\" or \"cvs edit\" are sent. The first entry on a line is\n",
439*86d7f5d3SJohn Marino "# a regular expression which is tested against the directory that the\n",
440*86d7f5d3SJohn Marino "# change is being made to, relative to the $CVSROOT. If it matches,\n",
441*86d7f5d3SJohn Marino "# then the remainder of the line is a filter program that should contain\n",
442*86d7f5d3SJohn Marino "# one occurrence of %s for the user to notify, and information on its\n",
443*86d7f5d3SJohn Marino "# standard input.\n",
444*86d7f5d3SJohn Marino "#\n",
445*86d7f5d3SJohn Marino "# \"ALL\" or \"DEFAULT\" can be used in place of the regular expression.\n",
446*86d7f5d3SJohn Marino "#\n",
447*86d7f5d3SJohn Marino "# format strings are replaceed as follows:\n",
448*86d7f5d3SJohn Marino "# %c = canonical name of the command being executed\n",
449*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
450*86d7f5d3SJohn Marino "# %R = the name of the referrer, if any, otherwise the value NONE\n",
451*86d7f5d3SJohn Marino #endif
452*86d7f5d3SJohn Marino "# %p = path relative to repository\n",
453*86d7f5d3SJohn Marino "# %r = repository (path portion of $CVSROOT)\n",
454*86d7f5d3SJohn Marino "# %s = user to notify\n",
455*86d7f5d3SJohn Marino "#\n",
456*86d7f5d3SJohn Marino "# For example:\n",
457*86d7f5d3SJohn Marino "#ALL (echo Committed to %r/%p; cat) |mail %s -s \"CVS notification\"\n",
458*86d7f5d3SJohn Marino NULL
459*86d7f5d3SJohn Marino };
460*86d7f5d3SJohn Marino
461*86d7f5d3SJohn Marino static const char *const modules_contents[] = {
462*86d7f5d3SJohn Marino "# Three different line formats are valid:\n",
463*86d7f5d3SJohn Marino "# key -a aliases...\n",
464*86d7f5d3SJohn Marino "# key [options] directory\n",
465*86d7f5d3SJohn Marino "# key [options] directory files...\n",
466*86d7f5d3SJohn Marino "#\n",
467*86d7f5d3SJohn Marino "# Where \"options\" are composed of:\n",
468*86d7f5d3SJohn Marino "# -i prog Run \"prog\" on \"cvs commit\" from top-level of module.\n",
469*86d7f5d3SJohn Marino "# -o prog Run \"prog\" on \"cvs checkout\" of module.\n",
470*86d7f5d3SJohn Marino "# -e prog Run \"prog\" on \"cvs export\" of module.\n",
471*86d7f5d3SJohn Marino "# -t prog Run \"prog\" on \"cvs rtag\" of module.\n",
472*86d7f5d3SJohn Marino "# -u prog Run \"prog\" on \"cvs update\" of module.\n",
473*86d7f5d3SJohn Marino "# -d dir Place module in directory \"dir\" instead of module name.\n",
474*86d7f5d3SJohn Marino "# -l Top-level directory only -- do not recurse.\n",
475*86d7f5d3SJohn Marino "#\n",
476*86d7f5d3SJohn Marino "# NOTE: If you change any of the \"Run\" options above, you'll have to\n",
477*86d7f5d3SJohn Marino "# release and re-checkout any working directories of these modules.\n",
478*86d7f5d3SJohn Marino "#\n",
479*86d7f5d3SJohn Marino "# And \"directory\" is a path to a directory relative to $CVSROOT.\n",
480*86d7f5d3SJohn Marino "#\n",
481*86d7f5d3SJohn Marino "# The \"-a\" option specifies an alias. An alias is interpreted as if\n",
482*86d7f5d3SJohn Marino "# everything on the right of the \"-a\" had been typed on the command line.\n",
483*86d7f5d3SJohn Marino "#\n",
484*86d7f5d3SJohn Marino "# You can encode a module within a module by using the special '&'\n",
485*86d7f5d3SJohn Marino "# character to interpose another module into the current module. This\n",
486*86d7f5d3SJohn Marino "# can be useful for creating a module that consists of many directories\n",
487*86d7f5d3SJohn Marino "# spread out over the entire source repository.\n",
488*86d7f5d3SJohn Marino NULL
489*86d7f5d3SJohn Marino };
490*86d7f5d3SJohn Marino
491*86d7f5d3SJohn Marino static const char *const config_contents[] = {
492*86d7f5d3SJohn Marino "# Set `SystemAuth' to `no' if pserver shouldn't check system users/passwords.\n",
493*86d7f5d3SJohn Marino "#SystemAuth=no\n",
494*86d7f5d3SJohn Marino "\n",
495*86d7f5d3SJohn Marino "# Set `LocalKeyword' to specify a local alias for a standard keyword.\n",
496*86d7f5d3SJohn Marino "#LocalKeyword=MYCVS=CVSHeader\n",
497*86d7f5d3SJohn Marino "\n",
498*86d7f5d3SJohn Marino "# Set `KeywordExpand' to `i' followed by a list of keywords to expand or\n",
499*86d7f5d3SJohn Marino "# `e' followed by a list of keywords to not expand.\n"
500*86d7f5d3SJohn Marino "#KeywordExpand=iMYCVS,Name,Date\n",
501*86d7f5d3SJohn Marino "#KeywordExpand=eCVSHeader\n",
502*86d7f5d3SJohn Marino "\n",
503*86d7f5d3SJohn Marino #ifdef PRESERVE_PERMISSIONS_SUPPORT
504*86d7f5d3SJohn Marino "# Set `PreservePermissions' to `yes' to save file status information\n",
505*86d7f5d3SJohn Marino "# in the repository.\n",
506*86d7f5d3SJohn Marino "#PreservePermissions=no\n",
507*86d7f5d3SJohn Marino "\n",
508*86d7f5d3SJohn Marino #endif
509*86d7f5d3SJohn Marino "# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top\n",
510*86d7f5d3SJohn Marino "# level of the new working directory when using the `cvs checkout'\n",
511*86d7f5d3SJohn Marino "# command.\n",
512*86d7f5d3SJohn Marino "#TopLevelAdmin=no\n",
513*86d7f5d3SJohn Marino "\n",
514*86d7f5d3SJohn Marino "# Put CVS lock files in this directory rather than directly in the repository.\n",
515*86d7f5d3SJohn Marino "#LockDir=/var/lock/cvs\n",
516*86d7f5d3SJohn Marino "\n",
517*86d7f5d3SJohn Marino "# Set `LogHistory' to `all' or `" ALL_HISTORY_REC_TYPES "' to log all transactions to the\n",
518*86d7f5d3SJohn Marino "# history file, or a subset as needed (ie `TMAR' logs all write operations)\n",
519*86d7f5d3SJohn Marino "#LogHistory=" ALL_HISTORY_REC_TYPES "\n",
520*86d7f5d3SJohn Marino "\n",
521*86d7f5d3SJohn Marino "# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg\n",
522*86d7f5d3SJohn Marino "# script to change the log message. Set it to `stat' to force CVS to verify\n",
523*86d7f5d3SJohn Marino "# that the file has changed before reading it (this can take up to an extra\n",
524*86d7f5d3SJohn Marino "# second per directory being committed, so it is not recommended for large\n",
525*86d7f5d3SJohn Marino "# repositories. Set it to `never' (the previous CVS behavior) to prevent\n",
526*86d7f5d3SJohn Marino "# verifymsg scripts from changing the log message.\n",
527*86d7f5d3SJohn Marino "#RereadLogAfterVerify=always\n",
528*86d7f5d3SJohn Marino "\n",
529*86d7f5d3SJohn Marino "# Set `UserAdminOptions' to the list of `cvs admin' commands (options)\n",
530*86d7f5d3SJohn Marino "# that users not in the `cvsadmin' group are allowed to run. This\n",
531*86d7f5d3SJohn Marino "# defaults to `k', or only allowing the changing of the default\n",
532*86d7f5d3SJohn Marino "# keyword expansion mode for files for users not in the `cvsadmin' group.\n",
533*86d7f5d3SJohn Marino "# This value is ignored if the `cvsadmin' group does not exist.\n",
534*86d7f5d3SJohn Marino "#\n",
535*86d7f5d3SJohn Marino "# The following string would enable all `cvs admin' commands for all\n",
536*86d7f5d3SJohn Marino "# users:\n",
537*86d7f5d3SJohn Marino "#UserAdminOptions=aAbceIklLmnNostuU\n",
538*86d7f5d3SJohn Marino #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
539*86d7f5d3SJohn Marino "\n",
540*86d7f5d3SJohn Marino "# Set `UseNewInfoFmtStrings' to `no' if you must support a legacy system by\n",
541*86d7f5d3SJohn Marino "# enabling the deprecated old style info file command line format strings.\n",
542*86d7f5d3SJohn Marino "# Be warned that these strings could be disabled in any new version of CVS.\n",
543*86d7f5d3SJohn Marino "UseNewInfoFmtStrings=yes\n",
544*86d7f5d3SJohn Marino #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
545*86d7f5d3SJohn Marino "\n",
546*86d7f5d3SJohn Marino "# Set `ImportNewFilesToVendorBranchOnly' to `yes' if you wish to force\n",
547*86d7f5d3SJohn Marino "# every `cvs import' command to behave as if the `-X' flag was\n",
548*86d7f5d3SJohn Marino "# specified.\n",
549*86d7f5d3SJohn Marino "#ImportNewFilesToVendorBranchOnly=no\n",
550*86d7f5d3SJohn Marino #ifdef PROXY_SUPPORT
551*86d7f5d3SJohn Marino "\n",
552*86d7f5d3SJohn Marino "# Set `PrimaryServer' to the CVSROOT to the primary, or write, server when\n",
553*86d7f5d3SJohn Marino "# establishing one or more read-only mirrors which serve as proxies for\n",
554*86d7f5d3SJohn Marino "# the write server in write mode or redirect the client to the primary for\n",
555*86d7f5d3SJohn Marino "# write requests.\n",
556*86d7f5d3SJohn Marino "#\n",
557*86d7f5d3SJohn Marino "# For example:\n",
558*86d7f5d3SJohn Marino "#\n",
559*86d7f5d3SJohn Marino "# PrimaryServer=:fork:localhost/cvsroot\n",
560*86d7f5d3SJohn Marino "\n",
561*86d7f5d3SJohn Marino "# Set `MaxProxyBufferSize' to the the maximum allowable secondary\n",
562*86d7f5d3SJohn Marino "# buffer memory cache size before the buffer begins being stored to disk, in\n",
563*86d7f5d3SJohn Marino "# bytes. Must be a positive integer but may end in `k', `M', `G', or `T' (for\n",
564*86d7f5d3SJohn Marino "# kiilo, mega, giga, & tera, respectively). If an otherwise valid number you\n",
565*86d7f5d3SJohn Marino "# specify is greater than the SIZE_MAX defined by your system's C compiler,\n",
566*86d7f5d3SJohn Marino "# then it will be resolved to SIZE_MAX without a warning. Defaults to 8M (8\n",
567*86d7f5d3SJohn Marino "# megabytes).\n",
568*86d7f5d3SJohn Marino "#\n",
569*86d7f5d3SJohn Marino "# High values for MaxProxyBufferSize may speed up a secondary server\n",
570*86d7f5d3SJohn Marino "# with old hardware and a lot of available memory but can actually slow a\n",
571*86d7f5d3SJohn Marino "# modern system down slightly.\n",
572*86d7f5d3SJohn Marino "#\n",
573*86d7f5d3SJohn Marino "# For example:\n",
574*86d7f5d3SJohn Marino "#\n",
575*86d7f5d3SJohn Marino "# MaxProxyBufferSize=1G\n",
576*86d7f5d3SJohn Marino #endif /* PROXY_SUPPORT */
577*86d7f5d3SJohn Marino "\n",
578*86d7f5d3SJohn Marino "# Set `MaxCommentLeaderLength' to the maximum length permitted for the\n",
579*86d7f5d3SJohn Marino "# automagically determined comment leader used when expanding the Log\n",
580*86d7f5d3SJohn Marino "# keyword, in bytes. CVS's behavior when the automagically determined\n",
581*86d7f5d3SJohn Marino "# comment leader exceeds this length is dependant on the value of\n",
582*86d7f5d3SJohn Marino "# `UseArchiveCommentLeader' set in this file. `unlimited' is a valid\n",
583*86d7f5d3SJohn Marino "# setting for this value. Defaults to 20 bytes.\n",
584*86d7f5d3SJohn Marino "#\n",
585*86d7f5d3SJohn Marino "# For example:\n",
586*86d7f5d3SJohn Marino "#\n",
587*86d7f5d3SJohn Marino "# MaxCommentLeaderLength=20\n",
588*86d7f5d3SJohn Marino "\n",
589*86d7f5d3SJohn Marino "# Set `UseArchiveCommentLeader' to `yes' to cause CVS to fall back on\n",
590*86d7f5d3SJohn Marino "# the comment leader set in the RCS archive file, if any, when the\n",
591*86d7f5d3SJohn Marino "# automagically determined comment leader exceeds `MaxCommentLeaderLength'\n",
592*86d7f5d3SJohn Marino "# bytes. If `UseArchiveCommentLeader' is not set and a comment leader\n",
593*86d7f5d3SJohn Marino "# greater than `MaxCommentLeaderLength' is calculated, the Log keyword\n",
594*86d7f5d3SJohn Marino "# being examined will not be expanded. Defaults to `no'.\n",
595*86d7f5d3SJohn Marino "#\n",
596*86d7f5d3SJohn Marino "# For example:\n",
597*86d7f5d3SJohn Marino "#\n",
598*86d7f5d3SJohn Marino "# UseArchiveCommentLeader=no\n",
599*86d7f5d3SJohn Marino NULL
600*86d7f5d3SJohn Marino };
601*86d7f5d3SJohn Marino
602*86d7f5d3SJohn Marino static const struct admin_file filelist[] = {
603*86d7f5d3SJohn Marino {CVSROOTADM_CHECKOUTLIST,
604*86d7f5d3SJohn Marino "a %s file can specify extra CVSROOT files to auto-checkout",
605*86d7f5d3SJohn Marino checkoutlist_contents},
606*86d7f5d3SJohn Marino {CVSROOTADM_COMMITINFO,
607*86d7f5d3SJohn Marino "a %s file can be used to configure 'cvs commit' checking",
608*86d7f5d3SJohn Marino commitinfo_contents},
609*86d7f5d3SJohn Marino {CVSROOTADM_IGNORE,
610*86d7f5d3SJohn Marino "a %s file can be used to specify files to ignore",
611*86d7f5d3SJohn Marino NULL},
612*86d7f5d3SJohn Marino {CVSROOTADM_LOGINFO,
613*86d7f5d3SJohn Marino "no logging of 'cvs commit' messages is done without a %s file",
614*86d7f5d3SJohn Marino &loginfo_contents[0]},
615*86d7f5d3SJohn Marino {CVSROOTADM_MODULES,
616*86d7f5d3SJohn Marino /* modules is special-cased in mkmodules. */
617*86d7f5d3SJohn Marino NULL,
618*86d7f5d3SJohn Marino modules_contents},
619*86d7f5d3SJohn Marino {CVSROOTADM_NOTIFY,
620*86d7f5d3SJohn Marino "a %s file can be used to specify where notifications go",
621*86d7f5d3SJohn Marino notify_contents},
622*86d7f5d3SJohn Marino {CVSROOTADM_POSTADMIN,
623*86d7f5d3SJohn Marino "a %s file can be used to configure 'cvs admin' logging",
624*86d7f5d3SJohn Marino postadmin_contents},
625*86d7f5d3SJohn Marino {CVSROOTADM_POSTPROXY,
626*86d7f5d3SJohn Marino "a %s file can be used to close or log connections to a primary server",
627*86d7f5d3SJohn Marino postproxy_contents},
628*86d7f5d3SJohn Marino {CVSROOTADM_POSTTAG,
629*86d7f5d3SJohn Marino "a %s file can be used to configure 'cvs tag' logging",
630*86d7f5d3SJohn Marino posttag_contents},
631*86d7f5d3SJohn Marino {CVSROOTADM_POSTWATCH,
632*86d7f5d3SJohn Marino "a %s file can be used to configure 'cvs watch' logging",
633*86d7f5d3SJohn Marino postwatch_contents},
634*86d7f5d3SJohn Marino {CVSROOTADM_PREPROXY,
635*86d7f5d3SJohn Marino "a %s file can be used to open or log connections to a primary server",
636*86d7f5d3SJohn Marino preproxy_contents},
637*86d7f5d3SJohn Marino {CVSROOTADM_RCSINFO,
638*86d7f5d3SJohn Marino "a %s file can be used to configure 'cvs commit' templates",
639*86d7f5d3SJohn Marino rcsinfo_contents},
640*86d7f5d3SJohn Marino {CVSROOTADM_READERS,
641*86d7f5d3SJohn Marino "a %s file specifies read-only users",
642*86d7f5d3SJohn Marino NULL},
643*86d7f5d3SJohn Marino {CVSROOTADM_TAGINFO,
644*86d7f5d3SJohn Marino "a %s file can be used to configure 'cvs tag' checking",
645*86d7f5d3SJohn Marino taginfo_contents},
646*86d7f5d3SJohn Marino {CVSROOTADM_VERIFYMSG,
647*86d7f5d3SJohn Marino "a %s file can be used to validate log messages",
648*86d7f5d3SJohn Marino verifymsg_contents},
649*86d7f5d3SJohn Marino {CVSROOTADM_WRAPPER,
650*86d7f5d3SJohn Marino "a %s file can be used to specify files to treat as wrappers",
651*86d7f5d3SJohn Marino cvswrappers_contents},
652*86d7f5d3SJohn Marino {CVSROOTADM_WRITERS,
653*86d7f5d3SJohn Marino "a %s file specifies read/write users",
654*86d7f5d3SJohn Marino NULL},
655*86d7f5d3SJohn Marino
656*86d7f5d3SJohn Marino /* Some have suggested listing CVSROOTADM_PASSWD here too. This
657*86d7f5d3SJohn Marino would mean that CVS commands which operate on the
658*86d7f5d3SJohn Marino CVSROOTADM_PASSWD file would transmit hashed passwords over the
659*86d7f5d3SJohn Marino net. This might seem to be no big deal, as pserver normally
660*86d7f5d3SJohn Marino transmits cleartext passwords, but the difference is that
661*86d7f5d3SJohn Marino CVSROOTADM_PASSWD contains *all* passwords, not just the ones
662*86d7f5d3SJohn Marino currently being used. For example, it could be too easy to
663*86d7f5d3SJohn Marino accidentally give someone readonly access to CVSROOTADM_PASSWD
664*86d7f5d3SJohn Marino (e.g. via anonymous CVS or cvsweb), and then if there are any
665*86d7f5d3SJohn Marino guessable passwords for read/write access (usually there will be)
666*86d7f5d3SJohn Marino they get read/write access.
667*86d7f5d3SJohn Marino
668*86d7f5d3SJohn Marino Another worry is the implications of storing old passwords--if
669*86d7f5d3SJohn Marino someone used a password in the past they might be using it
670*86d7f5d3SJohn Marino elsewhere, using a similar password, etc, and so saving old
671*86d7f5d3SJohn Marino passwords, even hashed, is probably not a good idea. */
672*86d7f5d3SJohn Marino
673*86d7f5d3SJohn Marino {CVSROOTADM_CONFIG,
674*86d7f5d3SJohn Marino "a %s file configures various behaviors",
675*86d7f5d3SJohn Marino config_contents},
676*86d7f5d3SJohn Marino {NULL, NULL, NULL}
677*86d7f5d3SJohn Marino };
678*86d7f5d3SJohn Marino
679*86d7f5d3SJohn Marino /* Rebuild the checked out administrative files in directory DIR. */
680*86d7f5d3SJohn Marino int
mkmodules(char * dir)681*86d7f5d3SJohn Marino mkmodules (char *dir)
682*86d7f5d3SJohn Marino {
683*86d7f5d3SJohn Marino struct saved_cwd cwd;
684*86d7f5d3SJohn Marino char *temp;
685*86d7f5d3SJohn Marino char *cp, *last, *fname;
686*86d7f5d3SJohn Marino #ifdef MY_NDBM
687*86d7f5d3SJohn Marino DBM *db;
688*86d7f5d3SJohn Marino #endif
689*86d7f5d3SJohn Marino FILE *fp;
690*86d7f5d3SJohn Marino char *line = NULL;
691*86d7f5d3SJohn Marino size_t line_allocated = 0;
692*86d7f5d3SJohn Marino const struct admin_file *fileptr;
693*86d7f5d3SJohn Marino
694*86d7f5d3SJohn Marino if (noexec)
695*86d7f5d3SJohn Marino return 0;
696*86d7f5d3SJohn Marino
697*86d7f5d3SJohn Marino if (save_cwd (&cwd))
698*86d7f5d3SJohn Marino error (1, errno, "Failed to save current directory.");
699*86d7f5d3SJohn Marino
700*86d7f5d3SJohn Marino if (CVS_CHDIR (dir) < 0)
701*86d7f5d3SJohn Marino error (1, errno, "cannot chdir to %s", dir);
702*86d7f5d3SJohn Marino
703*86d7f5d3SJohn Marino /*
704*86d7f5d3SJohn Marino * First, do the work necessary to update the "modules" database.
705*86d7f5d3SJohn Marino */
706*86d7f5d3SJohn Marino temp = make_tempfile ();
707*86d7f5d3SJohn Marino switch (checkout_file (CVSROOTADM_MODULES, temp))
708*86d7f5d3SJohn Marino {
709*86d7f5d3SJohn Marino
710*86d7f5d3SJohn Marino case 0: /* everything ok */
711*86d7f5d3SJohn Marino #ifdef MY_NDBM
712*86d7f5d3SJohn Marino /* open it, to generate any duplicate errors */
713*86d7f5d3SJohn Marino if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL)
714*86d7f5d3SJohn Marino dbm_close (db);
715*86d7f5d3SJohn Marino #else
716*86d7f5d3SJohn Marino write_dbmfile (temp);
717*86d7f5d3SJohn Marino rename_dbmfile (temp);
718*86d7f5d3SJohn Marino #endif
719*86d7f5d3SJohn Marino rename_rcsfile (temp, CVSROOTADM_MODULES);
720*86d7f5d3SJohn Marino break;
721*86d7f5d3SJohn Marino
722*86d7f5d3SJohn Marino default:
723*86d7f5d3SJohn Marino error (0, 0,
724*86d7f5d3SJohn Marino "'cvs checkout' is less functional without a %s file",
725*86d7f5d3SJohn Marino CVSROOTADM_MODULES);
726*86d7f5d3SJohn Marino break;
727*86d7f5d3SJohn Marino } /* switch on checkout_file() */
728*86d7f5d3SJohn Marino
729*86d7f5d3SJohn Marino if (unlink_file (temp) < 0
730*86d7f5d3SJohn Marino && !existence_error (errno))
731*86d7f5d3SJohn Marino error (0, errno, "cannot remove %s", temp);
732*86d7f5d3SJohn Marino free (temp);
733*86d7f5d3SJohn Marino
734*86d7f5d3SJohn Marino /* Checkout the files that need it in CVSROOT dir */
735*86d7f5d3SJohn Marino for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) {
736*86d7f5d3SJohn Marino if (fileptr->errormsg == NULL)
737*86d7f5d3SJohn Marino continue;
738*86d7f5d3SJohn Marino temp = make_tempfile ();
739*86d7f5d3SJohn Marino if (checkout_file (fileptr->filename, temp) == 0)
740*86d7f5d3SJohn Marino rename_rcsfile (temp, fileptr->filename);
741*86d7f5d3SJohn Marino /* else
742*86d7f5d3SJohn Marino * If there was some problem other than the file not existing,
743*86d7f5d3SJohn Marino * checkout_file already printed a real error message. If the
744*86d7f5d3SJohn Marino * file does not exist, it is harmless--it probably just means
745*86d7f5d3SJohn Marino * that the repository was created with an old version of CVS
746*86d7f5d3SJohn Marino * which didn't have so many files in CVSROOT.
747*86d7f5d3SJohn Marino */
748*86d7f5d3SJohn Marino
749*86d7f5d3SJohn Marino if (unlink_file (temp) < 0
750*86d7f5d3SJohn Marino && !existence_error (errno))
751*86d7f5d3SJohn Marino error (0, errno, "cannot remove %s", temp);
752*86d7f5d3SJohn Marino free (temp);
753*86d7f5d3SJohn Marino }
754*86d7f5d3SJohn Marino
755*86d7f5d3SJohn Marino fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r");
756*86d7f5d3SJohn Marino if (fp)
757*86d7f5d3SJohn Marino {
758*86d7f5d3SJohn Marino /*
759*86d7f5d3SJohn Marino * File format:
760*86d7f5d3SJohn Marino * [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>
761*86d7f5d3SJohn Marino *
762*86d7f5d3SJohn Marino * comment lines begin with '#'
763*86d7f5d3SJohn Marino */
764*86d7f5d3SJohn Marino while (getline (&line, &line_allocated, fp) >= 0)
765*86d7f5d3SJohn Marino {
766*86d7f5d3SJohn Marino /* skip lines starting with # */
767*86d7f5d3SJohn Marino if (line[0] == '#')
768*86d7f5d3SJohn Marino continue;
769*86d7f5d3SJohn Marino
770*86d7f5d3SJohn Marino if ((last = strrchr (line, '\n')) != NULL)
771*86d7f5d3SJohn Marino *last = '\0'; /* strip the newline */
772*86d7f5d3SJohn Marino
773*86d7f5d3SJohn Marino /* Skip leading white space. */
774*86d7f5d3SJohn Marino for (fname = line;
775*86d7f5d3SJohn Marino *fname && isspace ((unsigned char) *fname);
776*86d7f5d3SJohn Marino fname++)
777*86d7f5d3SJohn Marino ;
778*86d7f5d3SJohn Marino
779*86d7f5d3SJohn Marino /* Find end of filename. */
780*86d7f5d3SJohn Marino for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++)
781*86d7f5d3SJohn Marino ;
782*86d7f5d3SJohn Marino *cp = '\0';
783*86d7f5d3SJohn Marino
784*86d7f5d3SJohn Marino temp = make_tempfile ();
785*86d7f5d3SJohn Marino if (checkout_file (fname, temp) == 0)
786*86d7f5d3SJohn Marino {
787*86d7f5d3SJohn Marino rename_rcsfile (temp, fname);
788*86d7f5d3SJohn Marino }
789*86d7f5d3SJohn Marino else
790*86d7f5d3SJohn Marino {
791*86d7f5d3SJohn Marino /* Skip leading white space before the error message. */
792*86d7f5d3SJohn Marino for (cp++;
793*86d7f5d3SJohn Marino cp < last && *cp && isspace ((unsigned char) *cp);
794*86d7f5d3SJohn Marino cp++)
795*86d7f5d3SJohn Marino ;
796*86d7f5d3SJohn Marino if (cp < last && *cp)
797*86d7f5d3SJohn Marino error (0, 0, "%s", cp);
798*86d7f5d3SJohn Marino }
799*86d7f5d3SJohn Marino if (unlink_file (temp) < 0
800*86d7f5d3SJohn Marino && !existence_error (errno))
801*86d7f5d3SJohn Marino error (0, errno, "cannot remove %s", temp);
802*86d7f5d3SJohn Marino free (temp);
803*86d7f5d3SJohn Marino }
804*86d7f5d3SJohn Marino if (line)
805*86d7f5d3SJohn Marino free (line);
806*86d7f5d3SJohn Marino if (ferror (fp))
807*86d7f5d3SJohn Marino error (0, errno, "cannot read %s", CVSROOTADM_CHECKOUTLIST);
808*86d7f5d3SJohn Marino if (fclose (fp) < 0)
809*86d7f5d3SJohn Marino error (0, errno, "cannot close %s", CVSROOTADM_CHECKOUTLIST);
810*86d7f5d3SJohn Marino }
811*86d7f5d3SJohn Marino else
812*86d7f5d3SJohn Marino {
813*86d7f5d3SJohn Marino /* Error from CVS_FOPEN. */
814*86d7f5d3SJohn Marino if (!existence_error (errno))
815*86d7f5d3SJohn Marino error (0, errno, "cannot open %s", CVSROOTADM_CHECKOUTLIST);
816*86d7f5d3SJohn Marino }
817*86d7f5d3SJohn Marino
818*86d7f5d3SJohn Marino if (restore_cwd (&cwd))
819*86d7f5d3SJohn Marino error (1, errno, "Failed to restore current directory, `%s'.",
820*86d7f5d3SJohn Marino cwd.name);
821*86d7f5d3SJohn Marino free_cwd (&cwd);
822*86d7f5d3SJohn Marino
823*86d7f5d3SJohn Marino return 0;
824*86d7f5d3SJohn Marino }
825*86d7f5d3SJohn Marino
826*86d7f5d3SJohn Marino
827*86d7f5d3SJohn Marino
828*86d7f5d3SJohn Marino /*
829*86d7f5d3SJohn Marino * Yeah, I know, there are NFS race conditions here.
830*86d7f5d3SJohn Marino */
831*86d7f5d3SJohn Marino static char *
make_tempfile(void)832*86d7f5d3SJohn Marino make_tempfile (void)
833*86d7f5d3SJohn Marino {
834*86d7f5d3SJohn Marino static int seed = 0;
835*86d7f5d3SJohn Marino int fd;
836*86d7f5d3SJohn Marino char *temp;
837*86d7f5d3SJohn Marino
838*86d7f5d3SJohn Marino if (seed == 0)
839*86d7f5d3SJohn Marino seed = getpid ();
840*86d7f5d3SJohn Marino temp = xmalloc (sizeof (BAKPREFIX) + 40);
841*86d7f5d3SJohn Marino while (1)
842*86d7f5d3SJohn Marino {
843*86d7f5d3SJohn Marino (void) sprintf (temp, "%s%d", BAKPREFIX, seed++);
844*86d7f5d3SJohn Marino if ((fd = CVS_OPEN (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
845*86d7f5d3SJohn Marino break;
846*86d7f5d3SJohn Marino if (errno != EEXIST)
847*86d7f5d3SJohn Marino error (1, errno, "cannot create temporary file %s", temp);
848*86d7f5d3SJohn Marino }
849*86d7f5d3SJohn Marino if (close(fd) < 0)
850*86d7f5d3SJohn Marino error(1, errno, "cannot close temporary file %s", temp);
851*86d7f5d3SJohn Marino return temp;
852*86d7f5d3SJohn Marino }
853*86d7f5d3SJohn Marino
854*86d7f5d3SJohn Marino
855*86d7f5d3SJohn Marino
856*86d7f5d3SJohn Marino /* Get a file. If the file does not exist, return 1 silently. If
857*86d7f5d3SJohn Marino there is an error, print a message and return 1 (FIXME: probably
858*86d7f5d3SJohn Marino not a very clean convention). On success, return 0. */
859*86d7f5d3SJohn Marino static int
checkout_file(char * file,char * temp)860*86d7f5d3SJohn Marino checkout_file (char *file, char *temp)
861*86d7f5d3SJohn Marino {
862*86d7f5d3SJohn Marino char *rcs;
863*86d7f5d3SJohn Marino RCSNode *rcsnode;
864*86d7f5d3SJohn Marino int retcode = 0;
865*86d7f5d3SJohn Marino
866*86d7f5d3SJohn Marino if (noexec)
867*86d7f5d3SJohn Marino return 0;
868*86d7f5d3SJohn Marino
869*86d7f5d3SJohn Marino rcs = Xasprintf ("%s%s", file, RCSEXT);
870*86d7f5d3SJohn Marino if (!isfile (rcs))
871*86d7f5d3SJohn Marino {
872*86d7f5d3SJohn Marino free (rcs);
873*86d7f5d3SJohn Marino return 1;
874*86d7f5d3SJohn Marino }
875*86d7f5d3SJohn Marino
876*86d7f5d3SJohn Marino rcsnode = RCS_parsercsfile (rcs);
877*86d7f5d3SJohn Marino if (!rcsnode)
878*86d7f5d3SJohn Marino {
879*86d7f5d3SJohn Marino /* Probably not necessary (?); RCS_parsercsfile already printed a
880*86d7f5d3SJohn Marino message. */
881*86d7f5d3SJohn Marino error (0, 0, "Failed to parse `%s'.", rcs);
882*86d7f5d3SJohn Marino free (rcs);
883*86d7f5d3SJohn Marino return 1;
884*86d7f5d3SJohn Marino }
885*86d7f5d3SJohn Marino
886*86d7f5d3SJohn Marino retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp, NULL, NULL);
887*86d7f5d3SJohn Marino if (retcode != 0)
888*86d7f5d3SJohn Marino {
889*86d7f5d3SJohn Marino /* Probably not necessary (?); RCS_checkout already printed a
890*86d7f5d3SJohn Marino message. */
891*86d7f5d3SJohn Marino error (0, 0, "failed to check out %s file",
892*86d7f5d3SJohn Marino file);
893*86d7f5d3SJohn Marino }
894*86d7f5d3SJohn Marino freercsnode (&rcsnode);
895*86d7f5d3SJohn Marino free (rcs);
896*86d7f5d3SJohn Marino return retcode;
897*86d7f5d3SJohn Marino }
898*86d7f5d3SJohn Marino
899*86d7f5d3SJohn Marino
900*86d7f5d3SJohn Marino
901*86d7f5d3SJohn Marino #ifndef MY_NDBM
902*86d7f5d3SJohn Marino
903*86d7f5d3SJohn Marino static void
write_dbmfile(char * temp)904*86d7f5d3SJohn Marino write_dbmfile( char *temp )
905*86d7f5d3SJohn Marino {
906*86d7f5d3SJohn Marino char line[DBLKSIZ], value[DBLKSIZ];
907*86d7f5d3SJohn Marino FILE *fp;
908*86d7f5d3SJohn Marino DBM *db;
909*86d7f5d3SJohn Marino char *cp, *vp;
910*86d7f5d3SJohn Marino datum key, val;
911*86d7f5d3SJohn Marino int len, cont, err = 0;
912*86d7f5d3SJohn Marino
913*86d7f5d3SJohn Marino fp = xfopen (temp, "r");
914*86d7f5d3SJohn Marino if ((db = dbm_open (temp, O_RDWR | O_CREAT | O_TRUNC, 0666)) == NULL)
915*86d7f5d3SJohn Marino error (1, errno, "cannot open dbm file %s for creation", temp);
916*86d7f5d3SJohn Marino for (cont = 0; fgets (line, sizeof (line), fp) != NULL;)
917*86d7f5d3SJohn Marino {
918*86d7f5d3SJohn Marino if ((cp = strrchr (line, '\n')) != NULL)
919*86d7f5d3SJohn Marino *cp = '\0'; /* strip the newline */
920*86d7f5d3SJohn Marino
921*86d7f5d3SJohn Marino /*
922*86d7f5d3SJohn Marino * Add the line to the value, at the end if this is a continuation
923*86d7f5d3SJohn Marino * line; otherwise at the beginning, but only after any trailing
924*86d7f5d3SJohn Marino * backslash is removed.
925*86d7f5d3SJohn Marino */
926*86d7f5d3SJohn Marino vp = value;
927*86d7f5d3SJohn Marino if (cont)
928*86d7f5d3SJohn Marino vp += strlen (value);
929*86d7f5d3SJohn Marino
930*86d7f5d3SJohn Marino /*
931*86d7f5d3SJohn Marino * See if the line we read is a continuation line, and strip the
932*86d7f5d3SJohn Marino * backslash if so.
933*86d7f5d3SJohn Marino */
934*86d7f5d3SJohn Marino len = strlen (line);
935*86d7f5d3SJohn Marino if (len > 0)
936*86d7f5d3SJohn Marino cp = &line[len - 1];
937*86d7f5d3SJohn Marino else
938*86d7f5d3SJohn Marino cp = line;
939*86d7f5d3SJohn Marino if (*cp == '\\')
940*86d7f5d3SJohn Marino {
941*86d7f5d3SJohn Marino cont = 1;
942*86d7f5d3SJohn Marino *cp = '\0';
943*86d7f5d3SJohn Marino }
944*86d7f5d3SJohn Marino else
945*86d7f5d3SJohn Marino {
946*86d7f5d3SJohn Marino cont = 0;
947*86d7f5d3SJohn Marino }
948*86d7f5d3SJohn Marino (void) strcpy (vp, line);
949*86d7f5d3SJohn Marino if (value[0] == '#')
950*86d7f5d3SJohn Marino continue; /* comment line */
951*86d7f5d3SJohn Marino vp = value;
952*86d7f5d3SJohn Marino while (*vp && isspace ((unsigned char) *vp))
953*86d7f5d3SJohn Marino vp++;
954*86d7f5d3SJohn Marino if (*vp == '\0')
955*86d7f5d3SJohn Marino continue; /* empty line */
956*86d7f5d3SJohn Marino
957*86d7f5d3SJohn Marino /*
958*86d7f5d3SJohn Marino * If this was not a continuation line, add the entry to the database
959*86d7f5d3SJohn Marino */
960*86d7f5d3SJohn Marino if (!cont)
961*86d7f5d3SJohn Marino {
962*86d7f5d3SJohn Marino key.dptr = vp;
963*86d7f5d3SJohn Marino while (*vp && !isspace ((unsigned char) *vp))
964*86d7f5d3SJohn Marino vp++;
965*86d7f5d3SJohn Marino key.dsize = vp - key.dptr;
966*86d7f5d3SJohn Marino *vp++ = '\0'; /* NULL terminate the key */
967*86d7f5d3SJohn Marino while (*vp && isspace ((unsigned char) *vp))
968*86d7f5d3SJohn Marino vp++; /* skip whitespace to value */
969*86d7f5d3SJohn Marino if (*vp == '\0')
970*86d7f5d3SJohn Marino {
971*86d7f5d3SJohn Marino error (0, 0, "warning: NULL value for key `%s'", key.dptr);
972*86d7f5d3SJohn Marino continue;
973*86d7f5d3SJohn Marino }
974*86d7f5d3SJohn Marino val.dptr = vp;
975*86d7f5d3SJohn Marino val.dsize = strlen (vp);
976*86d7f5d3SJohn Marino if (dbm_store (db, key, val, DBM_INSERT) == 1)
977*86d7f5d3SJohn Marino {
978*86d7f5d3SJohn Marino error (0, 0, "duplicate key found for `%s'", key.dptr);
979*86d7f5d3SJohn Marino err++;
980*86d7f5d3SJohn Marino }
981*86d7f5d3SJohn Marino }
982*86d7f5d3SJohn Marino }
983*86d7f5d3SJohn Marino dbm_close (db);
984*86d7f5d3SJohn Marino if (fclose (fp) < 0)
985*86d7f5d3SJohn Marino error (0, errno, "cannot close %s", temp);
986*86d7f5d3SJohn Marino if (err)
987*86d7f5d3SJohn Marino {
988*86d7f5d3SJohn Marino /* I think that the size of the buffer needed here is
989*86d7f5d3SJohn Marino just determined by sizeof (CVSROOTADM_MODULES), the
990*86d7f5d3SJohn Marino filenames created by make_tempfile, and other things that won't
991*86d7f5d3SJohn Marino overflow. */
992*86d7f5d3SJohn Marino char dotdir[50], dotpag[50], dotdb[50];
993*86d7f5d3SJohn Marino
994*86d7f5d3SJohn Marino (void) sprintf (dotdir, "%s.dir", temp);
995*86d7f5d3SJohn Marino (void) sprintf (dotpag, "%s.pag", temp);
996*86d7f5d3SJohn Marino (void) sprintf (dotdb, "%s.db", temp);
997*86d7f5d3SJohn Marino if (unlink_file (dotdir) < 0
998*86d7f5d3SJohn Marino && !existence_error (errno))
999*86d7f5d3SJohn Marino error (0, errno, "cannot remove %s", dotdir);
1000*86d7f5d3SJohn Marino if (unlink_file (dotpag) < 0
1001*86d7f5d3SJohn Marino && !existence_error (errno))
1002*86d7f5d3SJohn Marino error (0, errno, "cannot remove %s", dotpag);
1003*86d7f5d3SJohn Marino if (unlink_file (dotdb) < 0
1004*86d7f5d3SJohn Marino && !existence_error (errno))
1005*86d7f5d3SJohn Marino error (0, errno, "cannot remove %s", dotdb);
1006*86d7f5d3SJohn Marino error (1, 0, "DBM creation failed; correct above errors");
1007*86d7f5d3SJohn Marino }
1008*86d7f5d3SJohn Marino }
1009*86d7f5d3SJohn Marino
1010*86d7f5d3SJohn Marino static void
rename_dbmfile(char * temp)1011*86d7f5d3SJohn Marino rename_dbmfile( char *temp )
1012*86d7f5d3SJohn Marino {
1013*86d7f5d3SJohn Marino /* I think that the size of the buffer needed here is
1014*86d7f5d3SJohn Marino just determined by sizeof (CVSROOTADM_MODULES), the
1015*86d7f5d3SJohn Marino filenames created by make_tempfile, and other things that won't
1016*86d7f5d3SJohn Marino overflow. */
1017*86d7f5d3SJohn Marino char newdir[50], newpag[50], newdb[50];
1018*86d7f5d3SJohn Marino char dotdir[50], dotpag[50], dotdb[50];
1019*86d7f5d3SJohn Marino char bakdir[50], bakpag[50], bakdb[50];
1020*86d7f5d3SJohn Marino
1021*86d7f5d3SJohn Marino int dir1_errno = 0, pag1_errno = 0, db1_errno = 0;
1022*86d7f5d3SJohn Marino int dir2_errno = 0, pag2_errno = 0, db2_errno = 0;
1023*86d7f5d3SJohn Marino int dir3_errno = 0, pag3_errno = 0, db3_errno = 0;
1024*86d7f5d3SJohn Marino
1025*86d7f5d3SJohn Marino (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES);
1026*86d7f5d3SJohn Marino (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES);
1027*86d7f5d3SJohn Marino (void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES);
1028*86d7f5d3SJohn Marino (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES);
1029*86d7f5d3SJohn Marino (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES);
1030*86d7f5d3SJohn Marino (void) sprintf (bakdb, "%s%s.db", BAKPREFIX, CVSROOTADM_MODULES);
1031*86d7f5d3SJohn Marino (void) sprintf (newdir, "%s.dir", temp);
1032*86d7f5d3SJohn Marino (void) sprintf (newpag, "%s.pag", temp);
1033*86d7f5d3SJohn Marino (void) sprintf (newdb, "%s.db", temp);
1034*86d7f5d3SJohn Marino
1035*86d7f5d3SJohn Marino (void) chmod (newdir, 0666);
1036*86d7f5d3SJohn Marino (void) chmod (newpag, 0666);
1037*86d7f5d3SJohn Marino (void) chmod (newdb, 0666);
1038*86d7f5d3SJohn Marino
1039*86d7f5d3SJohn Marino /* don't mess with me */
1040*86d7f5d3SJohn Marino SIG_beginCrSect ();
1041*86d7f5d3SJohn Marino
1042*86d7f5d3SJohn Marino /* rm .#modules.dir .#modules.pag */
1043*86d7f5d3SJohn Marino if (unlink_file (bakdir) < 0)
1044*86d7f5d3SJohn Marino dir1_errno = errno;
1045*86d7f5d3SJohn Marino if (unlink_file (bakpag) < 0)
1046*86d7f5d3SJohn Marino pag1_errno = errno;
1047*86d7f5d3SJohn Marino if (unlink_file (bakdb) < 0)
1048*86d7f5d3SJohn Marino db1_errno = errno;
1049*86d7f5d3SJohn Marino
1050*86d7f5d3SJohn Marino /* mv modules.dir .#modules.dir */
1051*86d7f5d3SJohn Marino if (CVS_RENAME (dotdir, bakdir) < 0)
1052*86d7f5d3SJohn Marino dir2_errno = errno;
1053*86d7f5d3SJohn Marino /* mv modules.pag .#modules.pag */
1054*86d7f5d3SJohn Marino if (CVS_RENAME (dotpag, bakpag) < 0)
1055*86d7f5d3SJohn Marino pag2_errno = errno;
1056*86d7f5d3SJohn Marino /* mv modules.db .#modules.db */
1057*86d7f5d3SJohn Marino if (CVS_RENAME (dotdb, bakdb) < 0)
1058*86d7f5d3SJohn Marino db2_errno = errno;
1059*86d7f5d3SJohn Marino
1060*86d7f5d3SJohn Marino /* mv "temp".dir modules.dir */
1061*86d7f5d3SJohn Marino if (CVS_RENAME (newdir, dotdir) < 0)
1062*86d7f5d3SJohn Marino dir3_errno = errno;
1063*86d7f5d3SJohn Marino /* mv "temp".pag modules.pag */
1064*86d7f5d3SJohn Marino if (CVS_RENAME (newpag, dotpag) < 0)
1065*86d7f5d3SJohn Marino pag3_errno = errno;
1066*86d7f5d3SJohn Marino /* mv "temp".db modules.db */
1067*86d7f5d3SJohn Marino if (CVS_RENAME (newdb, dotdb) < 0)
1068*86d7f5d3SJohn Marino db3_errno = errno;
1069*86d7f5d3SJohn Marino
1070*86d7f5d3SJohn Marino /* OK -- make my day */
1071*86d7f5d3SJohn Marino SIG_endCrSect ();
1072*86d7f5d3SJohn Marino
1073*86d7f5d3SJohn Marino /* I didn't want to call error() when we had signals blocked
1074*86d7f5d3SJohn Marino (unnecessary?), but do it now. */
1075*86d7f5d3SJohn Marino if (dir1_errno && !existence_error (dir1_errno))
1076*86d7f5d3SJohn Marino error (0, dir1_errno, "cannot remove %s", bakdir);
1077*86d7f5d3SJohn Marino if (pag1_errno && !existence_error (pag1_errno))
1078*86d7f5d3SJohn Marino error (0, pag1_errno, "cannot remove %s", bakpag);
1079*86d7f5d3SJohn Marino if (db1_errno && !existence_error (db1_errno))
1080*86d7f5d3SJohn Marino error (0, db1_errno, "cannot remove %s", bakdb);
1081*86d7f5d3SJohn Marino
1082*86d7f5d3SJohn Marino if (dir2_errno && !existence_error (dir2_errno))
1083*86d7f5d3SJohn Marino error (0, dir2_errno, "cannot remove %s", bakdir);
1084*86d7f5d3SJohn Marino if (pag2_errno && !existence_error (pag2_errno))
1085*86d7f5d3SJohn Marino error (0, pag2_errno, "cannot remove %s", bakpag);
1086*86d7f5d3SJohn Marino if (db2_errno && !existence_error (db2_errno))
1087*86d7f5d3SJohn Marino error (0, db2_errno, "cannot remove %s", bakdb);
1088*86d7f5d3SJohn Marino
1089*86d7f5d3SJohn Marino if (dir3_errno && !existence_error (dir3_errno))
1090*86d7f5d3SJohn Marino error (0, dir3_errno, "cannot remove %s", bakdir);
1091*86d7f5d3SJohn Marino if (pag3_errno && !existence_error (pag3_errno))
1092*86d7f5d3SJohn Marino error (0, pag3_errno, "cannot remove %s", bakpag);
1093*86d7f5d3SJohn Marino if (db3_errno && !existence_error (db3_errno))
1094*86d7f5d3SJohn Marino error (0, db3_errno, "cannot remove %s", bakdb);
1095*86d7f5d3SJohn Marino }
1096*86d7f5d3SJohn Marino
1097*86d7f5d3SJohn Marino #endif /* !MY_NDBM */
1098*86d7f5d3SJohn Marino
1099*86d7f5d3SJohn Marino static void
rename_rcsfile(char * temp,char * real)1100*86d7f5d3SJohn Marino rename_rcsfile (char *temp, char *real)
1101*86d7f5d3SJohn Marino {
1102*86d7f5d3SJohn Marino char *bak;
1103*86d7f5d3SJohn Marino struct stat statbuf;
1104*86d7f5d3SJohn Marino char *rcs;
1105*86d7f5d3SJohn Marino
1106*86d7f5d3SJohn Marino /* Set "x" bits if set in original. */
1107*86d7f5d3SJohn Marino rcs = Xasprintf ("%s%s", real, RCSEXT);
1108*86d7f5d3SJohn Marino statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */
1109*86d7f5d3SJohn Marino if (stat (rcs, &statbuf) < 0
1110*86d7f5d3SJohn Marino && !existence_error (errno))
1111*86d7f5d3SJohn Marino error (0, errno, "cannot stat %s", rcs);
1112*86d7f5d3SJohn Marino free (rcs);
1113*86d7f5d3SJohn Marino
1114*86d7f5d3SJohn Marino if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0)
1115*86d7f5d3SJohn Marino error (0, errno, "warning: cannot chmod %s", temp);
1116*86d7f5d3SJohn Marino bak = Xasprintf ("%s%s", BAKPREFIX, real);
1117*86d7f5d3SJohn Marino
1118*86d7f5d3SJohn Marino /* rm .#loginfo */
1119*86d7f5d3SJohn Marino if (unlink_file (bak) < 0
1120*86d7f5d3SJohn Marino && !existence_error (errno))
1121*86d7f5d3SJohn Marino error (0, errno, "cannot remove %s", bak);
1122*86d7f5d3SJohn Marino
1123*86d7f5d3SJohn Marino /* mv loginfo .#loginfo */
1124*86d7f5d3SJohn Marino if (CVS_RENAME (real, bak) < 0
1125*86d7f5d3SJohn Marino && !existence_error (errno))
1126*86d7f5d3SJohn Marino error (0, errno, "cannot rename %s to %s", real, bak);
1127*86d7f5d3SJohn Marino
1128*86d7f5d3SJohn Marino /* mv "temp" loginfo */
1129*86d7f5d3SJohn Marino if (CVS_RENAME (temp, real) < 0
1130*86d7f5d3SJohn Marino && !existence_error (errno))
1131*86d7f5d3SJohn Marino error (0, errno, "cannot rename %s to %s", temp, real);
1132*86d7f5d3SJohn Marino
1133*86d7f5d3SJohn Marino free (bak);
1134*86d7f5d3SJohn Marino }
1135*86d7f5d3SJohn Marino
1136*86d7f5d3SJohn Marino const char *const init_usage[] = {
1137*86d7f5d3SJohn Marino "Usage: %s %s\n",
1138*86d7f5d3SJohn Marino "(Specify the --help global option for a list of other help options)\n",
1139*86d7f5d3SJohn Marino NULL
1140*86d7f5d3SJohn Marino };
1141*86d7f5d3SJohn Marino
1142*86d7f5d3SJohn Marino int
init(int argc,char ** argv)1143*86d7f5d3SJohn Marino init (int argc, char **argv)
1144*86d7f5d3SJohn Marino {
1145*86d7f5d3SJohn Marino /* Name of CVSROOT directory. */
1146*86d7f5d3SJohn Marino char *adm;
1147*86d7f5d3SJohn Marino /* Name of this administrative file. */
1148*86d7f5d3SJohn Marino char *info;
1149*86d7f5d3SJohn Marino /* Name of ,v file for this administrative file. */
1150*86d7f5d3SJohn Marino char *info_v;
1151*86d7f5d3SJohn Marino /* Exit status. */
1152*86d7f5d3SJohn Marino int err = 0;
1153*86d7f5d3SJohn Marino
1154*86d7f5d3SJohn Marino const struct admin_file *fileptr;
1155*86d7f5d3SJohn Marino
1156*86d7f5d3SJohn Marino umask (cvsumask);
1157*86d7f5d3SJohn Marino
1158*86d7f5d3SJohn Marino if (argc == -1 || argc > 1)
1159*86d7f5d3SJohn Marino usage (init_usage);
1160*86d7f5d3SJohn Marino
1161*86d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
1162*86d7f5d3SJohn Marino if (current_parsed_root->isremote)
1163*86d7f5d3SJohn Marino {
1164*86d7f5d3SJohn Marino start_server ();
1165*86d7f5d3SJohn Marino
1166*86d7f5d3SJohn Marino ign_setup ();
1167*86d7f5d3SJohn Marino send_init_command ();
1168*86d7f5d3SJohn Marino return get_responses_and_close ();
1169*86d7f5d3SJohn Marino }
1170*86d7f5d3SJohn Marino #endif /* CLIENT_SUPPORT */
1171*86d7f5d3SJohn Marino
1172*86d7f5d3SJohn Marino /* Note: we do *not* create parent directories as needed like the
1173*86d7f5d3SJohn Marino old cvsinit.sh script did. Few utilities do that, and a
1174*86d7f5d3SJohn Marino non-existent parent directory is as likely to be a typo as something
1175*86d7f5d3SJohn Marino which needs to be created. */
1176*86d7f5d3SJohn Marino mkdir_if_needed (current_parsed_root->directory);
1177*86d7f5d3SJohn Marino
1178*86d7f5d3SJohn Marino adm = Xasprintf ("%s/%s", current_parsed_root->directory, CVSROOTADM);
1179*86d7f5d3SJohn Marino mkdir_if_needed (adm);
1180*86d7f5d3SJohn Marino
1181*86d7f5d3SJohn Marino /* This is needed because we pass "fileptr->filename" not "info"
1182*86d7f5d3SJohn Marino to add_rcs_file below. I think this would be easy to change,
1183*86d7f5d3SJohn Marino thus nuking the need for CVS_CHDIR here, but I haven't looked
1184*86d7f5d3SJohn Marino closely (e.g. see wrappers calls within add_rcs_file). */
1185*86d7f5d3SJohn Marino if ( CVS_CHDIR (adm) < 0)
1186*86d7f5d3SJohn Marino error (1, errno, "cannot change to directory %s", adm);
1187*86d7f5d3SJohn Marino
1188*86d7f5d3SJohn Marino /* Make Emptydir so it's there if we need it */
1189*86d7f5d3SJohn Marino mkdir_if_needed (CVSNULLREPOS);
1190*86d7f5d3SJohn Marino
1191*86d7f5d3SJohn Marino /* 80 is long enough for all the administrative file names, plus
1192*86d7f5d3SJohn Marino "/" and so on. */
1193*86d7f5d3SJohn Marino info = xmalloc (strlen (adm) + 80);
1194*86d7f5d3SJohn Marino info_v = xmalloc (strlen (adm) + 80);
1195*86d7f5d3SJohn Marino for (fileptr = filelist; fileptr && fileptr->filename; ++fileptr)
1196*86d7f5d3SJohn Marino {
1197*86d7f5d3SJohn Marino if (fileptr->contents == NULL)
1198*86d7f5d3SJohn Marino continue;
1199*86d7f5d3SJohn Marino strcpy (info, adm);
1200*86d7f5d3SJohn Marino strcat (info, "/");
1201*86d7f5d3SJohn Marino strcat (info, fileptr->filename);
1202*86d7f5d3SJohn Marino strcpy (info_v, info);
1203*86d7f5d3SJohn Marino strcat (info_v, RCSEXT);
1204*86d7f5d3SJohn Marino if (isfile (info_v))
1205*86d7f5d3SJohn Marino /* We will check out this file in the mkmodules step.
1206*86d7f5d3SJohn Marino Nothing else is required. */
1207*86d7f5d3SJohn Marino ;
1208*86d7f5d3SJohn Marino else
1209*86d7f5d3SJohn Marino {
1210*86d7f5d3SJohn Marino int retcode;
1211*86d7f5d3SJohn Marino
1212*86d7f5d3SJohn Marino if (!isfile (info))
1213*86d7f5d3SJohn Marino {
1214*86d7f5d3SJohn Marino FILE *fp;
1215*86d7f5d3SJohn Marino const char * const *p;
1216*86d7f5d3SJohn Marino
1217*86d7f5d3SJohn Marino fp = xfopen (info, "w");
1218*86d7f5d3SJohn Marino for (p = fileptr->contents; *p != NULL; ++p)
1219*86d7f5d3SJohn Marino if (fputs (*p, fp) < 0)
1220*86d7f5d3SJohn Marino error (1, errno, "cannot write %s", info);
1221*86d7f5d3SJohn Marino if (fclose (fp) < 0)
1222*86d7f5d3SJohn Marino error (1, errno, "cannot close %s", info);
1223*86d7f5d3SJohn Marino }
1224*86d7f5d3SJohn Marino /* The message used to say " of " and fileptr->filename after
1225*86d7f5d3SJohn Marino "initial checkin" but I fail to see the point as we know what
1226*86d7f5d3SJohn Marino file it is from the name. */
1227*86d7f5d3SJohn Marino retcode = add_rcs_file ("initial checkin", info_v,
1228*86d7f5d3SJohn Marino fileptr->filename, "1.1", NULL,
1229*86d7f5d3SJohn Marino
1230*86d7f5d3SJohn Marino /* No vendor branch. */
1231*86d7f5d3SJohn Marino NULL, NULL, 0, NULL,
1232*86d7f5d3SJohn Marino
1233*86d7f5d3SJohn Marino NULL, 0, NULL, 0);
1234*86d7f5d3SJohn Marino if (retcode != 0)
1235*86d7f5d3SJohn Marino /* add_rcs_file already printed an error message. */
1236*86d7f5d3SJohn Marino err = 1;
1237*86d7f5d3SJohn Marino }
1238*86d7f5d3SJohn Marino }
1239*86d7f5d3SJohn Marino
1240*86d7f5d3SJohn Marino /* Turn on history logging by default. The user can remove the file
1241*86d7f5d3SJohn Marino to disable it. */
1242*86d7f5d3SJohn Marino strcpy (info, adm);
1243*86d7f5d3SJohn Marino strcat (info, "/");
1244*86d7f5d3SJohn Marino strcat (info, CVSROOTADM_HISTORY);
1245*86d7f5d3SJohn Marino if (!isfile (info))
1246*86d7f5d3SJohn Marino {
1247*86d7f5d3SJohn Marino FILE *fp;
1248*86d7f5d3SJohn Marino
1249*86d7f5d3SJohn Marino fp = xfopen (info, "w");
1250*86d7f5d3SJohn Marino if (fclose (fp) < 0)
1251*86d7f5d3SJohn Marino error (1, errno, "cannot close %s", info);
1252*86d7f5d3SJohn Marino
1253*86d7f5d3SJohn Marino /* Make the new history file world-writeable, since every CVS
1254*86d7f5d3SJohn Marino user will need to be able to write to it. We use chmod()
1255*86d7f5d3SJohn Marino because xchmod() is too shy. */
1256*86d7f5d3SJohn Marino chmod (info, 0666);
1257*86d7f5d3SJohn Marino }
1258*86d7f5d3SJohn Marino
1259*86d7f5d3SJohn Marino /* Make an empty val-tags file to prevent problems creating it later. */
1260*86d7f5d3SJohn Marino strcpy (info, adm);
1261*86d7f5d3SJohn Marino strcat (info, "/");
1262*86d7f5d3SJohn Marino strcat (info, CVSROOTADM_VALTAGS);
1263*86d7f5d3SJohn Marino if (!isfile (info))
1264*86d7f5d3SJohn Marino {
1265*86d7f5d3SJohn Marino FILE *fp;
1266*86d7f5d3SJohn Marino
1267*86d7f5d3SJohn Marino fp = xfopen (info, "w");
1268*86d7f5d3SJohn Marino if (fclose (fp) < 0)
1269*86d7f5d3SJohn Marino error (1, errno, "cannot close %s", info);
1270*86d7f5d3SJohn Marino
1271*86d7f5d3SJohn Marino /* Make the new val-tags file world-writeable, since every CVS
1272*86d7f5d3SJohn Marino user will need to be able to write to it. We use chmod()
1273*86d7f5d3SJohn Marino because xchmod() is too shy. */
1274*86d7f5d3SJohn Marino chmod (info, 0666);
1275*86d7f5d3SJohn Marino }
1276*86d7f5d3SJohn Marino
1277*86d7f5d3SJohn Marino free (info);
1278*86d7f5d3SJohn Marino free (info_v);
1279*86d7f5d3SJohn Marino
1280*86d7f5d3SJohn Marino mkmodules (adm);
1281*86d7f5d3SJohn Marino
1282*86d7f5d3SJohn Marino free (adm);
1283*86d7f5d3SJohn Marino return err;
1284*86d7f5d3SJohn Marino }
1285