1*431378d1Snaddy /* $OpenBSD: server.c,v 1.106 2020/10/19 19:51:20 naddy Exp $ */
29fac60a5Sjoris /*
39fac60a5Sjoris * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
49fac60a5Sjoris *
59fac60a5Sjoris * Permission to use, copy, modify, and distribute this software for any
69fac60a5Sjoris * purpose with or without fee is hereby granted, provided that the above
79fac60a5Sjoris * copyright notice and this permission notice appear in all copies.
89fac60a5Sjoris *
99fac60a5Sjoris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109fac60a5Sjoris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119fac60a5Sjoris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129fac60a5Sjoris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139fac60a5Sjoris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149fac60a5Sjoris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159fac60a5Sjoris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169fac60a5Sjoris */
179fac60a5Sjoris
18d892f828Stobias #include <sys/types.h>
191f8531bdSotto #include <sys/stat.h>
201f8531bdSotto
211f8531bdSotto #include <errno.h>
221f8531bdSotto #include <fcntl.h>
231f8531bdSotto #include <libgen.h>
24b0d19690Stobias #include <stdio.h>
251f8531bdSotto #include <stdlib.h>
261f8531bdSotto #include <string.h>
271f8531bdSotto #include <unistd.h>
289fac60a5Sjoris
299fac60a5Sjoris #include "cvs.h"
309fac60a5Sjoris #include "remote.h"
319fac60a5Sjoris
329fac60a5Sjoris struct cvs_resp cvs_responses[] = {
339fac60a5Sjoris /* this is what our server uses, the client should support it */
349fac60a5Sjoris { "Valid-requests", 1, cvs_client_validreq, RESP_NEEDED },
359fac60a5Sjoris { "ok", 0, cvs_client_ok, RESP_NEEDED},
369fac60a5Sjoris { "error", 0, cvs_client_error, RESP_NEEDED },
379fac60a5Sjoris { "E", 0, cvs_client_e, RESP_NEEDED },
389fac60a5Sjoris { "M", 0, cvs_client_m, RESP_NEEDED },
399fac60a5Sjoris { "Checked-in", 0, cvs_client_checkedin, RESP_NEEDED },
409fac60a5Sjoris { "Updated", 0, cvs_client_updated, RESP_NEEDED },
419fac60a5Sjoris { "Merged", 0, cvs_client_merged, RESP_NEEDED },
429fac60a5Sjoris { "Removed", 0, cvs_client_removed, RESP_NEEDED },
43bbf7e810Sjoris { "Remove-entry", 0, cvs_client_remove_entry, 0 },
44bbf7e810Sjoris { "Set-static-directory", 0,
45bbf7e810Sjoris cvs_client_set_static_directory, 0 },
46bbf7e810Sjoris { "Clear-static-directory", 0,
47bbf7e810Sjoris cvs_client_clear_static_directory, 0 },
48bbf7e810Sjoris { "Set-sticky", 0, cvs_client_set_sticky, 0 },
49bbf7e810Sjoris { "Clear-sticky", 0, cvs_client_clear_sticky, 0 },
509fac60a5Sjoris
519fac60a5Sjoris /* unsupported responses until told otherwise */
529fac60a5Sjoris { "New-entry", 0, NULL, 0 },
539fac60a5Sjoris { "Created", 0, NULL, 0 },
549fac60a5Sjoris { "Update-existing", 0, NULL, 0 },
559fac60a5Sjoris { "Rcs-diff", 0, NULL, 0 },
569fac60a5Sjoris { "Patched", 0, NULL, 0 },
579fac60a5Sjoris { "Mode", 0, NULL, 0 },
589fac60a5Sjoris { "Mod-time", 0, NULL, 0 },
599fac60a5Sjoris { "Checksum", 0, NULL, 0 },
609fac60a5Sjoris { "Copy-file", 0, NULL, 0 },
619fac60a5Sjoris { "Template", 0, NULL, 0 },
629fac60a5Sjoris { "Set-checkin-prog", 0, NULL, 0 },
639fac60a5Sjoris { "Set-update-prog", 0, NULL, 0 },
649fac60a5Sjoris { "Notified", 0, NULL, 0 },
659fac60a5Sjoris { "Module-expansion", 0, NULL, 0 },
669fac60a5Sjoris { "Wrapper-rcsOption", 0, NULL, 0 },
679fac60a5Sjoris { "Mbinary", 0, NULL, 0 },
689fac60a5Sjoris { "F", 0, NULL, 0 },
699fac60a5Sjoris { "MT", 0, NULL, 0 },
709fac60a5Sjoris { "", -1, NULL, 0 }
719fac60a5Sjoris };
729fac60a5Sjoris
739fac60a5Sjoris int cvs_server(int, char **);
749fac60a5Sjoris char *cvs_server_path = NULL;
759fac60a5Sjoris
769fac60a5Sjoris static char *server_currentdir = NULL;
7710283864Stobias static char **server_argv;
789fac60a5Sjoris static int server_argc = 1;
799fac60a5Sjoris
801b5598b0Sjoris extern int disable_fast_checkout;
811b5598b0Sjoris
829fac60a5Sjoris struct cvs_cmd cvs_cmd_server = {
83f331ff59Stobias CVS_OP_SERVER, CVS_USE_WDIR, "server", { "", "" },
849fac60a5Sjoris "server mode",
859fac60a5Sjoris NULL,
869fac60a5Sjoris NULL,
879fac60a5Sjoris NULL,
889fac60a5Sjoris cvs_server
899fac60a5Sjoris };
909fac60a5Sjoris
919fac60a5Sjoris
929fac60a5Sjoris int
cvs_server(int argc,char ** argv)939fac60a5Sjoris cvs_server(int argc, char **argv)
949fac60a5Sjoris {
959fac60a5Sjoris char *cmd, *data;
969fac60a5Sjoris struct cvs_req *req;
979fac60a5Sjoris
98b0d19690Stobias if (argc > 1)
99b0d19690Stobias fatal("server does not take any extra arguments");
100b0d19690Stobias
101a694c629Stobias /* Be on server-side very verbose per default. */
102a694c629Stobias verbosity = 2;
103a694c629Stobias
104b0d19690Stobias setvbuf(stdin, NULL, _IOLBF, 0);
105b0d19690Stobias setvbuf(stdout, NULL, _IOLBF, 0);
106b0d19690Stobias
107b0d19690Stobias cvs_server_active = 1;
108b0d19690Stobias
10910283864Stobias server_argv = xcalloc(server_argc + 1, sizeof(*server_argv));
1109fac60a5Sjoris server_argv[0] = xstrdup("server");
1119fac60a5Sjoris
1129f4abebfSray (void)xasprintf(&cvs_server_path, "%s/cvs-serv%d", cvs_tmpdir,
1139f4abebfSray getpid());
1149fac60a5Sjoris
1159fac60a5Sjoris if (mkdir(cvs_server_path, 0700) == -1)
1169fac60a5Sjoris fatal("failed to create temporary server directory: %s, %s",
1179fac60a5Sjoris cvs_server_path, strerror(errno));
1189fac60a5Sjoris
1199fac60a5Sjoris if (chdir(cvs_server_path) == -1)
1209fac60a5Sjoris fatal("failed to change directory to '%s'", cvs_server_path);
1219fac60a5Sjoris
1229fac60a5Sjoris for (;;) {
1239fac60a5Sjoris cmd = cvs_remote_input();
1249fac60a5Sjoris
1259fac60a5Sjoris if ((data = strchr(cmd, ' ')) != NULL)
1269fac60a5Sjoris (*data++) = '\0';
1279fac60a5Sjoris
1289fac60a5Sjoris req = cvs_remote_get_request_info(cmd);
1299fac60a5Sjoris if (req == NULL)
1309fac60a5Sjoris fatal("request '%s' is not supported by our server",
1319fac60a5Sjoris cmd);
1329fac60a5Sjoris
1339fac60a5Sjoris if (req->hdlr == NULL)
1349fac60a5Sjoris fatal("opencvs server does not support '%s'", cmd);
1359fac60a5Sjoris
1367917ff23Sjoris if ((req->flags & REQ_NEEDDIR) && (server_currentdir == NULL))
1377917ff23Sjoris fatal("`%s' needs a directory to be sent with "
1387917ff23Sjoris "the `Directory` request first", cmd);
1397917ff23Sjoris
1409fac60a5Sjoris (*req->hdlr)(data);
141397ddb8aSnicm free(cmd);
1429fac60a5Sjoris }
1439fac60a5Sjoris
1449fac60a5Sjoris return (0);
1459fac60a5Sjoris }
1469fac60a5Sjoris
1479fac60a5Sjoris void
cvs_server_send_response(char * fmt,...)1489fac60a5Sjoris cvs_server_send_response(char *fmt, ...)
1499fac60a5Sjoris {
150be3337c1Stobias int i;
1519fac60a5Sjoris va_list ap;
152ffd4dac3Sray char *data;
1539fac60a5Sjoris
1549fac60a5Sjoris va_start(ap, fmt);
155be3337c1Stobias i = vasprintf(&data, fmt, ap);
1569fac60a5Sjoris va_end(ap);
157be3337c1Stobias if (i == -1)
1589a0ecc80Stobias fatal("cvs_server_send_response: could not allocate memory");
1599fac60a5Sjoris
160d0a063c4Sjoris cvs_log(LP_TRACE, "%s", data);
1619fac60a5Sjoris cvs_remote_output(data);
162397ddb8aSnicm free(data);
1639fac60a5Sjoris }
1649fac60a5Sjoris
1659fac60a5Sjoris void
cvs_server_root(char * data)1669fac60a5Sjoris cvs_server_root(char *data)
1679fac60a5Sjoris {
168b0d19690Stobias if (data == NULL)
169b0d19690Stobias fatal("Missing argument for Root");
170b0d19690Stobias
171b0d19690Stobias if (current_cvsroot != NULL)
172b0d19690Stobias return;
173b0d19690Stobias
174b0d19690Stobias if (data[0] != '/' || (current_cvsroot = cvsroot_get(data)) == NULL)
175b0d19690Stobias fatal("Invalid Root specified!");
176d892f828Stobias
177d892f828Stobias cvs_parse_configfile();
178bf6291b7Sjoris cvs_parse_modules();
179d892f828Stobias umask(cvs_umask);
1809fac60a5Sjoris }
1819fac60a5Sjoris
1829fac60a5Sjoris void
cvs_server_validresp(char * data)1839fac60a5Sjoris cvs_server_validresp(char *data)
1849fac60a5Sjoris {
1859fac60a5Sjoris int i;
1869fac60a5Sjoris char *sp, *ep;
1879fac60a5Sjoris struct cvs_resp *resp;
1889fac60a5Sjoris
1891d8d3676Sray if ((sp = data) == NULL)
1901d8d3676Sray fatal("Missing argument for Valid-responses");
1911d8d3676Sray
1929fac60a5Sjoris do {
1939fac60a5Sjoris if ((ep = strchr(sp, ' ')) != NULL)
1949fac60a5Sjoris *ep = '\0';
1959fac60a5Sjoris
1969fac60a5Sjoris resp = cvs_remote_get_response_info(sp);
1979fac60a5Sjoris if (resp != NULL)
1989fac60a5Sjoris resp->supported = 1;
1999fac60a5Sjoris
2009fac60a5Sjoris if (ep != NULL)
2019fac60a5Sjoris sp = ep + 1;
2029fac60a5Sjoris } while (ep != NULL);
2039fac60a5Sjoris
2049fac60a5Sjoris for (i = 0; cvs_responses[i].supported != -1; i++) {
2059fac60a5Sjoris resp = &cvs_responses[i];
2069fac60a5Sjoris if ((resp->flags & RESP_NEEDED) &&
2079fac60a5Sjoris resp->supported != 1) {
2089fac60a5Sjoris fatal("client does not support required '%s'",
2099fac60a5Sjoris resp->name);
2109fac60a5Sjoris }
2119fac60a5Sjoris }
2129fac60a5Sjoris }
2139fac60a5Sjoris
2149fac60a5Sjoris void
cvs_server_validreq(char * data)2159fac60a5Sjoris cvs_server_validreq(char *data)
2169fac60a5Sjoris {
2179fac60a5Sjoris BUF *bp;
2189fac60a5Sjoris char *d;
2199fac60a5Sjoris int i, first;
2209fac60a5Sjoris
2219fac60a5Sjoris first = 0;
2227bb3ddb0Sray bp = buf_alloc(512);
2239fac60a5Sjoris for (i = 0; cvs_requests[i].supported != -1; i++) {
2249fac60a5Sjoris if (cvs_requests[i].hdlr == NULL)
2259fac60a5Sjoris continue;
2269fac60a5Sjoris
2279fac60a5Sjoris if (first != 0)
2287bb3ddb0Sray buf_putc(bp, ' ');
2299fac60a5Sjoris else
2309fac60a5Sjoris first++;
2319fac60a5Sjoris
2327bb3ddb0Sray buf_puts(bp, cvs_requests[i].name);
2339fac60a5Sjoris }
2349fac60a5Sjoris
2357bb3ddb0Sray buf_putc(bp, '\0');
2367bb3ddb0Sray d = buf_release(bp);
2379fac60a5Sjoris
2389fac60a5Sjoris cvs_server_send_response("Valid-requests %s", d);
2399fac60a5Sjoris cvs_server_send_response("ok");
240397ddb8aSnicm free(d);
2419fac60a5Sjoris }
2429fac60a5Sjoris
2439fac60a5Sjoris void
cvs_server_static_directory(char * data)24488f45eccSxsa cvs_server_static_directory(char *data)
24588f45eccSxsa {
24688f45eccSxsa FILE *fp;
247b9fc9a72Sderaadt char fpath[PATH_MAX];
24888f45eccSxsa
249b9fc9a72Sderaadt (void)xsnprintf(fpath, PATH_MAX, "%s/%s",
250e40de241Sxsa server_currentdir, CVS_PATH_STATICENTRIES);
25188f45eccSxsa
25288f45eccSxsa if ((fp = fopen(fpath, "w+")) == NULL) {
25388f45eccSxsa cvs_log(LP_ERRNO, "%s", fpath);
254ba7b4b60Sotto return;
25588f45eccSxsa }
25688f45eccSxsa (void)fclose(fp);
25788f45eccSxsa }
25888f45eccSxsa
25988f45eccSxsa void
cvs_server_sticky(char * data)260af06ad21Sxsa cvs_server_sticky(char *data)
261af06ad21Sxsa {
262af06ad21Sxsa FILE *fp;
263b9fc9a72Sderaadt char tagpath[PATH_MAX];
264af06ad21Sxsa
2651d8d3676Sray if (data == NULL)
2661d8d3676Sray fatal("Missing argument for Sticky");
2671d8d3676Sray
268b9fc9a72Sderaadt (void)xsnprintf(tagpath, PATH_MAX, "%s/%s",
269e40de241Sxsa server_currentdir, CVS_PATH_TAG);
270af06ad21Sxsa
271af06ad21Sxsa if ((fp = fopen(tagpath, "w+")) == NULL) {
272af06ad21Sxsa cvs_log(LP_ERRNO, "%s", tagpath);
273ba7b4b60Sotto return;
274af06ad21Sxsa }
275af06ad21Sxsa
276af06ad21Sxsa (void)fprintf(fp, "%s\n", data);
277af06ad21Sxsa (void)fclose(fp);
278af06ad21Sxsa }
279af06ad21Sxsa
280af06ad21Sxsa void
cvs_server_globalopt(char * data)2819fac60a5Sjoris cvs_server_globalopt(char *data)
2829fac60a5Sjoris {
2831d8d3676Sray if (data == NULL)
2841d8d3676Sray fatal("Missing argument for Global_option");
2851d8d3676Sray
286a7be67ccSxsa if (!strcmp(data, "-l"))
287a7be67ccSxsa cvs_nolog = 1;
2889fac60a5Sjoris
2899fac60a5Sjoris if (!strcmp(data, "-n"))
2909fac60a5Sjoris cvs_noexec = 1;
2919fac60a5Sjoris
292a7be67ccSxsa if (!strcmp(data, "-Q"))
293a7be67ccSxsa verbosity = 0;
294a7be67ccSxsa
295a694c629Stobias if (!strcmp(data, "-q"))
296a694c629Stobias verbosity = 1;
297a694c629Stobias
298a7be67ccSxsa if (!strcmp(data, "-r"))
299a7be67ccSxsa cvs_readonly = 1;
300a7be67ccSxsa
301a7be67ccSxsa if (!strcmp(data, "-t"))
302a7be67ccSxsa cvs_trace = 1;
3039fac60a5Sjoris }
3049fac60a5Sjoris
3059fac60a5Sjoris void
cvs_server_set(char * data)306b4a9add8Sxsa cvs_server_set(char *data)
307b4a9add8Sxsa {
308b4a9add8Sxsa char *ep;
309b4a9add8Sxsa
3101d8d3676Sray if (data == NULL)
3111d8d3676Sray fatal("Missing argument for Set");
3121d8d3676Sray
313b4a9add8Sxsa ep = strchr(data, '=');
314b4a9add8Sxsa if (ep == NULL)
315b4a9add8Sxsa fatal("no = in variable assignment");
316b4a9add8Sxsa
317b4a9add8Sxsa *(ep++) = '\0';
318b4a9add8Sxsa if (cvs_var_set(data, ep) < 0)
319b4a9add8Sxsa fatal("cvs_server_set: cvs_var_set failed");
320b4a9add8Sxsa }
321b4a9add8Sxsa
322b4a9add8Sxsa void
cvs_server_directory(char * data)3239fac60a5Sjoris cvs_server_directory(char *data)
3249fac60a5Sjoris {
3259fac60a5Sjoris CVSENTRIES *entlist;
326ae83823aSxsa char *dir, *repo, *parent, *entry, *dirn, *p;
327*431378d1Snaddy char parentbuf[PATH_MAX], dirnbuf[PATH_MAX];
3289fac60a5Sjoris
329b0d19690Stobias if (current_cvsroot == NULL)
330b0d19690Stobias fatal("No Root specified for Directory");
331b0d19690Stobias
3329fac60a5Sjoris dir = cvs_remote_input();
3335219eee5Sjoris STRIP_SLASH(dir);
3345219eee5Sjoris
3355219eee5Sjoris if (strlen(dir) < strlen(current_cvsroot->cr_dir))
3369fac60a5Sjoris fatal("cvs_server_directory: bad Directory request");
3379fac60a5Sjoris
3385219eee5Sjoris repo = dir + strlen(current_cvsroot->cr_dir);
3399fac60a5Sjoris
3405219eee5Sjoris /*
3415219eee5Sjoris * This is somewhat required for checkout, as the
3425219eee5Sjoris * directory request will be:
3435219eee5Sjoris *
3445219eee5Sjoris * Directory .
3455219eee5Sjoris * /path/to/cvs/root
3465219eee5Sjoris */
3475219eee5Sjoris if (repo[0] == '\0')
3485219eee5Sjoris p = xstrdup(".");
3495219eee5Sjoris else
3505219eee5Sjoris p = xstrdup(repo + 1);
3515219eee5Sjoris
3525dd120b0Sjoris cvs_mkpath(p, NULL);
3535219eee5Sjoris
354*431378d1Snaddy if (strlcpy(dirnbuf, p, sizeof(dirnbuf)) >= sizeof(dirnbuf))
355*431378d1Snaddy fatal("cvs_server_directory: truncation");
356*431378d1Snaddy if ((dirn = basename(dirnbuf)) == NULL)
3579fac60a5Sjoris fatal("cvs_server_directory: %s", strerror(errno));
3589fac60a5Sjoris
359*431378d1Snaddy if (strlcpy(parentbuf, p, sizeof(parentbuf)) >= sizeof(parentbuf))
360*431378d1Snaddy fatal("cvs_server_directory: truncation");
361*431378d1Snaddy if ((parent = dirname(parentbuf)) == NULL)
3629fac60a5Sjoris fatal("cvs_server_directory: %s", strerror(errno));
3639fac60a5Sjoris
3649fac60a5Sjoris if (strcmp(parent, ".")) {
365ae83823aSxsa entry = xmalloc(CVS_ENT_MAXLINELEN);
366ae83823aSxsa cvs_ent_line_str(dirn, NULL, NULL, NULL, NULL, 1, 0,
367ae83823aSxsa entry, CVS_ENT_MAXLINELEN);
3689fac60a5Sjoris
369ae83823aSxsa entlist = cvs_ent_open(parent);
3709fac60a5Sjoris cvs_ent_add(entlist, entry);
371397ddb8aSnicm free(entry);
3729fac60a5Sjoris }
3739fac60a5Sjoris
374397ddb8aSnicm free(server_currentdir);
37552cd4e1bSray server_currentdir = p;
3769fac60a5Sjoris
377397ddb8aSnicm free(dir);
3789fac60a5Sjoris }
3799fac60a5Sjoris
3809fac60a5Sjoris void
cvs_server_entry(char * data)3819fac60a5Sjoris cvs_server_entry(char *data)
3829fac60a5Sjoris {
3839fac60a5Sjoris CVSENTRIES *entlist;
3849fac60a5Sjoris
3851d8d3676Sray if (data == NULL)
3861d8d3676Sray fatal("Missing argument for Entry");
3871d8d3676Sray
3889fac60a5Sjoris entlist = cvs_ent_open(server_currentdir);
3899fac60a5Sjoris cvs_ent_add(entlist, data);
3909fac60a5Sjoris }
3919fac60a5Sjoris
3929fac60a5Sjoris void
cvs_server_modified(char * data)3939fac60a5Sjoris cvs_server_modified(char *data)
3949fac60a5Sjoris {
395da62a647Sxsa int fd;
3969fac60a5Sjoris size_t flen;
3979fac60a5Sjoris mode_t fmode;
3989fac60a5Sjoris const char *errstr;
399b9fc9a72Sderaadt char *mode, *len, fpath[PATH_MAX];
4009fac60a5Sjoris
4011d8d3676Sray if (data == NULL)
4021d8d3676Sray fatal("Missing argument for Modified");
4031d8d3676Sray
4041b5598b0Sjoris /* sorry, we have to use TMP_DIR */
4051b5598b0Sjoris disable_fast_checkout = 1;
4061b5598b0Sjoris
4079fac60a5Sjoris mode = cvs_remote_input();
4089fac60a5Sjoris len = cvs_remote_input();
4099fac60a5Sjoris
4109fac60a5Sjoris cvs_strtomode(mode, &fmode);
411397ddb8aSnicm free(mode);
4129fac60a5Sjoris
4139fac60a5Sjoris flen = strtonum(len, 0, INT_MAX, &errstr);
4149fac60a5Sjoris if (errstr != NULL)
4159fac60a5Sjoris fatal("cvs_server_modified: %s", errstr);
416397ddb8aSnicm free(len);
4179fac60a5Sjoris
418b9fc9a72Sderaadt (void)xsnprintf(fpath, PATH_MAX, "%s/%s", server_currentdir, data);
4199fac60a5Sjoris
4209fac60a5Sjoris if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
4219fac60a5Sjoris fatal("cvs_server_modified: %s: %s", fpath, strerror(errno));
4229fac60a5Sjoris
423bb510330Sjoris cvs_remote_receive_file(fd, flen);
4249fac60a5Sjoris
4259fac60a5Sjoris if (fchmod(fd, 0600) == -1)
4269fac60a5Sjoris fatal("cvs_server_modified: failed to set file mode");
4279fac60a5Sjoris
4289fac60a5Sjoris (void)close(fd);
4299fac60a5Sjoris }
4309fac60a5Sjoris
4319fac60a5Sjoris void
cvs_server_useunchanged(char * data)4329fac60a5Sjoris cvs_server_useunchanged(char *data)
4339fac60a5Sjoris {
4349fac60a5Sjoris }
4359fac60a5Sjoris
4369fac60a5Sjoris void
cvs_server_unchanged(char * data)4379fac60a5Sjoris cvs_server_unchanged(char *data)
4389fac60a5Sjoris {
439b9fc9a72Sderaadt char fpath[PATH_MAX];
4409fac60a5Sjoris CVSENTRIES *entlist;
4419fac60a5Sjoris struct cvs_ent *ent;
442a1742a04Sjoris char sticky[CVS_ENT_MAXLINELEN];
443a1742a04Sjoris char rev[CVS_REV_BUFSZ], entry[CVS_ENT_MAXLINELEN];
4449fac60a5Sjoris
4451d8d3676Sray if (data == NULL)
4461d8d3676Sray fatal("Missing argument for Unchanged");
4471d8d3676Sray
4481b5598b0Sjoris /* sorry, we have to use TMP_DIR */
4491b5598b0Sjoris disable_fast_checkout = 1;
4501b5598b0Sjoris
451b9fc9a72Sderaadt (void)xsnprintf(fpath, PATH_MAX, "%s/%s", server_currentdir, data);
4529fac60a5Sjoris
4539fac60a5Sjoris entlist = cvs_ent_open(server_currentdir);
4549fac60a5Sjoris ent = cvs_ent_get(entlist, data);
4559fac60a5Sjoris if (ent == NULL)
4569fac60a5Sjoris fatal("received Unchanged request for non-existing file");
4579fac60a5Sjoris
458a1742a04Sjoris sticky[0] = '\0';
459a1742a04Sjoris if (ent->ce_tag != NULL)
460a1742a04Sjoris (void)xsnprintf(sticky, sizeof(sticky), "T%s", ent->ce_tag);
4619fac60a5Sjoris
462a1742a04Sjoris rcsnum_tostr(ent->ce_rev, rev, sizeof(rev));
463a1742a04Sjoris (void)xsnprintf(entry, sizeof(entry), "/%s/%s/%s/%s/%s",
464a1742a04Sjoris ent->ce_name, rev, CVS_SERVER_UNCHANGED, ent->ce_opts ?
465a1742a04Sjoris ent->ce_opts : "", sticky);
4669fac60a5Sjoris
4679fac60a5Sjoris cvs_ent_free(ent);
468a1742a04Sjoris cvs_ent_add(entlist, entry);
4699fac60a5Sjoris }
4709fac60a5Sjoris
4719fac60a5Sjoris void
cvs_server_questionable(char * data)4729fac60a5Sjoris cvs_server_questionable(char *data)
4739fac60a5Sjoris {
474bf2db54cSjoris CVSENTRIES *entlist;
475bf2db54cSjoris char entry[CVS_ENT_MAXLINELEN];
476bf2db54cSjoris
477bf2db54cSjoris if (data == NULL)
478bf2db54cSjoris fatal("Questionable request with no data attached");
479bf2db54cSjoris
480bf2db54cSjoris (void)xsnprintf(entry, sizeof(entry), "/%s/%c///", data,
481bf2db54cSjoris CVS_SERVER_QUESTIONABLE);
482bf2db54cSjoris
483bf2db54cSjoris entlist = cvs_ent_open(server_currentdir);
484bf2db54cSjoris cvs_ent_add(entlist, entry);
485bf2db54cSjoris
4861b5598b0Sjoris /* sorry, we have to use TMP_DIR */
4871b5598b0Sjoris disable_fast_checkout = 1;
4889fac60a5Sjoris }
4899fac60a5Sjoris
4909fac60a5Sjoris void
cvs_server_argument(char * data)4919fac60a5Sjoris cvs_server_argument(char *data)
4929fac60a5Sjoris {
4931d8d3676Sray if (data == NULL)
4941d8d3676Sray fatal("Missing argument for Argument");
4951d8d3676Sray
496caa2ffb0Sderaadt server_argv = xreallocarray(server_argv, server_argc + 2,
49710283864Stobias sizeof(*server_argv));
49810283864Stobias server_argv[server_argc] = xstrdup(data);
49910283864Stobias server_argv[++server_argc] = NULL;
5009fac60a5Sjoris }
5019fac60a5Sjoris
5029fac60a5Sjoris void
cvs_server_argumentx(char * data)50390f82a7aSxsa cvs_server_argumentx(char *data)
50490f82a7aSxsa {
505275f583eSjoris int idx;
506275f583eSjoris size_t len;
507275f583eSjoris
508ba1c72edStobias if (server_argc == 1)
509275f583eSjoris fatal("Protocol Error: ArgumentX without previous argument");
510275f583eSjoris
511275f583eSjoris idx = server_argc - 1;
512275f583eSjoris
513275f583eSjoris len = strlen(server_argv[idx]) + strlen(data) + 2;
514caa2ffb0Sderaadt server_argv[idx] = xreallocarray(server_argv[idx], len, sizeof(char));
515275f583eSjoris strlcat(server_argv[idx], "\n", len);
516275f583eSjoris strlcat(server_argv[idx], data, len);
51790f82a7aSxsa }
51890f82a7aSxsa
51990f82a7aSxsa void
cvs_server_update_patches(char * data)520cadd0e2eSxsa cvs_server_update_patches(char *data)
521cadd0e2eSxsa {
522cadd0e2eSxsa /*
523cadd0e2eSxsa * This does not actually do anything.
524cadd0e2eSxsa * It is used to tell that the server is able to
525cadd0e2eSxsa * generate patches when given an `update' request.
526cadd0e2eSxsa * The client must issue the -u argument to `update'
527cadd0e2eSxsa * to receive patches.
528cadd0e2eSxsa */
529cadd0e2eSxsa }
530cadd0e2eSxsa
531cadd0e2eSxsa void
cvs_server_add(char * data)53277a3e292Sxsa cvs_server_add(char *data)
53377a3e292Sxsa {
53477a3e292Sxsa if (chdir(server_currentdir) == -1)
53577a3e292Sxsa fatal("cvs_server_add: %s", strerror(errno));
53677a3e292Sxsa
53777a3e292Sxsa cvs_cmdop = CVS_OP_ADD;
538f331ff59Stobias cmdp->cmd_flags = cvs_cmd_add.cmd_flags;
53977a3e292Sxsa cvs_add(server_argc, server_argv);
54077a3e292Sxsa cvs_server_send_response("ok");
54177a3e292Sxsa }
54277a3e292Sxsa
54377a3e292Sxsa void
cvs_server_import(char * data)54427de14f8Sjoris cvs_server_import(char *data)
54527de14f8Sjoris {
54627de14f8Sjoris if (chdir(server_currentdir) == -1)
54727de14f8Sjoris fatal("cvs_server_import: %s", strerror(errno));
54827de14f8Sjoris
54927de14f8Sjoris cvs_cmdop = CVS_OP_IMPORT;
550f331ff59Stobias cmdp->cmd_flags = cvs_cmd_import.cmd_flags;
55127de14f8Sjoris cvs_import(server_argc, server_argv);
55227de14f8Sjoris cvs_server_send_response("ok");
55327de14f8Sjoris }
55427de14f8Sjoris
55527de14f8Sjoris void
cvs_server_admin(char * data)55640133d45Sxsa cvs_server_admin(char *data)
55740133d45Sxsa {
55840133d45Sxsa if (chdir(server_currentdir) == -1)
55940133d45Sxsa fatal("cvs_server_admin: %s", strerror(errno));
56040133d45Sxsa
56140133d45Sxsa cvs_cmdop = CVS_OP_ADMIN;
562f331ff59Stobias cmdp->cmd_flags = cvs_cmd_admin.cmd_flags;
56340133d45Sxsa cvs_admin(server_argc, server_argv);
56440133d45Sxsa cvs_server_send_response("ok");
56540133d45Sxsa }
56640133d45Sxsa
567c3f1b62fSxsa void
cvs_server_annotate(char * data)568c3f1b62fSxsa cvs_server_annotate(char *data)
569c3f1b62fSxsa {
570c3f1b62fSxsa if (chdir(server_currentdir) == -1)
571c3f1b62fSxsa fatal("cvs_server_annotate: %s", strerror(errno));
572c3f1b62fSxsa
573c3f1b62fSxsa cvs_cmdop = CVS_OP_ANNOTATE;
574f331ff59Stobias cmdp->cmd_flags = cvs_cmd_annotate.cmd_flags;
575c3f1b62fSxsa cvs_annotate(server_argc, server_argv);
576c3f1b62fSxsa cvs_server_send_response("ok");
577c3f1b62fSxsa }
57840133d45Sxsa
57940133d45Sxsa void
cvs_server_rannotate(char * data)580e9658789Stobias cvs_server_rannotate(char *data)
581e9658789Stobias {
582e9658789Stobias if (chdir(server_currentdir) == -1)
583e9658789Stobias fatal("cvs_server_rannotate: %s", strerror(errno));
584e9658789Stobias
585e9658789Stobias cvs_cmdop = CVS_OP_RANNOTATE;
586e9658789Stobias cmdp->cmd_flags = cvs_cmd_rannotate.cmd_flags;
587e9658789Stobias cvs_annotate(server_argc, server_argv);
588e9658789Stobias cvs_server_send_response("ok");
589e9658789Stobias }
590e9658789Stobias
591e9658789Stobias void
cvs_server_commit(char * data)5929fac60a5Sjoris cvs_server_commit(char *data)
5939fac60a5Sjoris {
5949fac60a5Sjoris if (chdir(server_currentdir) == -1)
5959fac60a5Sjoris fatal("cvs_server_commit: %s", strerror(errno));
5969fac60a5Sjoris
5979fac60a5Sjoris cvs_cmdop = CVS_OP_COMMIT;
598f331ff59Stobias cmdp->cmd_flags = cvs_cmd_commit.cmd_flags;
5999fac60a5Sjoris cvs_commit(server_argc, server_argv);
6009fac60a5Sjoris cvs_server_send_response("ok");
6019fac60a5Sjoris }
6029fac60a5Sjoris
6039fac60a5Sjoris void
cvs_server_checkout(char * data)6045219eee5Sjoris cvs_server_checkout(char *data)
605afbb3e97Stobias {
606afbb3e97Stobias if (chdir(server_currentdir) == -1)
6075219eee5Sjoris fatal("cvs_server_checkout: %s", strerror(errno));
6085219eee5Sjoris
6095219eee5Sjoris cvs_cmdop = CVS_OP_CHECKOUT;
610f331ff59Stobias cmdp->cmd_flags = cvs_cmd_checkout.cmd_flags;
6115219eee5Sjoris cvs_checkout(server_argc, server_argv);
6125219eee5Sjoris cvs_server_send_response("ok");
6135219eee5Sjoris }
6145219eee5Sjoris
6155219eee5Sjoris void
cvs_server_diff(char * data)6169fac60a5Sjoris cvs_server_diff(char *data)
6179fac60a5Sjoris {
6189fac60a5Sjoris if (chdir(server_currentdir) == -1)
6199fac60a5Sjoris fatal("cvs_server_diff: %s", strerror(errno));
6209fac60a5Sjoris
6219fac60a5Sjoris cvs_cmdop = CVS_OP_DIFF;
622f331ff59Stobias cmdp->cmd_flags = cvs_cmd_diff.cmd_flags;
6239fac60a5Sjoris cvs_diff(server_argc, server_argv);
6249fac60a5Sjoris cvs_server_send_response("ok");
6259fac60a5Sjoris }
6269fac60a5Sjoris
6279fac60a5Sjoris void
cvs_server_rdiff(char * data)628fd660bf2Stobias cvs_server_rdiff(char *data)
629fd660bf2Stobias {
630fd660bf2Stobias if (chdir(server_currentdir) == -1)
631fd660bf2Stobias fatal("cvs_server_rdiff: %s", strerror(errno));
632fd660bf2Stobias
633fd660bf2Stobias cvs_cmdop = CVS_OP_RDIFF;
634fd660bf2Stobias cmdp->cmd_flags = cvs_cmd_rdiff.cmd_flags;
635fd660bf2Stobias cvs_diff(server_argc, server_argv);
636fd660bf2Stobias cvs_server_send_response("ok");
637fd660bf2Stobias }
638fd660bf2Stobias
639fd660bf2Stobias void
cvs_server_export(char * data)6405e1effbaStobias cvs_server_export(char *data)
641afbb3e97Stobias {
642afbb3e97Stobias if (chdir(server_currentdir) == -1)
643afbb3e97Stobias fatal("cvs_server_export: %s", strerror(errno));
6445e1effbaStobias
6455e1effbaStobias cvs_cmdop = CVS_OP_EXPORT;
646f331ff59Stobias cmdp->cmd_flags = cvs_cmd_export.cmd_flags;
6471b5598b0Sjoris cvs_export(server_argc, server_argv);
6485e1effbaStobias cvs_server_send_response("ok");
6495e1effbaStobias }
6505e1effbaStobias
6515e1effbaStobias void
cvs_server_init(char * data)652fd590a3cSxsa cvs_server_init(char *data)
653fd590a3cSxsa {
654545fb2e2Stobias if (data == NULL)
655545fb2e2Stobias fatal("Missing argument for init");
656545fb2e2Stobias
657545fb2e2Stobias if (current_cvsroot != NULL)
658545fb2e2Stobias fatal("Root in combination with init is not supported");
659545fb2e2Stobias
660545fb2e2Stobias if ((current_cvsroot = cvsroot_get(data)) == NULL)
661545fb2e2Stobias fatal("Invalid argument for init");
662fd590a3cSxsa
663fd590a3cSxsa cvs_cmdop = CVS_OP_INIT;
664f331ff59Stobias cmdp->cmd_flags = cvs_cmd_init.cmd_flags;
665fd590a3cSxsa cvs_init(server_argc, server_argv);
666fd590a3cSxsa cvs_server_send_response("ok");
667fd590a3cSxsa }
668fd590a3cSxsa
669fd590a3cSxsa void
cvs_server_release(char * data)670fe3f9a6fSxsa cvs_server_release(char *data)
671fe3f9a6fSxsa {
672fe3f9a6fSxsa if (chdir(server_currentdir) == -1)
673ced0e988Sxsa fatal("cvs_server_release: %s", strerror(errno));
674fe3f9a6fSxsa
675fe3f9a6fSxsa cvs_cmdop = CVS_OP_RELEASE;
676f331ff59Stobias cmdp->cmd_flags = cvs_cmd_release.cmd_flags;
677fe3f9a6fSxsa cvs_release(server_argc, server_argv);
678fe3f9a6fSxsa cvs_server_send_response("ok");
679fe3f9a6fSxsa }
680fe3f9a6fSxsa
681fe3f9a6fSxsa void
cvs_server_remove(char * data)68277a3e292Sxsa cvs_server_remove(char *data)
68377a3e292Sxsa {
68477a3e292Sxsa if (chdir(server_currentdir) == -1)
68577a3e292Sxsa fatal("cvs_server_remove: %s", strerror(errno));
68677a3e292Sxsa
68777a3e292Sxsa cvs_cmdop = CVS_OP_REMOVE;
688f331ff59Stobias cmdp->cmd_flags = cvs_cmd_remove.cmd_flags;
68977a3e292Sxsa cvs_remove(server_argc, server_argv);
69077a3e292Sxsa cvs_server_send_response("ok");
69177a3e292Sxsa }
69277a3e292Sxsa
69377a3e292Sxsa void
cvs_server_status(char * data)6949fac60a5Sjoris cvs_server_status(char *data)
6959fac60a5Sjoris {
6969fac60a5Sjoris if (chdir(server_currentdir) == -1)
6979fac60a5Sjoris fatal("cvs_server_status: %s", strerror(errno));
6989fac60a5Sjoris
6999fac60a5Sjoris cvs_cmdop = CVS_OP_STATUS;
700f331ff59Stobias cmdp->cmd_flags = cvs_cmd_status.cmd_flags;
7019fac60a5Sjoris cvs_status(server_argc, server_argv);
7029fac60a5Sjoris cvs_server_send_response("ok");
7039fac60a5Sjoris }
7049fac60a5Sjoris
7059fac60a5Sjoris void
cvs_server_log(char * data)7069fac60a5Sjoris cvs_server_log(char *data)
7079fac60a5Sjoris {
7089fac60a5Sjoris if (chdir(server_currentdir) == -1)
7099fac60a5Sjoris fatal("cvs_server_log: %s", strerror(errno));
7109fac60a5Sjoris
7119fac60a5Sjoris cvs_cmdop = CVS_OP_LOG;
712f331ff59Stobias cmdp->cmd_flags = cvs_cmd_log.cmd_flags;
7139fac60a5Sjoris cvs_getlog(server_argc, server_argv);
7149fac60a5Sjoris cvs_server_send_response("ok");
7159fac60a5Sjoris }
7169fac60a5Sjoris
7179fac60a5Sjoris void
cvs_server_rlog(char * data)718449bca81Sniallo cvs_server_rlog(char *data)
719449bca81Sniallo {
72063c942a2Stobias if (chdir(current_cvsroot->cr_dir) == -1)
721ced0e988Sxsa fatal("cvs_server_rlog: %s", strerror(errno));
722449bca81Sniallo
723449bca81Sniallo cvs_cmdop = CVS_OP_RLOG;
724f331ff59Stobias cmdp->cmd_flags = cvs_cmd_rlog.cmd_flags;
725449bca81Sniallo cvs_getlog(server_argc, server_argv);
726449bca81Sniallo cvs_server_send_response("ok");
727449bca81Sniallo }
728449bca81Sniallo
729449bca81Sniallo void
cvs_server_tag(char * data)730ddb6a81aSxsa cvs_server_tag(char *data)
731ddb6a81aSxsa {
732ddb6a81aSxsa if (chdir(server_currentdir) == -1)
733ddb6a81aSxsa fatal("cvs_server_tag: %s", strerror(errno));
734ddb6a81aSxsa
735ddb6a81aSxsa cvs_cmdop = CVS_OP_TAG;
736f331ff59Stobias cmdp->cmd_flags = cvs_cmd_tag.cmd_flags;
737f8d46fa9Sxsa cvs_tag(server_argc, server_argv);
738ddb6a81aSxsa cvs_server_send_response("ok");
739ddb6a81aSxsa }
740ddb6a81aSxsa
741ddb6a81aSxsa void
cvs_server_rtag(char * data)7424b15c6ebStobias cvs_server_rtag(char *data)
7434b15c6ebStobias {
7444b15c6ebStobias if (chdir(current_cvsroot->cr_dir) == -1)
745afbb3e97Stobias fatal("cvs_server_rtag: %s", strerror(errno));
7464b15c6ebStobias
7474b15c6ebStobias cvs_cmdop = CVS_OP_RTAG;
748f331ff59Stobias cmdp->cmd_flags = cvs_cmd_rtag.cmd_flags;
7494b15c6ebStobias cvs_tag(server_argc, server_argv);
7504b15c6ebStobias cvs_server_send_response("ok");
7514b15c6ebStobias }
7524b15c6ebStobias
7534b15c6ebStobias void
cvs_server_update(char * data)7549fac60a5Sjoris cvs_server_update(char *data)
7559fac60a5Sjoris {
7569fac60a5Sjoris if (chdir(server_currentdir) == -1)
7579fac60a5Sjoris fatal("cvs_server_update: %s", strerror(errno));
7589fac60a5Sjoris
7599fac60a5Sjoris cvs_cmdop = CVS_OP_UPDATE;
760f331ff59Stobias cmdp->cmd_flags = cvs_cmd_update.cmd_flags;
7619fac60a5Sjoris cvs_update(server_argc, server_argv);
7629fac60a5Sjoris cvs_server_send_response("ok");
7639fac60a5Sjoris }
764f5e00cb0Sxsa
765f5e00cb0Sxsa void
cvs_server_version(char * data)766f5e00cb0Sxsa cvs_server_version(char *data)
767f5e00cb0Sxsa {
768f5e00cb0Sxsa cvs_cmdop = CVS_OP_VERSION;
769f331ff59Stobias cmdp->cmd_flags = cvs_cmd_version.cmd_flags;
770f5e00cb0Sxsa cvs_version(server_argc, server_argv);
771f5e00cb0Sxsa cvs_server_send_response("ok");
772f5e00cb0Sxsa }
773408908afSjoris
774408908afSjoris void
cvs_server_update_entry(const char * resp,struct cvs_file * cf)775408908afSjoris cvs_server_update_entry(const char *resp, struct cvs_file *cf)
776408908afSjoris {
7779f4abebfSray char *p;
778b9fc9a72Sderaadt char repo[PATH_MAX], fpath[PATH_MAX];
779408908afSjoris
780408908afSjoris if ((p = strrchr(cf->file_rpath, ',')) != NULL)
781408908afSjoris *p = '\0';
782408908afSjoris
783b9fc9a72Sderaadt cvs_get_repository_path(cf->file_wd, repo, PATH_MAX);
784b9fc9a72Sderaadt (void)xsnprintf(fpath, PATH_MAX, "%s/%s", repo, cf->file_name);
7855dd120b0Sjoris
7869f4abebfSray cvs_server_send_response("%s %s/", resp, cf->file_wd);
7875dd120b0Sjoris cvs_remote_output(fpath);
788408908afSjoris
789408908afSjoris if (p != NULL)
790408908afSjoris *p = ',';
791408908afSjoris }
7925dd120b0Sjoris
7935dd120b0Sjoris void
cvs_server_set_sticky(const char * dir,char * tag)7940fcddf58Sotto cvs_server_set_sticky(const char *dir, char *tag)
7955dd120b0Sjoris {
796b9fc9a72Sderaadt char fpath[PATH_MAX];
797b9fc9a72Sderaadt char repo[PATH_MAX];
7985dd120b0Sjoris
799b9fc9a72Sderaadt cvs_get_repository_path(dir, repo, PATH_MAX);
800b9fc9a72Sderaadt (void)xsnprintf(fpath, PATH_MAX, "%s/", repo);
8015dd120b0Sjoris
8025f01291dSjoris cvs_server_send_response("Set-sticky %s/", dir);
8035dd120b0Sjoris cvs_remote_output(fpath);
80451ef6581Sjoris cvs_remote_output(tag);
8055dd120b0Sjoris }
8065dd120b0Sjoris
8075dd120b0Sjoris void
cvs_server_clear_sticky(char * dir)8085dd120b0Sjoris cvs_server_clear_sticky(char *dir)
8095dd120b0Sjoris {
810b9fc9a72Sderaadt char fpath[PATH_MAX];
811b9fc9a72Sderaadt char repo[PATH_MAX];
8125dd120b0Sjoris
813b9fc9a72Sderaadt cvs_get_repository_path(dir, repo, PATH_MAX);
814b9fc9a72Sderaadt (void)xsnprintf(fpath, PATH_MAX, "%s/", repo);
8155dd120b0Sjoris
8165f01291dSjoris cvs_server_send_response("Clear-sticky %s//", dir);
8175dd120b0Sjoris cvs_remote_output(fpath);
8185dd120b0Sjoris }
8195ede44f5Sjoris
8205ede44f5Sjoris void
cvs_server_exp_modules(char * module)8215ede44f5Sjoris cvs_server_exp_modules(char *module)
8225ede44f5Sjoris {
8235ede44f5Sjoris struct module_checkout *mo;
8245ede44f5Sjoris struct cvs_filelist *fl;
8255ede44f5Sjoris
8265ede44f5Sjoris if (server_argc != 2)
8275ede44f5Sjoris fatal("expand-modules with no arguments");
8285ede44f5Sjoris
8295ede44f5Sjoris mo = cvs_module_lookup(server_argv[1]);
8305ede44f5Sjoris
8315ede44f5Sjoris RB_FOREACH(fl, cvs_flisthead, &(mo->mc_modules))
8325ede44f5Sjoris cvs_server_send_response("Module-expansion %s", fl->file_path);
8335ede44f5Sjoris cvs_server_send_response("ok");
8345ede44f5Sjoris
8355ede44f5Sjoris server_argc--;
836397ddb8aSnicm free(server_argv[1]);
8375ede44f5Sjoris server_argv[1] = NULL;
8385ede44f5Sjoris }
839