[BACK]Return to req.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/req.c, Revision 1.14

1.14    ! joris       1: /*     $OpenBSD: req.c,v 1.13 2005/04/18 21:33:34 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 *);
1.13      jfb        65: static int  cvs_req_entry        (int, char *);
                     66: static int  cvs_req_filestate    (int, char *);
1.11      jfb        67:
                     68: static int  cvs_req_command      (int, char *);
1.1       jfb        69:
                     70:
                     71: struct cvs_reqhdlr {
                     72:        int (*hdlr)(int, char *);
                     73: } cvs_req_swtab[CVS_REQ_MAX + 1] = {
1.11      jfb        74:        { NULL                  },
                     75:        { cvs_req_root          },
                     76:        { cvs_req_validreq      },
                     77:        { cvs_req_validresp     },
                     78:        { cvs_req_directory     },
                     79:        { NULL                  },
                     80:        { NULL                  },
                     81:        { NULL                  },
1.13      jfb        82:        { cvs_req_entry         },
1.11      jfb        83:        { NULL                  },
                     84:        { NULL                  },      /* 10 */
1.13      jfb        85:        { cvs_req_filestate     },
                     86:        { cvs_req_filestate     },
                     87:        { cvs_req_filestate     },
1.11      jfb        88:        { cvs_req_useunchanged  },
                     89:        { NULL                  },
                     90:        { NULL                  },
1.13      jfb        91:        { cvs_req_filestate     },
1.11      jfb        92:        { cvs_req_case          },
                     93:        { NULL                  },
                     94:        { cvs_req_argument      },      /* 20 */
                     95:        { cvs_req_argument      },
                     96:        { cvs_req_globalopt     },
                     97:        { cvs_req_gzipstream    },
                     98:        { NULL                  },
                     99:        { NULL                  },
                    100:        { NULL                  },
                    101:        { NULL                  },
                    102:        { NULL                  },
                    103:        { NULL                  },
                    104:        { NULL                  },      /* 30 */
                    105:        { NULL                  },
                    106:        { NULL                  },
                    107:        { NULL                  },
                    108:        { cvs_req_set           },
1.12      jfb       109:        { cvs_req_expandmod     },
1.11      jfb       110:        { cvs_req_command       },
                    111:        { NULL                  },
                    112:        { NULL                  },
                    113:        { NULL                  },
                    114:        { NULL                  },      /* 40 */
                    115:        { NULL                  },
                    116:        { NULL                  },
                    117:        { NULL                  },
                    118:        { NULL                  },
                    119:        { NULL                  },
                    120:        { cvs_req_command       },
                    121:        { NULL                  },
                    122:        { cvs_req_command       },
                    123:        { NULL                  },
                    124:        { NULL                  },      /* 50 */
                    125:        { NULL                  },
                    126:        { NULL                  },
                    127:        { NULL                  },
                    128:        { cvs_req_command       },
                    129:        { cvs_req_command       },
                    130:        { cvs_req_command       },
                    131:        { NULL                  },
                    132:        { NULL                  },
                    133:        { NULL                  },
                    134:        { cvs_req_command       },      /* 60 */
                    135:        { NULL                  },
                    136:        { cvs_req_command       },
                    137:        { cvs_req_command       },
1.12      jfb       138:        { cvs_req_noop          },
1.11      jfb       139:        { NULL                  },
                    140:        { NULL                  },
                    141:        { NULL                  },
                    142:        { NULL                  },
                    143:        { cvs_req_command       },
1.1       jfb       144: };
                    145:
                    146:
                    147:
                    148: /*
1.2       jfb       149:  * Argument array built by `Argument' and `Argumentx' requests.
                    150:  */
                    151:
1.11      jfb       152: static char *cvs_req_rootpath;
1.14    ! joris     153: static char *cvs_req_currentdir;
        !           154: static char *cvs_req_repopath;
        !           155: static char cvs_req_tmppath[MAXPATHLEN];
1.11      jfb       156:
1.14    ! joris     157: extern char cvs_server_tmpdir[MAXPATHLEN];
1.2       jfb       158: static char *cvs_req_args[CVS_PROTO_MAXARG];
                    159: static int   cvs_req_nargs = 0;
                    160:
                    161:
                    162: /*
1.1       jfb       163:  * cvs_req_handle()
                    164:  *
                    165:  * Generic request handler dispatcher.  The handler expects the first line
                    166:  * of the command as single argument.
                    167:  * Returns the return value of the command on success, or -1 on failure.
                    168:  */
                    169: int
                    170: cvs_req_handle(char *line)
                    171: {
                    172:        char *cp, *cmd;
                    173:        struct cvs_req *req;
                    174:
                    175:        cmd = line;
                    176:
                    177:        cp = strchr(cmd, ' ');
                    178:        if (cp != NULL)
                    179:                *(cp++) = '\0';
                    180:
                    181:        req = cvs_req_getbyname(cmd);
                    182:        if (req == NULL)
                    183:                return (-1);
                    184:        else if (cvs_req_swtab[req->req_id].hdlr == NULL) {
1.10      jfb       185:                cvs_log(LP_ERR, "handler for `%s' not implemented", cmd);
1.1       jfb       186:                return (-1);
                    187:        }
                    188:
                    189:        return (*cvs_req_swtab[req->req_id].hdlr)(req->req_id, cp);
                    190: }
                    191:
1.12      jfb       192: /*
                    193:  * cvs_req_noop()
                    194:  */
                    195: static int
                    196: cvs_req_noop(int reqid, char *line)
                    197: {
                    198:        int ret;
                    199:
                    200:        ret = cvs_sendresp(CVS_RESP_OK, NULL);
                    201:        if (ret < 0)
                    202:                return (-1);
                    203:        return (0);
                    204: }
                    205:
1.1       jfb       206:
                    207: static int
                    208: cvs_req_root(int reqid, char *line)
                    209: {
1.11      jfb       210:        if (cvs_req_rootpath != NULL) {
                    211:                cvs_log(LP_ERR, "duplicate Root request received");
1.13      jfb       212:                cvs_printf("Protocol error: Duplicate Root request");
1.11      jfb       213:                return (-1);
                    214:        }
1.9       jfb       215:
1.11      jfb       216:        cvs_req_rootpath = strdup(line);
                    217:        if (cvs_req_rootpath == NULL) {
                    218:                cvs_log(LP_ERRNO, "failed to copy Root path");
1.9       jfb       219:                return (-1);
                    220:        }
                    221:
1.4       jfb       222:        return (0);
                    223: }
                    224:
                    225:
                    226: static int
                    227: cvs_req_validreq(int reqid, char *line)
                    228: {
                    229:        char *vreq;
                    230:
                    231:        vreq = cvs_req_getvalid();
                    232:        if (vreq == NULL)
                    233:                return (-1);
                    234:
1.11      jfb       235:        if ((cvs_sendresp(CVS_RESP_VALIDREQ, vreq) < 0) ||
                    236:            (cvs_sendresp(CVS_RESP_OK, NULL) < 0))
                    237:                return (-1);
1.4       jfb       238:
                    239:        return (0);
                    240: }
                    241:
                    242: static int
                    243: cvs_req_validresp(int reqid, char *line)
                    244: {
                    245:        char *sp, *ep;
                    246:        struct cvs_resp *resp;
1.1       jfb       247:
1.4       jfb       248:        sp = line;
                    249:        do {
                    250:                ep = strchr(sp, ' ');
                    251:                if (ep != NULL)
                    252:                        *(ep++) = '\0';
                    253:
                    254:                resp = cvs_resp_getbyname(sp);
                    255:                if (resp != NULL)
                    256:                        ;
                    257:
                    258:                if (ep != NULL)
                    259:                        sp = ep + 1;
                    260:        } while (ep != NULL);
1.1       jfb       261:
                    262:        return (0);
                    263: }
                    264:
                    265: static int
                    266: cvs_req_directory(int reqid, char *line)
                    267: {
1.14    ! joris     268:        int l;
1.11      jfb       269:        char rdir[MAXPATHLEN];
1.1       jfb       270:
1.11      jfb       271:        if (cvs_getln(NULL, rdir, sizeof(rdir)) < 0)
                    272:                return (-1);
                    273:
1.14    ! joris     274:        if (cvs_req_currentdir != NULL)
        !           275:                free(cvs_req_currentdir);
        !           276:
        !           277:        cvs_req_currentdir = strdup(rdir);
        !           278:        if (cvs_req_currentdir == NULL) {
        !           279:                cvs_log(LP_ERROR, "failed to duplicate directory");
        !           280:                return (-1);
        !           281:        }
        !           282:
        !           283:        /* now obtain the path relative to the Root directory */
        !           284:        cvs_req_repopath = cvs_req_currentdir + strlen(cvs_req_rootpath) + 1;
        !           285:
        !           286:        /* create tmp path */
        !           287:        l = snprintf(cvs_req_tmppath, sizeof(cvs_req_tmppath), "%s/%s",
        !           288:            cvs_server_tmpdir, cvs_req_repopath);
        !           289:        if (l == -1 || l >= (int)sizeof(cvs_req_tmppath)) {
        !           290:                errno = ENAMETOOLONG;
        !           291:                cvs_log(LP_ERRNO, "%s", cvs_req_tmppath);
        !           292:                return (-1);
        !           293:        }
        !           294:
        !           295:        if ((mkdir(cvs_req_tmppath, 0755) == -1) && (errno != EEXIST)) {
        !           296:                cvs_log(LP_ERRNO, "failed to create temporary directory '%s'",
        !           297:                    cvs_req_tmppath);
        !           298:                return (-1);
        !           299:        }
        !           300:
        !           301:        /* create the CVS/ administrative files */
        !           302:        /* XXX - TODO */
        !           303:
1.11      jfb       304:        return (0);
                    305: }
                    306:
1.13      jfb       307: static int
                    308: cvs_req_entry(int reqid, char *line)
                    309: {
                    310:        struct cvs_ent *ent;
                    311:
                    312:        if ((ent = cvs_ent_parse(line)) == NULL)
                    313:                return (-1);
                    314:
                    315:        return (0);
                    316: }
                    317:
                    318: /*
                    319:  * cvs_req_filestate()
                    320:  *
                    321:  * Handler for the `Modified', `Is-Modified', `Unchanged' and `Questionable'
                    322:  * requests, which are all used to report the assumed state of a file from the
                    323:  * client.
                    324:  */
                    325: static int
                    326: cvs_req_filestate(int reqid, char *line)
                    327: {
1.14    ! joris     328:        int l;
1.13      jfb       329:        mode_t fmode;
                    330:        BUF *fdata;
1.14    ! joris     331:        char fpath[MAXPATHLEN];
1.13      jfb       332:
                    333:        if (reqid == CVS_REQ_MODIFIED) {
                    334:                fdata = cvs_recvfile(NULL, &fmode);
                    335:                if (fdata == NULL)
                    336:                        return (-1);
1.14    ! joris     337:
        !           338:                /* create full temporary path */
        !           339:                l = snprintf(fpath, sizeof(fpath), "%s/%s", cvs_req_tmppath,
        !           340:                    line);
        !           341:                if (l == -1 || l >= (int)sizeof(fpath)) {
        !           342:                        errno = ENAMETOOLONG;
        !           343:                        cvs_log(LP_ERRNO, "%s", fpath);
        !           344:                        cvs_buf_free(fdata);
        !           345:                        return (-1);
        !           346:                }
        !           347:
        !           348:                /* write the file */
        !           349:                if (cvs_buf_write(fdata, fpath, fmode) < 0) {
        !           350:                        cvs_log(LP_ERROR, "failed to create file %s", fpath);
        !           351:                        cvs_buf_free(fdata);
        !           352:                        return (-1);
        !           353:                }
        !           354:
        !           355:                cvs_buf_free(fdata);
1.13      jfb       356:        }
                    357:
                    358:        return (0);
                    359: }
1.12      jfb       360:
                    361: /*
                    362:  * cvs_req_expandmod()
                    363:  *
                    364:  */
                    365: static int
                    366: cvs_req_expandmod(int reqid, char *line)
                    367: {
                    368:        int ret;
                    369:
                    370:        ret = cvs_sendresp(CVS_RESP_OK, NULL);
                    371:        if (ret < 0)
                    372:                return (-1);
                    373:        return (0);
                    374: }
                    375:
                    376:
1.11      jfb       377: /*
                    378:  * cvs_req_useunchanged()
                    379:  *
                    380:  * Handler for the `UseUnchanged' requests.  The protocol documentation
                    381:  * specifies that this request must be supported by the server and must be
                    382:  * sent by the client, though it gives no clue regarding its use.
                    383:  */
                    384: static int
                    385: cvs_req_useunchanged(int reqid, char *line)
                    386: {
1.5       jfb       387:        return (0);
                    388: }
                    389:
1.11      jfb       390:
1.5       jfb       391: /*
                    392:  * cvs_req_case()
                    393:  *
                    394:  * Handler for the `Case' requests, which toggles case sensitivity ON or OFF
                    395:  */
                    396: static int
                    397: cvs_req_case(int reqid, char *line)
                    398: {
                    399:        cvs_nocase = 1;
1.2       jfb       400:        return (0);
                    401: }
                    402:
                    403:
                    404: static int
1.11      jfb       405: cvs_req_set(int reqid, char *line)
                    406: {
                    407:        char *cp, *lp;
                    408:
                    409:        if ((lp = strdup(line)) == NULL) {
                    410:                cvs_log(LP_ERRNO, "failed to copy Set argument");
                    411:                return (-1);
                    412:        }
                    413:
                    414:        if ((cp = strchr(lp, '=')) == NULL) {
                    415:                cvs_log(LP_ERR, "error in Set request "
                    416:                    "(no = in variable assignment)");
                    417:                free(lp);
                    418:                return (-1);
                    419:        }
                    420:        *(cp++) = '\0';
                    421:
                    422:        if (cvs_var_set(lp, cp) < 0) {
                    423:                free(lp);
                    424:                return (-1);
                    425:        }
                    426:
                    427:        free(lp);
                    428:
                    429:        return (0);
                    430: }
                    431:
                    432:
                    433: static int
1.2       jfb       434: cvs_req_argument(int reqid, char *line)
                    435: {
                    436:        char *nap;
                    437:
                    438:        if (cvs_req_nargs == CVS_PROTO_MAXARG) {
                    439:                cvs_log(LP_ERR, "too many arguments");
                    440:                return (-1);
                    441:        }
                    442:
                    443:        if (reqid == CVS_REQ_ARGUMENT) {
                    444:                cvs_req_args[cvs_req_nargs] = strdup(line);
                    445:                if (cvs_req_args[cvs_req_nargs] == NULL) {
                    446:                        cvs_log(LP_ERRNO, "failed to copy argument");
                    447:                        return (-1);
                    448:                }
                    449:                cvs_req_nargs++;
1.6       deraadt   450:        } else if (reqid == CVS_REQ_ARGUMENTX) {
1.2       jfb       451:                if (cvs_req_nargs == 0)
                    452:                        cvs_log(LP_WARN, "no argument to append to");
                    453:                else {
                    454:                        asprintf(&nap, "%s%s", cvs_req_args[cvs_req_nargs - 1],
                    455:                            line);
                    456:                        if (nap == NULL) {
                    457:                                cvs_log(LP_ERRNO,
                    458:                                    "failed to append to argument");
                    459:                                return (-1);
                    460:                        }
                    461:                        free(cvs_req_args[cvs_req_nargs - 1]);
                    462:                        cvs_req_args[cvs_req_nargs - 1] = nap;
                    463:                }
1.3       jfb       464:        }
                    465:
                    466:        return (0);
                    467: }
                    468:
                    469:
                    470: static int
                    471: cvs_req_globalopt(int reqid, char *line)
                    472: {
                    473:        if ((*line != '-') || (*(line + 2) != '\0')) {
                    474:                cvs_log(LP_ERR,
                    475:                    "invalid `Global_option' request format");
                    476:                return (-1);
                    477:        }
                    478:
                    479:        switch (*(line + 1)) {
                    480:        case 'l':
                    481:                cvs_nolog = 1;
                    482:                break;
                    483:        case 'n':
                    484:                break;
                    485:        case 'Q':
                    486:                verbosity = 0;
                    487:                break;
                    488:        case 'q':
                    489:                if (verbosity > 1)
                    490:                        verbosity = 1;
                    491:                break;
                    492:        case 'r':
                    493:                cvs_readonly = 1;
                    494:                break;
                    495:        case 't':
                    496:                cvs_trace = 1;
                    497:                break;
                    498:        default:
                    499:                cvs_log(LP_ERR, "unknown global option `%s'", line);
                    500:                return (-1);
1.2       jfb       501:        }
1.8       jfb       502:
                    503:        return (0);
                    504: }
                    505:
                    506:
                    507: /*
                    508:  * cvs_req_gzipstream()
                    509:  *
                    510:  * Handler for the `Gzip-stream' request, which enables compression at the
                    511:  * level given along with the request.  After this request has been processed,
                    512:  * all further connection data should be compressed.
                    513:  */
                    514: static int
                    515: cvs_req_gzipstream(int reqid, char *line)
                    516: {
                    517:        char *ep;
                    518:        long val;
                    519:
                    520:        val = strtol(line, &ep, 10);
                    521:        if ((line[0] == '\0') || (*ep != '\0')) {
                    522:                cvs_log(LP_ERR, "invalid Gzip-stream level `%s'", line);
                    523:                return (-1);
                    524:        } else if ((errno == ERANGE) && ((val < 0) || (val > 9))) {
                    525:                cvs_log(LP_ERR, "Gzip-stream level %ld out of range", val);
                    526:                return (-1);
                    527:        }
                    528:
                    529:        cvs_compress = (int)val;
1.1       jfb       530:
                    531:        return (0);
                    532: }
                    533:
                    534:
1.11      jfb       535: /*
                    536:  * cvs_req_command()
                    537:  *
                    538:  * Generic request handler for CVS command requests (i.e. diff, update, tag).
                    539:  */
1.1       jfb       540: static int
1.11      jfb       541: cvs_req_command(int reqid, char *line)
1.1       jfb       542: {
1.11      jfb       543:        int ret;
                    544:
                    545:        switch (reqid) {
                    546:        case CVS_REQ_VERSION:
                    547:                ret = cvs_sendresp(CVS_RESP_M, CVS_VERSION);
                    548:                break;
                    549:        case CVS_REQ_ADD:
                    550:        case CVS_REQ_ANNOTATE:
1.12      jfb       551:        case CVS_REQ_CO:
1.11      jfb       552:        case CVS_REQ_CI:
                    553:        case CVS_REQ_DIFF:
                    554:        case CVS_REQ_LOG:
                    555:        case CVS_REQ_REMOVE:
                    556:        case CVS_REQ_STATUS:
                    557:        case CVS_REQ_TAG:
                    558:        default:
                    559:                cvs_sendresp(CVS_RESP_E, "command not yet implemented");
                    560:                cvs_sendresp(CVS_RESP_ERROR, NULL);
                    561:                return (0);
                    562:        }
                    563:
                    564:        if (ret == 0)
                    565:                ret = cvs_sendresp(CVS_RESP_OK, NULL);
                    566:
                    567:        return (ret);
1.1       jfb       568: }