Annotation of src/usr.bin/cvs/req.c, Revision 1.12
1.12 ! jfb 1: /* $OpenBSD: req.c,v 1.11 2005/01/13 06:09:14 jfb Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27:
28: #include <sys/types.h>
29: #include <sys/stat.h>
30:
31: #include <fcntl.h>
32: #include <stdio.h>
33: #include <errno.h>
34: #include <stdlib.h>
35: #include <unistd.h>
36: #include <string.h>
37:
38: #include "buf.h"
39: #include "cvs.h"
40: #include "log.h"
41: #include "file.h"
42: #include "proto.h"
43:
44:
45: extern int verbosity;
46: extern int cvs_compress;
47: extern char *cvs_rsh;
48: extern int cvs_trace;
49: extern int cvs_nolog;
50: extern int cvs_readonly;
51:
52:
1.11 jfb 53: static int cvs_req_set (int, char *);
1.12 ! jfb 54: static int cvs_req_noop (int, char *);
1.11 jfb 55: static int cvs_req_root (int, char *);
56: static int cvs_req_validreq (int, char *);
57: static int cvs_req_validresp (int, char *);
1.12 ! jfb 58: static int cvs_req_expandmod (int, char *);
1.11 jfb 59: static int cvs_req_directory (int, char *);
60: static int cvs_req_useunchanged (int, char *);
61: static int cvs_req_case (int, char *);
62: static int cvs_req_argument (int, char *);
63: static int cvs_req_globalopt (int, char *);
64: static int cvs_req_gzipstream (int, char *);
65:
66: static int cvs_req_command (int, char *);
1.1 jfb 67:
68:
69: struct cvs_reqhdlr {
70: int (*hdlr)(int, char *);
71: } cvs_req_swtab[CVS_REQ_MAX + 1] = {
1.11 jfb 72: { NULL },
73: { cvs_req_root },
74: { cvs_req_validreq },
75: { cvs_req_validresp },
76: { cvs_req_directory },
77: { NULL },
78: { NULL },
79: { NULL },
80: { NULL },
81: { NULL },
82: { NULL }, /* 10 */
83: { NULL },
84: { NULL },
85: { NULL },
86: { cvs_req_useunchanged },
87: { NULL },
88: { NULL },
89: { NULL },
90: { cvs_req_case },
91: { NULL },
92: { cvs_req_argument }, /* 20 */
93: { cvs_req_argument },
94: { cvs_req_globalopt },
95: { cvs_req_gzipstream },
96: { NULL },
97: { NULL },
98: { NULL },
99: { NULL },
100: { NULL },
101: { NULL },
102: { NULL }, /* 30 */
103: { NULL },
104: { NULL },
105: { NULL },
106: { cvs_req_set },
1.12 ! jfb 107: { cvs_req_expandmod },
1.11 jfb 108: { cvs_req_command },
109: { NULL },
110: { NULL },
111: { NULL },
112: { NULL }, /* 40 */
113: { NULL },
114: { NULL },
115: { NULL },
116: { NULL },
117: { NULL },
118: { cvs_req_command },
119: { NULL },
120: { cvs_req_command },
121: { NULL },
122: { NULL }, /* 50 */
123: { NULL },
124: { NULL },
125: { NULL },
126: { cvs_req_command },
127: { cvs_req_command },
128: { cvs_req_command },
129: { NULL },
130: { NULL },
131: { NULL },
132: { cvs_req_command }, /* 60 */
133: { NULL },
134: { cvs_req_command },
135: { cvs_req_command },
1.12 ! jfb 136: { cvs_req_noop },
1.11 jfb 137: { NULL },
138: { NULL },
139: { NULL },
140: { NULL },
141: { cvs_req_command },
1.1 jfb 142: };
143:
144:
145:
146: /*
1.2 jfb 147: * Argument array built by `Argument' and `Argumentx' requests.
148: */
149:
1.11 jfb 150: static char *cvs_req_rootpath;
151:
1.2 jfb 152: static char *cvs_req_args[CVS_PROTO_MAXARG];
153: static int cvs_req_nargs = 0;
154:
155:
156: /*
1.1 jfb 157: * cvs_req_handle()
158: *
159: * Generic request handler dispatcher. The handler expects the first line
160: * of the command as single argument.
161: * Returns the return value of the command on success, or -1 on failure.
162: */
163: int
164: cvs_req_handle(char *line)
165: {
166: char *cp, *cmd;
167: struct cvs_req *req;
168:
169: cmd = line;
170:
171: cp = strchr(cmd, ' ');
172: if (cp != NULL)
173: *(cp++) = '\0';
174:
175: req = cvs_req_getbyname(cmd);
176: if (req == NULL)
177: return (-1);
178: else if (cvs_req_swtab[req->req_id].hdlr == NULL) {
1.10 jfb 179: cvs_log(LP_ERR, "handler for `%s' not implemented", cmd);
1.1 jfb 180: return (-1);
181: }
182:
183: return (*cvs_req_swtab[req->req_id].hdlr)(req->req_id, cp);
184: }
185:
1.12 ! jfb 186: /*
! 187: * cvs_req_noop()
! 188: */
! 189: static int
! 190: cvs_req_noop(int reqid, char *line)
! 191: {
! 192: int ret;
! 193:
! 194: ret = cvs_sendresp(CVS_RESP_OK, NULL);
! 195: if (ret < 0)
! 196: return (-1);
! 197: return (0);
! 198: }
! 199:
1.1 jfb 200:
201: static int
202: cvs_req_root(int reqid, char *line)
203: {
1.11 jfb 204: if (cvs_req_rootpath != NULL) {
205: cvs_log(LP_ERR, "duplicate Root request received");
206: return (-1);
207: }
1.9 jfb 208:
1.11 jfb 209: cvs_req_rootpath = strdup(line);
210: if (cvs_req_rootpath == NULL) {
211: cvs_log(LP_ERRNO, "failed to copy Root path");
1.9 jfb 212: return (-1);
213: }
214:
1.4 jfb 215: return (0);
216: }
217:
218:
219: static int
220: cvs_req_validreq(int reqid, char *line)
221: {
222: char *vreq;
223:
224: vreq = cvs_req_getvalid();
225: if (vreq == NULL)
226: return (-1);
227:
1.11 jfb 228: if ((cvs_sendresp(CVS_RESP_VALIDREQ, vreq) < 0) ||
229: (cvs_sendresp(CVS_RESP_OK, NULL) < 0))
230: return (-1);
1.4 jfb 231:
232: return (0);
233: }
234:
235: static int
236: cvs_req_validresp(int reqid, char *line)
237: {
238: char *sp, *ep;
239: struct cvs_resp *resp;
1.1 jfb 240:
1.4 jfb 241: sp = line;
242: do {
243: ep = strchr(sp, ' ');
244: if (ep != NULL)
245: *(ep++) = '\0';
246:
247: resp = cvs_resp_getbyname(sp);
248: if (resp != NULL)
249: ;
250:
251: if (ep != NULL)
252: sp = ep + 1;
253: } while (ep != NULL);
1.1 jfb 254:
255: return (0);
256: }
257:
258: static int
259: cvs_req_directory(int reqid, char *line)
260: {
1.11 jfb 261: char rdir[MAXPATHLEN];
1.1 jfb 262:
1.11 jfb 263: if (cvs_getln(NULL, rdir, sizeof(rdir)) < 0)
264: return (-1);
265:
266: return (0);
267: }
268:
1.12 ! jfb 269:
! 270: /*
! 271: * cvs_req_expandmod()
! 272: *
! 273: */
! 274: static int
! 275: cvs_req_expandmod(int reqid, char *line)
! 276: {
! 277: int ret;
! 278:
! 279: ret = cvs_sendresp(CVS_RESP_OK, NULL);
! 280: if (ret < 0)
! 281: return (-1);
! 282: return (0);
! 283: }
! 284:
! 285:
1.11 jfb 286: /*
287: * cvs_req_useunchanged()
288: *
289: * Handler for the `UseUnchanged' requests. The protocol documentation
290: * specifies that this request must be supported by the server and must be
291: * sent by the client, though it gives no clue regarding its use.
292: */
293: static int
294: cvs_req_useunchanged(int reqid, char *line)
295: {
1.5 jfb 296: return (0);
297: }
298:
1.11 jfb 299:
1.5 jfb 300: /*
301: * cvs_req_case()
302: *
303: * Handler for the `Case' requests, which toggles case sensitivity ON or OFF
304: */
305: static int
306: cvs_req_case(int reqid, char *line)
307: {
308: cvs_nocase = 1;
1.2 jfb 309: return (0);
310: }
311:
312:
313: static int
1.11 jfb 314: cvs_req_set(int reqid, char *line)
315: {
316: char *cp, *lp;
317:
318: if ((lp = strdup(line)) == NULL) {
319: cvs_log(LP_ERRNO, "failed to copy Set argument");
320: return (-1);
321: }
322:
323: if ((cp = strchr(lp, '=')) == NULL) {
324: cvs_log(LP_ERR, "error in Set request "
325: "(no = in variable assignment)");
326: free(lp);
327: return (-1);
328: }
329: *(cp++) = '\0';
330:
331: if (cvs_var_set(lp, cp) < 0) {
332: free(lp);
333: return (-1);
334: }
335:
336: free(lp);
337:
338: return (0);
339: }
340:
341:
342: static int
1.2 jfb 343: cvs_req_argument(int reqid, char *line)
344: {
345: char *nap;
346:
347: if (cvs_req_nargs == CVS_PROTO_MAXARG) {
348: cvs_log(LP_ERR, "too many arguments");
349: return (-1);
350: }
351:
352: if (reqid == CVS_REQ_ARGUMENT) {
353: cvs_req_args[cvs_req_nargs] = strdup(line);
354: if (cvs_req_args[cvs_req_nargs] == NULL) {
355: cvs_log(LP_ERRNO, "failed to copy argument");
356: return (-1);
357: }
358: cvs_req_nargs++;
1.6 deraadt 359: } else if (reqid == CVS_REQ_ARGUMENTX) {
1.2 jfb 360: if (cvs_req_nargs == 0)
361: cvs_log(LP_WARN, "no argument to append to");
362: else {
363: asprintf(&nap, "%s%s", cvs_req_args[cvs_req_nargs - 1],
364: line);
365: if (nap == NULL) {
366: cvs_log(LP_ERRNO,
367: "failed to append to argument");
368: return (-1);
369: }
370: free(cvs_req_args[cvs_req_nargs - 1]);
371: cvs_req_args[cvs_req_nargs - 1] = nap;
372: }
1.3 jfb 373: }
374:
375: return (0);
376: }
377:
378:
379: static int
380: cvs_req_globalopt(int reqid, char *line)
381: {
382: if ((*line != '-') || (*(line + 2) != '\0')) {
383: cvs_log(LP_ERR,
384: "invalid `Global_option' request format");
385: return (-1);
386: }
387:
388: switch (*(line + 1)) {
389: case 'l':
390: cvs_nolog = 1;
391: break;
392: case 'n':
393: break;
394: case 'Q':
395: verbosity = 0;
396: break;
397: case 'q':
398: if (verbosity > 1)
399: verbosity = 1;
400: break;
401: case 'r':
402: cvs_readonly = 1;
403: break;
404: case 't':
405: cvs_trace = 1;
406: break;
407: default:
408: cvs_log(LP_ERR, "unknown global option `%s'", line);
409: return (-1);
1.2 jfb 410: }
1.8 jfb 411:
412: return (0);
413: }
414:
415:
416: /*
417: * cvs_req_gzipstream()
418: *
419: * Handler for the `Gzip-stream' request, which enables compression at the
420: * level given along with the request. After this request has been processed,
421: * all further connection data should be compressed.
422: */
423: static int
424: cvs_req_gzipstream(int reqid, char *line)
425: {
426: char *ep;
427: long val;
428:
429: val = strtol(line, &ep, 10);
430: if ((line[0] == '\0') || (*ep != '\0')) {
431: cvs_log(LP_ERR, "invalid Gzip-stream level `%s'", line);
432: return (-1);
433: } else if ((errno == ERANGE) && ((val < 0) || (val > 9))) {
434: cvs_log(LP_ERR, "Gzip-stream level %ld out of range", val);
435: return (-1);
436: }
437:
438: cvs_compress = (int)val;
1.1 jfb 439:
440: return (0);
441: }
442:
443:
1.11 jfb 444: /*
445: * cvs_req_command()
446: *
447: * Generic request handler for CVS command requests (i.e. diff, update, tag).
448: */
1.1 jfb 449: static int
1.11 jfb 450: cvs_req_command(int reqid, char *line)
1.1 jfb 451: {
1.11 jfb 452: int ret;
453:
454: switch (reqid) {
455: case CVS_REQ_VERSION:
456: ret = cvs_sendresp(CVS_RESP_M, CVS_VERSION);
457: break;
458: case CVS_REQ_ADD:
459: case CVS_REQ_ANNOTATE:
1.12 ! jfb 460: case CVS_REQ_CO:
1.11 jfb 461: case CVS_REQ_CI:
462: case CVS_REQ_DIFF:
463: case CVS_REQ_LOG:
464: case CVS_REQ_REMOVE:
465: case CVS_REQ_STATUS:
466: case CVS_REQ_TAG:
467: default:
468: cvs_sendresp(CVS_RESP_E, "command not yet implemented");
469: cvs_sendresp(CVS_RESP_ERROR, NULL);
470: return (0);
471: }
472:
473: if (ret == 0)
474: ret = cvs_sendresp(CVS_RESP_OK, NULL);
475:
476: return (ret);
1.1 jfb 477: }