| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: cvs.c,v 1.159 2017/06/01 08:08:24 joris Exp $ */  | 
    ||
2  | 
    /*  | 
    ||
3  | 
    * Copyright (c) 2006, 2007 Joris Vink <joris@openbsd.org>  | 
    ||
4  | 
    * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>  | 
    ||
5  | 
    * All rights reserved.  | 
    ||
6  | 
    *  | 
    ||
7  | 
    * Redistribution and use in source and binary forms, with or without  | 
    ||
8  | 
    * modification, are permitted provided that the following conditions  | 
    ||
9  | 
    * are met:  | 
    ||
10  | 
    *  | 
    ||
11  | 
    * 1. Redistributions of source code must retain the above copyright  | 
    ||
12  | 
    * notice, this list of conditions and the following disclaimer.  | 
    ||
13  | 
    * 2. The name of the author may not be used to endorse or promote products  | 
    ||
14  | 
    * derived from this software without specific prior written permission.  | 
    ||
15  | 
    *  | 
    ||
16  | 
    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  | 
    ||
17  | 
    * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY  | 
    ||
18  | 
    * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL  | 
    ||
19  | 
    * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  | 
    ||
20  | 
    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  | 
    ||
21  | 
    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  | 
    ||
22  | 
    * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  | 
    ||
23  | 
    * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  | 
    ||
24  | 
    * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  | 
    ||
25  | 
    * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
    ||
26  | 
    */  | 
    ||
27  | 
    |||
28  | 
    #include <sys/stat.h>  | 
    ||
29  | 
    |||
30  | 
    #include <ctype.h>  | 
    ||
31  | 
    #include <errno.h>  | 
    ||
32  | 
    #include <pwd.h>  | 
    ||
33  | 
    #include <stdlib.h>  | 
    ||
34  | 
    #include <string.h>  | 
    ||
35  | 
    #include <time.h>  | 
    ||
36  | 
    #include <unistd.h>  | 
    ||
37  | 
    #include <err.h>  | 
    ||
38  | 
    |||
39  | 
    #include "cvs.h"  | 
    ||
40  | 
    #include "remote.h"  | 
    ||
41  | 
    #include "hash.h"  | 
    ||
42  | 
    |||
43  | 
    extern char *__progname;  | 
    ||
44  | 
    |||
45  | 
    /* verbosity level: 0 = really quiet, 1 = quiet, 2 = verbose */  | 
    ||
46  | 
    int verbosity = 2;  | 
    ||
47  | 
    |||
48  | 
    /* compression level used with zlib, 0 meaning no compression taking place */  | 
    ||
49  | 
    int cvs_compress = 0;  | 
    ||
50  | 
    int cvs_readrc = 1; /* read .cvsrc on startup */  | 
    ||
51  | 
    int cvs_trace = 0;  | 
    ||
52  | 
    int cvs_nolog = 0;  | 
    ||
53  | 
    int cvs_readonly = 0;  | 
    ||
54  | 
    int cvs_readonlyfs = 0;  | 
    ||
55  | 
    int cvs_nocase = 0; /* set to 1 to disable filename case sensitivity */  | 
    ||
56  | 
    int cvs_noexec = 0; /* set to 1 to disable disk operations (-n option) */  | 
    ||
57  | 
    int cvs_cmdop;  | 
    ||
58  | 
    int cvs_umask = CVS_UMASK_DEFAULT;  | 
    ||
59  | 
    int cvs_server_active = 0;  | 
    ||
60  | 
    |||
61  | 
    char *cvs_tagname = NULL;  | 
    ||
62  | 
    char *cvs_defargs; /* default global arguments from .cvsrc */  | 
    ||
63  | 
    char *cvs_rootstr;  | 
    ||
64  | 
    char *cvs_rsh = CVS_RSH_DEFAULT;  | 
    ||
65  | 
    char *cvs_editor = CVS_EDITOR_DEFAULT;  | 
    ||
66  | 
    char *cvs_homedir = NULL;  | 
    ||
67  | 
    char *cvs_tmpdir = CVS_TMPDIR_DEFAULT;  | 
    ||
68  | 
    |||
69  | 
    struct cvsroot *current_cvsroot = NULL;  | 
    ||
70  | 
    struct cvs_cmd *cmdp; /* struct of command we are running */  | 
    ||
71  | 
    |||
72  | 
    int cvs_getopt(int, char **);  | 
    ||
73  | 
    __dead void usage(void);  | 
    ||
74  | 
    static void cvs_read_rcfile(void);  | 
    ||
75  | 
    |||
76  | 
    struct wklhead temp_files;  | 
    ||
77  | 
    |||
78  | 
    void sighandler(int);  | 
    ||
79  | 
    volatile sig_atomic_t cvs_quit = 0;  | 
    ||
80  | 
    volatile sig_atomic_t sig_received = 0;  | 
    ||
81  | 
    |||
82  | 
    extern CVSENTRIES *current_list;  | 
    ||
83  | 
    |||
84  | 
    struct hash_table created_directories;  | 
    ||
85  | 
    struct hash_table created_cvs_directories;  | 
    ||
86  | 
    |||
87  | 
    void  | 
    ||
88  | 
    sighandler(int sig)  | 
    ||
89  | 
    { | 
    ||
90  | 
    sig_received = sig;  | 
    ||
91  | 
    |||
92  | 
    	switch (sig) { | 
    ||
93  | 
    case SIGINT:  | 
    ||
94  | 
    case SIGTERM:  | 
    ||
95  | 
    case SIGPIPE:  | 
    ||
96  | 
    cvs_quit = 1;  | 
    ||
97  | 
    break;  | 
    ||
98  | 
    default:  | 
    ||
99  | 
    break;  | 
    ||
100  | 
    }  | 
    ||
101  | 
    }  | 
    ||
102  | 
    |||
103  | 
    void  | 
    ||
104  | 
    cvs_cleanup(void)  | 
    ||
105  | 
    { | 
    ||
106  | 
    82  | 
    cvs_log(LP_TRACE, "cvs_cleanup: removing locks");  | 
    |
107  | 
    41  | 
    worklist_run(&repo_locks, worklist_unlink);  | 
    |
108  | 
    |||
109  | 
    41  | 
    cvs_log(LP_TRACE, "cvs_cleanup: removing temp files");  | 
    |
110  | 
    41  | 
    worklist_run(&temp_files, worklist_unlink);  | 
    |
111  | 
    |||
112  | 
    ✗✓ | 41  | 
    	if (cvs_server_path != NULL) { | 
    
113  | 
    if (cvs_rmdir(cvs_server_path) == -1)  | 
    ||
114  | 
    cvs_log(LP_ERR,  | 
    ||
115  | 
    "warning: failed to remove server directory: %s",  | 
    ||
116  | 
    cvs_server_path);  | 
    ||
117  | 
    free(cvs_server_path);  | 
    ||
118  | 
    cvs_server_path = NULL;  | 
    ||
119  | 
    }  | 
    ||
120  | 
    |||
121  | 
    ✓✓ | 41  | 
    if (current_list != NULL)  | 
    
122  | 
    37  | 
    cvs_ent_close(current_list, ENT_SYNC);  | 
    |
123  | 
    41  | 
    }  | 
    |
124  | 
    |||
125  | 
    __dead void  | 
    ||
126  | 
    usage(void)  | 
    ||
127  | 
    { | 
    ||
128  | 
    (void)fprintf(stderr,  | 
    ||
129  | 
    "usage: %s [-flnQqRrtvw] [-d root] [-e editor] [-s var=val]\n"  | 
    ||
130  | 
    " [-T tmpdir] [-z level] command ...\n", __progname);  | 
    ||
131  | 
    exit(1);  | 
    ||
132  | 
    }  | 
    ||
133  | 
    |||
134  | 
    int  | 
    ||
135  | 
    cvs_build_cmd(char ***cmd_argv, char **argv, int argc)  | 
    ||
136  | 
    { | 
    ||
137  | 
    int cmd_argc, i, cur;  | 
    ||
138  | 
    82  | 
    char *cp, *linebuf, *lp;  | 
    |
139  | 
    |||
140  | 
    ✓✗ | 41  | 
    	if (cmdp->cmd_defargs == NULL) { | 
    
141  | 
    41  | 
    *cmd_argv = argv;  | 
    |
142  | 
    41  | 
    return argc;  | 
    |
143  | 
    }  | 
    ||
144  | 
    |||
145  | 
    cur = argc + 2;  | 
    ||
146  | 
    cmd_argc = 0;  | 
    ||
147  | 
    *cmd_argv = xcalloc(cur, sizeof(char *));  | 
    ||
148  | 
    (*cmd_argv)[cmd_argc++] = argv[0];  | 
    ||
149  | 
    |||
150  | 
    linebuf = xstrdup(cmdp->cmd_defargs);  | 
    ||
151  | 
    	for (lp = linebuf; lp != NULL;) { | 
    ||
152  | 
    cp = strsep(&lp, " \t\b\f\n\r\t\v");  | 
    ||
153  | 
    if (cp == NULL)  | 
    ||
154  | 
    break;  | 
    ||
155  | 
    if (*cp == '\0')  | 
    ||
156  | 
    continue;  | 
    ||
157  | 
    |||
158  | 
    		if (cmd_argc == cur) { | 
    ||
159  | 
    cur += 8;  | 
    ||
160  | 
    *cmd_argv = xreallocarray(*cmd_argv, cur,  | 
    ||
161  | 
    sizeof(char *));  | 
    ||
162  | 
    }  | 
    ||
163  | 
    |||
164  | 
    (*cmd_argv)[cmd_argc++] = cp;  | 
    ||
165  | 
    }  | 
    ||
166  | 
    |||
167  | 
    	if (cmd_argc + argc > cur) { | 
    ||
168  | 
    cur = cmd_argc + argc + 1;  | 
    ||
169  | 
    *cmd_argv = xreallocarray(*cmd_argv, cur,  | 
    ||
170  | 
    sizeof(char *));  | 
    ||
171  | 
    }  | 
    ||
172  | 
    |||
173  | 
    for (i = 1; i < argc; i++)  | 
    ||
174  | 
    (*cmd_argv)[cmd_argc++] = argv[i];  | 
    ||
175  | 
    |||
176  | 
    (*cmd_argv)[cmd_argc] = NULL;  | 
    ||
177  | 
    |||
178  | 
    return cmd_argc;  | 
    ||
179  | 
    41  | 
    }  | 
    |
180  | 
    |||
181  | 
    int  | 
    ||
182  | 
    main(int argc, char **argv)  | 
    ||
183  | 
    { | 
    ||
184  | 
    82  | 
    char *envstr, **cmd_argv, **targv;  | 
    |
185  | 
    41  | 
    int i, ret, cmd_argc;  | 
    |
186  | 
    struct passwd *pw;  | 
    ||
187  | 
    41  | 
    struct stat st;  | 
    |
188  | 
    41  | 
    char fpath[PATH_MAX];  | 
    |
189  | 
    |||
190  | 
    ✗✓ | 41  | 
    	if (pledge("stdio rpath wpath cpath fattr getpw proc exec flock", NULL) == -1) | 
    
191  | 
    err(1, "pledge");  | 
    ||
192  | 
    |||
193  | 
    41  | 
    tzset();  | 
    |
194  | 
    |||
195  | 
    41  | 
    TAILQ_INIT(&cvs_variables);  | 
    |
196  | 
    41  | 
    SLIST_INIT(&repo_locks);  | 
    |
197  | 
    41  | 
    SLIST_INIT(&temp_files);  | 
    |
198  | 
    |||
199  | 
    41  | 
    hash_table_init(&created_directories, 100);  | 
    |
200  | 
    41  | 
    hash_table_init(&created_cvs_directories, 100);  | 
    |
201  | 
    |||
202  | 
    /* check environment so command-line options override it */  | 
    ||
203  | 
    ✗✓ | 41  | 
    	if ((envstr = getenv("CVS_RSH")) != NULL) | 
    
204  | 
    cvs_rsh = envstr;  | 
    ||
205  | 
    |||
206  | 
    ✓✗✗✓ | 
    82  | 
    	if (((envstr = getenv("CVSEDITOR")) != NULL) || | 
    
207  | 
    ✓✗ | 41  | 
    	    ((envstr = getenv("VISUAL")) != NULL) || | 
    
208  | 
    41  | 
    	    ((envstr = getenv("EDITOR")) != NULL)) | 
    |
209  | 
    cvs_editor = envstr;  | 
    ||
210  | 
    |||
211  | 
    ✗✓ | 41  | 
    	if ((envstr = getenv("CVSREAD")) != NULL) | 
    
212  | 
    cvs_readonly = 1;  | 
    ||
213  | 
    |||
214  | 
    ✗✓ | 41  | 
    	if ((envstr = getenv("CVSREADONLYFS")) != NULL) { | 
    
215  | 
    cvs_readonlyfs = 1;  | 
    ||
216  | 
    cvs_nolog = 1;  | 
    ||
217  | 
    }  | 
    ||
218  | 
    |||
219  | 
    ✗✓ | 41  | 
    	if ((cvs_homedir = getenv("HOME")) == NULL) { | 
    
220  | 
    if ((pw = getpwuid(getuid())) != NULL)  | 
    ||
221  | 
    cvs_homedir = pw->pw_dir;  | 
    ||
222  | 
    }  | 
    ||
223  | 
    |||
224  | 
    ✗✓ | 41  | 
    	if ((envstr = getenv("TMPDIR")) != NULL) | 
    
225  | 
    cvs_tmpdir = envstr;  | 
    ||
226  | 
    |||
227  | 
    41  | 
    ret = cvs_getopt(argc, argv);  | 
    |
228  | 
    |||
229  | 
    41  | 
    argc -= ret;  | 
    |
230  | 
    41  | 
    argv += ret;  | 
    |
231  | 
    ✗✓ | 41  | 
    if (argc == 0)  | 
    
232  | 
    usage();  | 
    ||
233  | 
    |||
234  | 
    41  | 
    cmdp = cvs_findcmd(argv[0]);  | 
    |
235  | 
    ✗✓ | 41  | 
    	if (cmdp == NULL) { | 
    
236  | 
    fprintf(stderr, "Unknown command: `%s'\n\n", argv[0]);  | 
    ||
237  | 
    fprintf(stderr, "CVS commands are:\n");  | 
    ||
238  | 
    for (i = 0; cvs_cdt[i] != NULL; i++)  | 
    ||
239  | 
    fprintf(stderr, "\t%-16s%s\n",  | 
    ||
240  | 
    cvs_cdt[i]->cmd_name, cvs_cdt[i]->cmd_descr);  | 
    ||
241  | 
    exit(1);  | 
    ||
242  | 
    }  | 
    ||
243  | 
    |||
244  | 
    /*  | 
    ||
245  | 
    * check the tmp dir, either specified through  | 
    ||
246  | 
    * the environment variable TMPDIR, or via  | 
    ||
247  | 
    * the global option -T <dir>  | 
    ||
248  | 
    */  | 
    ||
249  | 
    ✗✓ | 41  | 
    if (stat(cvs_tmpdir, &st) == -1)  | 
    
250  | 
    		fatal("stat failed on `%s': %s", cvs_tmpdir, strerror(errno)); | 
    ||
251  | 
    ✗✓ | 41  | 
    else if (!S_ISDIR(st.st_mode))  | 
    
252  | 
    		fatal("`%s' is not valid temporary directory", cvs_tmpdir); | 
    ||
253  | 
    |||
254  | 
    ✗✓ | 41  | 
    	if (cvs_readrc == 1 && cvs_homedir != NULL) { | 
    
255  | 
    cvs_read_rcfile();  | 
    ||
256  | 
    |||
257  | 
    		if (cvs_defargs != NULL) { | 
    ||
258  | 
    if ((targv = cvs_makeargv(cvs_defargs, &i)) == NULL)  | 
    ||
259  | 
    				fatal("failed to load default arguments to %s", | 
    ||
260  | 
    __progname);  | 
    ||
261  | 
    |||
262  | 
    cvs_getopt(i, targv);  | 
    ||
263  | 
    cvs_freeargv(targv, i);  | 
    ||
264  | 
    free(targv);  | 
    ||
265  | 
    }  | 
    ||
266  | 
    }  | 
    ||
267  | 
    |||
268  | 
    /* setup signal handlers */  | 
    ||
269  | 
    41  | 
    signal(SIGTERM, sighandler);  | 
    |
270  | 
    41  | 
    signal(SIGINT, sighandler);  | 
    |
271  | 
    41  | 
    signal(SIGHUP, sighandler);  | 
    |
272  | 
    41  | 
    signal(SIGABRT, sighandler);  | 
    |
273  | 
    41  | 
    signal(SIGALRM, sighandler);  | 
    |
274  | 
    41  | 
    signal(SIGPIPE, sighandler);  | 
    |
275  | 
    |||
276  | 
    41  | 
    cvs_cmdop = cmdp->cmd_op;  | 
    |
277  | 
    |||
278  | 
    41  | 
    cmd_argc = cvs_build_cmd(&cmd_argv, argv, argc);  | 
    |
279  | 
    |||
280  | 
    41  | 
    cvs_file_init();  | 
    |
281  | 
    |||
282  | 
    ✗✓ | 41  | 
    	if (cvs_cmdop == CVS_OP_SERVER) { | 
    
283  | 
    cmdp->cmd(cmd_argc, cmd_argv);  | 
    ||
284  | 
    cvs_cleanup();  | 
    ||
285  | 
    return (0);  | 
    ||
286  | 
    }  | 
    ||
287  | 
    |||
288  | 
    41  | 
    cvs_umask = umask(0);  | 
    |
289  | 
    41  | 
    umask(cvs_umask);  | 
    |
290  | 
    |||
291  | 
    ✗✓ | 41  | 
    	if ((current_cvsroot = cvsroot_get(".")) == NULL) { | 
    
292  | 
    cvs_log(LP_ERR,  | 
    ||
293  | 
    "No CVSROOT specified! Please use the '-d' option");  | 
    ||
294  | 
    		fatal("or set the CVSROOT environment variable."); | 
    ||
295  | 
    }  | 
    ||
296  | 
    |||
297  | 
    ✗✓ | 41  | 
    	if (cvsroot_is_remote()) { | 
    
298  | 
    cmdp->cmd(cmd_argc, cmd_argv);  | 
    ||
299  | 
    cvs_cleanup();  | 
    ||
300  | 
    return (0);  | 
    ||
301  | 
    }  | 
    ||
302  | 
    |||
303  | 
    82  | 
    (void)xsnprintf(fpath, sizeof(fpath), "%s/%s",  | 
    |
304  | 
    41  | 
    current_cvsroot->cr_dir, CVS_PATH_ROOT);  | 
    |
305  | 
    |||
306  | 
    ✗✓ | 41  | 
    	if (stat(fpath, &st) == -1 && cvs_cmdop != CVS_OP_INIT) { | 
    
307  | 
    if (errno == ENOENT)  | 
    ||
308  | 
    			fatal("repository '%s' does not exist", | 
    ||
309  | 
    current_cvsroot->cr_dir);  | 
    ||
310  | 
    else  | 
    ||
311  | 
    			fatal("%s: %s", current_cvsroot->cr_dir, | 
    ||
312  | 
    strerror(errno));  | 
    ||
313  | 
    	} else { | 
    ||
314  | 
    ✗✓ | 41  | 
    if (!S_ISDIR(st.st_mode))  | 
    
315  | 
    			fatal("'%s' is not a directory", | 
    ||
316  | 
    current_cvsroot->cr_dir);  | 
    ||
317  | 
    }  | 
    ||
318  | 
    |||
319  | 
    ✓✓ | 41  | 
    	if (cvs_cmdop != CVS_OP_INIT) { | 
    
320  | 
    40  | 
    cvs_parse_configfile();  | 
    |
321  | 
    40  | 
    cvs_parse_modules();  | 
    |
322  | 
    40  | 
    }  | 
    |
323  | 
    |||
324  | 
    41  | 
    cmdp->cmd(cmd_argc, cmd_argv);  | 
    |
325  | 
    41  | 
    cvs_cleanup();  | 
    |
326  | 
    |||
327  | 
    41  | 
    return (0);  | 
    |
328  | 
    40  | 
    }  | 
    |
329  | 
    |||
330  | 
    int  | 
    ||
331  | 
    cvs_getopt(int argc, char **argv)  | 
    ||
332  | 
    { | 
    ||
333  | 
    int ret;  | 
    ||
334  | 
    char *ep;  | 
    ||
335  | 
    82  | 
    const char *errstr;  | 
    |
336  | 
    |||
337  | 
    ✓✓ | 178  | 
    	while ((ret = getopt(argc, argv, "b:d:e:flnQqRrs:T:tvwxz:")) != -1) { | 
    
338  | 
    ✓✗✓✗ ✓✗✗✓ ✓✗✗✗ ✗✗✗✗ ✗✗  | 
    192  | 
    		switch (ret) { | 
    
339  | 
    case 'b':  | 
    ||
340  | 
    /*  | 
    ||
341  | 
    * We do not care about the bin directory for RCS files  | 
    ||
342  | 
    * as this program has no dependencies on RCS programs,  | 
    ||
343  | 
    * so it is only here for backwards compatibility.  | 
    ||
344  | 
    */  | 
    ||
345  | 
    cvs_log(LP_NOTICE, "the -b argument is obsolete");  | 
    ||
346  | 
    break;  | 
    ||
347  | 
    case 'd':  | 
    ||
348  | 
    17  | 
    cvs_rootstr = optarg;  | 
    |
349  | 
    17  | 
    break;  | 
    |
350  | 
    case 'e':  | 
    ||
351  | 
    cvs_editor = optarg;  | 
    ||
352  | 
    break;  | 
    ||
353  | 
    case 'f':  | 
    ||
354  | 
    41  | 
    cvs_readrc = 0;  | 
    |
355  | 
    41  | 
    break;  | 
    |
356  | 
    case 'l':  | 
    ||
357  | 
    cvs_nolog = 1;  | 
    ||
358  | 
    break;  | 
    ||
359  | 
    case 'n':  | 
    ||
360  | 
    cvs_noexec = 1;  | 
    ||
361  | 
    cvs_nolog = 1;  | 
    ||
362  | 
    break;  | 
    ||
363  | 
    case 'Q':  | 
    ||
364  | 
    35  | 
    verbosity = 0;  | 
    |
365  | 
    35  | 
    break;  | 
    |
366  | 
    case 'q':  | 
    ||
367  | 
    ✗✓ | 3  | 
    if (verbosity > 1)  | 
    
368  | 
    3  | 
    verbosity = 1;  | 
    |
369  | 
    break;  | 
    ||
370  | 
    case 'R':  | 
    ||
371  | 
    cvs_readonlyfs = 1;  | 
    ||
372  | 
    cvs_nolog = 1;  | 
    ||
373  | 
    break;  | 
    ||
374  | 
    case 'r':  | 
    ||
375  | 
    cvs_readonly = 1;  | 
    ||
376  | 
    break;  | 
    ||
377  | 
    case 's':  | 
    ||
378  | 
    ep = strchr(optarg, '=');  | 
    ||
379  | 
    			if (ep == NULL) { | 
    ||
380  | 
    cvs_log(LP_ERR, "no = in variable assignment");  | 
    ||
381  | 
    exit(1);  | 
    ||
382  | 
    }  | 
    ||
383  | 
    *(ep++) = '\0';  | 
    ||
384  | 
    if (cvs_var_set(optarg, ep) < 0)  | 
    ||
385  | 
    exit(1);  | 
    ||
386  | 
    break;  | 
    ||
387  | 
    case 'T':  | 
    ||
388  | 
    cvs_tmpdir = optarg;  | 
    ||
389  | 
    break;  | 
    ||
390  | 
    case 't':  | 
    ||
391  | 
    cvs_trace = 1;  | 
    ||
392  | 
    break;  | 
    ||
393  | 
    case 'v':  | 
    ||
394  | 
    			printf("%s\n", CVS_VERSION); | 
    ||
395  | 
    exit(0);  | 
    ||
396  | 
    /* NOTREACHED */  | 
    ||
397  | 
    case 'w':  | 
    ||
398  | 
    cvs_readonly = 0;  | 
    ||
399  | 
    break;  | 
    ||
400  | 
    case 'x':  | 
    ||
401  | 
    /*  | 
    ||
402  | 
    * Kerberos encryption support, kept for compatibility  | 
    ||
403  | 
    */  | 
    ||
404  | 
    break;  | 
    ||
405  | 
    case 'z':  | 
    ||
406  | 
    cvs_compress = strtonum(optarg, 0, 9, &errstr);  | 
    ||
407  | 
    if (errstr != NULL)  | 
    ||
408  | 
    				fatal("cvs_compress: %s", errstr); | 
    ||
409  | 
    break;  | 
    ||
410  | 
    default:  | 
    ||
411  | 
    usage();  | 
    ||
412  | 
    /* NOTREACHED */  | 
    ||
413  | 
    }  | 
    ||
414  | 
    }  | 
    ||
415  | 
    |||
416  | 
    41  | 
    ret = optind;  | 
    |
417  | 
    41  | 
    optind = 1;  | 
    |
418  | 
    41  | 
    optreset = 1; /* for next call */  | 
    |
419  | 
    |||
420  | 
    41  | 
    return (ret);  | 
    |
421  | 
    41  | 
    }  | 
    |
422  | 
    |||
423  | 
    /*  | 
    ||
424  | 
    * cvs_read_rcfile()  | 
    ||
425  | 
    *  | 
    ||
426  | 
    * Read the CVS `.cvsrc' file in the user's home directory. If the file  | 
    ||
427  | 
    * exists, it should contain a list of arguments that should always be given  | 
    ||
428  | 
    * implicitly to the specified commands.  | 
    ||
429  | 
    */  | 
    ||
430  | 
    static void  | 
    ||
431  | 
    cvs_read_rcfile(void)  | 
    ||
432  | 
    { | 
    ||
433  | 
    char rcpath[PATH_MAX], *buf, *lbuf, *lp, *p;  | 
    ||
434  | 
    int cmd_parsed, cvs_parsed, i, linenum;  | 
    ||
435  | 
    size_t len, pos;  | 
    ||
436  | 
    struct cvs_cmd *tcmdp;  | 
    ||
437  | 
    FILE *fp;  | 
    ||
438  | 
    |||
439  | 
    linenum = 0;  | 
    ||
440  | 
    |||
441  | 
    i = snprintf(rcpath, PATH_MAX, "%s/%s", cvs_homedir, CVS_PATH_RC);  | 
    ||
442  | 
    	if (i < 0 || i >= PATH_MAX) { | 
    ||
443  | 
    cvs_log(LP_ERRNO, "%s", rcpath);  | 
    ||
444  | 
    return;  | 
    ||
445  | 
    }  | 
    ||
446  | 
    |||
447  | 
    fp = fopen(rcpath, "r");  | 
    ||
448  | 
    	if (fp == NULL) { | 
    ||
449  | 
    if (errno != ENOENT)  | 
    ||
450  | 
    cvs_log(LP_NOTICE, "failed to open `%s': %s", rcpath,  | 
    ||
451  | 
    strerror(errno));  | 
    ||
452  | 
    return;  | 
    ||
453  | 
    }  | 
    ||
454  | 
    |||
455  | 
    cmd_parsed = cvs_parsed = 0;  | 
    ||
456  | 
    lbuf = NULL;  | 
    ||
457  | 
    	while ((buf = fgetln(fp, &len)) != NULL) { | 
    ||
458  | 
    		if (buf[len - 1] == '\n') { | 
    ||
459  | 
    buf[len - 1] = '\0';  | 
    ||
460  | 
    		} else { | 
    ||
461  | 
    lbuf = xmalloc(len + 1);  | 
    ||
462  | 
    memcpy(lbuf, buf, len);  | 
    ||
463  | 
    lbuf[len] = '\0';  | 
    ||
464  | 
    buf = lbuf;  | 
    ||
465  | 
    }  | 
    ||
466  | 
    |||
467  | 
    linenum++;  | 
    ||
468  | 
    |||
469  | 
    /* skip any whitespaces */  | 
    ||
470  | 
    p = buf;  | 
    ||
471  | 
    while (*p == ' ')  | 
    ||
472  | 
    p++;  | 
    ||
473  | 
    |||
474  | 
    /*  | 
    ||
475  | 
    * Allow comments.  | 
    ||
476  | 
    * GNU cvs stops parsing a line if it encounters a \t  | 
    ||
477  | 
    * in front of a command, stick at this behaviour for  | 
    ||
478  | 
    * compatibility.  | 
    ||
479  | 
    */  | 
    ||
480  | 
    if (*p == '#' || *p == '\t')  | 
    ||
481  | 
    continue;  | 
    ||
482  | 
    |||
483  | 
    pos = strcspn(p, " \t");  | 
    ||
484  | 
    		if (pos == strlen(p)) { | 
    ||
485  | 
    lp = NULL;  | 
    ||
486  | 
    		} else { | 
    ||
487  | 
    lp = p + pos;  | 
    ||
488  | 
    *lp = '\0';  | 
    ||
489  | 
    }  | 
    ||
490  | 
    |||
491  | 
    		if (strcmp(p, "cvs") == 0 && !cvs_parsed) { | 
    ||
492  | 
    /*  | 
    ||
493  | 
    * Global default options. In the case of cvs only,  | 
    ||
494  | 
    * we keep the 'cvs' string as first argument because  | 
    ||
495  | 
    * getopt() does not like starting at index 0 for  | 
    ||
496  | 
    * argument processing.  | 
    ||
497  | 
    */  | 
    ||
498  | 
    			if (lp != NULL) { | 
    ||
499  | 
    *lp = ' ';  | 
    ||
500  | 
    cvs_defargs = xstrdup(p);  | 
    ||
501  | 
    }  | 
    ||
502  | 
    cvs_parsed = 1;  | 
    ||
503  | 
    		} else { | 
    ||
504  | 
    tcmdp = cvs_findcmd(p);  | 
    ||
505  | 
    if (tcmdp == NULL && verbosity == 2)  | 
    ||
506  | 
    cvs_log(LP_NOTICE,  | 
    ||
507  | 
    "unknown command `%s' in `%s:%d'",  | 
    ||
508  | 
    p, rcpath, linenum);  | 
    ||
509  | 
    |||
510  | 
    if (tcmdp != cmdp || cmd_parsed)  | 
    ||
511  | 
    continue;  | 
    ||
512  | 
    |||
513  | 
    			if (lp != NULL) { | 
    ||
514  | 
    lp++;  | 
    ||
515  | 
    cmdp->cmd_defargs = xstrdup(lp);  | 
    ||
516  | 
    }  | 
    ||
517  | 
    cmd_parsed = 1;  | 
    ||
518  | 
    }  | 
    ||
519  | 
    }  | 
    ||
520  | 
    free(lbuf);  | 
    ||
521  | 
    |||
522  | 
    	if (ferror(fp)) { | 
    ||
523  | 
    cvs_log(LP_NOTICE, "failed to read line from `%s'", rcpath);  | 
    ||
524  | 
    }  | 
    ||
525  | 
    |||
526  | 
    (void)fclose(fp);  | 
    ||
527  | 
    }  | 
    ||
528  | 
    |||
529  | 
    /*  | 
    ||
530  | 
    * cvs_var_set()  | 
    ||
531  | 
    *  | 
    ||
532  | 
    * Set the value of the variable <var> to <val>. If there is no such variable,  | 
    ||
533  | 
    * a new entry is created, otherwise the old value is overwritten.  | 
    ||
534  | 
    * Returns 0 on success, or -1 on failure.  | 
    ||
535  | 
    */  | 
    ||
536  | 
    int  | 
    ||
537  | 
    cvs_var_set(const char *var, const char *val)  | 
    ||
538  | 
    { | 
    ||
539  | 
    const char *cp;  | 
    ||
540  | 
    struct cvs_var *vp;  | 
    ||
541  | 
    |||
542  | 
    	if (var == NULL || *var == '\0') { | 
    ||
543  | 
    cvs_log(LP_ERR, "no variable name");  | 
    ||
544  | 
    return (-1);  | 
    ||
545  | 
    }  | 
    ||
546  | 
    |||
547  | 
    /* sanity check on the name */  | 
    ||
548  | 
    for (cp = var; *cp != '\0'; cp++)  | 
    ||
549  | 
    		if (!isalnum((unsigned char)*cp) && (*cp != '_')) { | 
    ||
550  | 
    cvs_log(LP_ERR,  | 
    ||
551  | 
    "variable name `%s' contains invalid characters",  | 
    ||
552  | 
    var);  | 
    ||
553  | 
    return (-1);  | 
    ||
554  | 
    }  | 
    ||
555  | 
    |||
556  | 
    TAILQ_FOREACH(vp, &cvs_variables, cv_link)  | 
    ||
557  | 
    if (strcmp(vp->cv_name, var) == 0)  | 
    ||
558  | 
    break;  | 
    ||
559  | 
    |||
560  | 
    	if (vp == NULL) { | 
    ||
561  | 
    vp = xcalloc(1, sizeof(*vp));  | 
    ||
562  | 
    |||
563  | 
    vp->cv_name = xstrdup(var);  | 
    ||
564  | 
    TAILQ_INSERT_TAIL(&cvs_variables, vp, cv_link);  | 
    ||
565  | 
    |||
566  | 
    } else /* free the previous value */  | 
    ||
567  | 
    free(vp->cv_val);  | 
    ||
568  | 
    |||
569  | 
    vp->cv_val = xstrdup(val);  | 
    ||
570  | 
    |||
571  | 
    return (0);  | 
    ||
572  | 
    }  | 
    ||
573  | 
    |||
574  | 
    /*  | 
    ||
575  | 
    * cvs_var_unset()  | 
    ||
576  | 
    *  | 
    ||
577  | 
    * Remove any entry for the variable <var>.  | 
    ||
578  | 
    * Returns 0 on success, or -1 on failure.  | 
    ||
579  | 
    */  | 
    ||
580  | 
    int  | 
    ||
581  | 
    cvs_var_unset(const char *var)  | 
    ||
582  | 
    { | 
    ||
583  | 
    struct cvs_var *vp;  | 
    ||
584  | 
    |||
585  | 
    TAILQ_FOREACH(vp, &cvs_variables, cv_link)  | 
    ||
586  | 
    		if (strcmp(vp->cv_name, var) == 0) { | 
    ||
587  | 
    TAILQ_REMOVE(&cvs_variables, vp, cv_link);  | 
    ||
588  | 
    free(vp->cv_name);  | 
    ||
589  | 
    free(vp->cv_val);  | 
    ||
590  | 
    free(vp);  | 
    ||
591  | 
    return (0);  | 
    ||
592  | 
    }  | 
    ||
593  | 
    |||
594  | 
    return (-1);  | 
    ||
595  | 
    }  | 
    ||
596  | 
    |||
597  | 
    /*  | 
    ||
598  | 
    * cvs_var_get()  | 
    ||
599  | 
    *  | 
    ||
600  | 
    * Get the value associated with the variable <var>. Returns a pointer to the  | 
    ||
601  | 
    * value string on success, or NULL if the variable does not exist.  | 
    ||
602  | 
    */  | 
    ||
603  | 
    |||
604  | 
    const char *  | 
    ||
605  | 
    cvs_var_get(const char *var)  | 
    ||
606  | 
    { | 
    ||
607  | 
    struct cvs_var *vp;  | 
    ||
608  | 
    |||
609  | 
    TAILQ_FOREACH(vp, &cvs_variables, cv_link)  | 
    ||
610  | 
    if (strcmp(vp->cv_name, var) == 0)  | 
    ||
611  | 
    return (vp->cv_val);  | 
    ||
612  | 
    |||
613  | 
    return (NULL);  | 
    ||
614  | 
    }  | 
    
| Generated by: GCOVR (Version 3.3) |