Annotation of src/usr.bin/cvs/cvsd.c, Revision 1.18
1.18 ! jfb 1: /* $OpenBSD: cvsd.c,v 1.17 2005/02/15 15:17:34 jfb Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.14 tedu 4: * All rights reserved.
1.1 jfb 5: *
1.14 tedu 6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
1.1 jfb 9: *
1.14 tedu 10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
1.1 jfb 12: * 2. The name of the author may not be used to endorse or promote products
1.14 tedu 13: * derived from this software without specific prior written permission.
1.1 jfb 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
1.14 tedu 24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 jfb 25: */
26:
27: #include <sys/param.h>
28: #include <sys/stat.h>
29: #include <sys/wait.h>
30: #include <sys/uio.h>
31:
32: #include <err.h>
33: #include <pwd.h>
34: #include <grp.h>
35: #include <poll.h>
36: #include <fcntl.h>
37: #include <dirent.h>
38: #include <stdlib.h>
39: #include <stdio.h>
40: #include <unistd.h>
41: #include <signal.h>
42: #include <errno.h>
43: #include <string.h>
44: #include <sysexits.h>
45:
46: #include "log.h"
47: #include "sock.h"
48: #include "cvs.h"
1.18 ! jfb 49: #include "repo.h"
1.1 jfb 50: #include "cvsd.h"
51:
52:
53: static void cvsd_parent_loop (void);
1.8 jfb 54: static void cvsd_report (void);
1.1 jfb 55:
56:
57: extern char *__progname;
58:
59:
1.11 jfb 60: int cvsd_fg = 0;
1.18 ! jfb 61: uid_t cvsd_uid = 0;
! 62: gid_t cvsd_gid = 0;
1.1 jfb 63:
1.10 jfb 64: volatile sig_atomic_t cvsd_running = 1;
65: volatile sig_atomic_t cvsd_restart = 0;
1.1 jfb 66:
1.9 jfb 67: static char *cvsd_user = NULL;
68: static char *cvsd_group = NULL;
1.7 jfb 69: static char *cvsd_root = NULL;
1.18 ! jfb 70: static char *cvsd_conffile = CVSD_PATH_CONF;
1.11 jfb 71: static char *cvsd_moddir = NULL;
1.1 jfb 72: static int cvsd_privfd = -1;
73:
1.18 ! jfb 74: static CVSREPO *cvsd_repo;
! 75:
1.1 jfb 76:
77: static TAILQ_HEAD(,cvsd_child) cvsd_children;
78: static volatile sig_atomic_t cvsd_chnum = 0;
79: static volatile sig_atomic_t cvsd_chmax = CVSD_CHILD_DEFMAX;
1.7 jfb 80: static volatile sig_atomic_t cvsd_sigchld = 0;
1.8 jfb 81: static volatile sig_atomic_t cvsd_siginfo = 0;
1.1 jfb 82:
83:
1.18 ! jfb 84: void usage (void);
1.8 jfb 85: void cvsd_sighdlr (int);
86: int cvsd_msghdlr (struct cvsd_child *, int);
1.3 jfb 87:
88:
1.1 jfb 89: /*
1.8 jfb 90: * cvsd_sighdlr()
1.1 jfb 91: *
1.8 jfb 92: * Generic signal handler.
1.1 jfb 93: */
94: void
1.8 jfb 95: cvsd_sighdlr(int signo)
1.1 jfb 96: {
1.8 jfb 97: switch (signo) {
98: case SIGHUP:
1.10 jfb 99: cvsd_restart = 1;
1.8 jfb 100: break;
101: case SIGCHLD:
102: cvsd_sigchld = 1;
103: break;
104: case SIGINT:
105: case SIGTERM:
106: case SIGQUIT:
1.10 jfb 107: cvsd_running = 0;
1.8 jfb 108: break;
109: case SIGINFO:
110: cvsd_siginfo = 1;
111: break;
112: }
1.1 jfb 113: }
114:
115:
116: /*
117: * usage()
118: *
119: * Display program usage.
120: */
121: void
122: usage(void)
123: {
124: fprintf(stderr,
1.8 jfb 125: "Usage: %s [-dfhpv] [-c config] [-g group] [-r root] "
126: "[-s path] [-u user]\n"
1.7 jfb 127: "\t-c config\tUse <config> as the configuration file\n"
1.1 jfb 128: "\t-d\t\tStart the server in debugging mode (very verbose)\n"
129: "\t-f\t\tStay in foreground instead of becoming a daemon\n"
1.8 jfb 130: "\t-g group\tUse group <group> for privilege revocation\n"
1.6 jfb 131: "\t-h\t\tPrint the usage and exit\n"
132: "\t-p\t\tPerform repository sanity check on startup\n"
133: "\t-r root\t\tUse <root> as the root directory of the repository\n"
134: "\t-s path\t\tUse <path> as the path for the CVS server socket\n"
1.16 xsa 135: "\t-u user\t\tUse user <user> for privilege revocation\n"
1.1 jfb 136: "\t-v\t\tBe verbose\n",
137: __progname);
138: }
139:
140:
141: int
142: main(int argc, char **argv)
143: {
1.18 ! jfb 144: int ret, repo_flags;
1.1 jfb 145: struct passwd *pwd;
146: struct group *grp;
147:
1.18 ! jfb 148: repo_flags = 0;
1.17 jfb 149: cvsd_set(CVSD_SET_SOCK, CVSD_SOCK_PATH);
1.9 jfb 150: cvsd_set(CVSD_SET_USER, CVSD_USER);
151: cvsd_set(CVSD_SET_GROUP, CVSD_GROUP);
1.1 jfb 152:
153: if (cvs_log_init(LD_STD|LD_SYSLOG, LF_PID) < 0)
154: err(1, "failed to initialize logging mechanism");
155:
1.18 ! jfb 156: while ((ret = getopt(argc, argv, "c:dfg:hpr:s:u:v")) != -1) {
1.1 jfb 157: switch (ret) {
1.3 jfb 158: case 'c':
159: cvsd_conffile = optarg;
1.1 jfb 160: break;
161: case 'd':
162: cvs_log_filter(LP_FILTER_UNSET, LP_DEBUG);
163: cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
164: break;
165: case 'f':
1.10 jfb 166: cvsd_fg = 1;
1.6 jfb 167: break;
1.8 jfb 168: case 'g':
1.9 jfb 169: cvsd_set(CVSD_SET_GROUP, optarg);
1.8 jfb 170: break;
1.6 jfb 171: case 'h':
172: usage();
173: exit(0);
174: /* NOTREACHED */
1.1 jfb 175: break;
176: case 'p':
1.18 ! jfb 177: repo_flags |= CVS_REPO_CHKPERM;
1.1 jfb 178: break;
179: case 'r':
1.17 jfb 180: cvsd_set(CVSD_SET_ROOT, optarg);
1.1 jfb 181: break;
182: case 's':
1.17 jfb 183: cvsd_set(CVSD_SET_SOCK, optarg);
1.1 jfb 184: break;
1.8 jfb 185: case 'u':
1.9 jfb 186: cvsd_set(CVSD_SET_USER, optarg);
1.8 jfb 187: break;
1.1 jfb 188: case 'v':
189: cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
190: break;
191: default:
192: usage();
193: exit(EX_USAGE);
194: }
195: }
196:
197: argc -= optind;
198: argv += optind;
199:
1.3 jfb 200: if (cvs_conf_read(cvsd_conffile) < 0)
201: errx(1, "error parsing configuration file `%s'", cvsd_conffile);
1.1 jfb 202:
203: if (cvsd_root == NULL)
204: errx(1, "no CVS root directory specified");
205:
206: if (argc > 0)
207: errx(EX_USAGE, "unrecognized trailing arguments");
208:
209: TAILQ_INIT(&cvsd_children);
210:
1.8 jfb 211: pwd = getpwnam(cvsd_user);
1.1 jfb 212: if (pwd == NULL)
1.8 jfb 213: err(EX_NOUSER, "failed to get user `%s'", cvsd_user);
1.1 jfb 214:
1.8 jfb 215: grp = getgrnam(cvsd_group);
1.1 jfb 216: if (grp == NULL)
1.8 jfb 217: err(EX_NOUSER, "failed to get group `%s'", cvsd_group);
1.1 jfb 218:
1.18 ! jfb 219: endpwent();
! 220: endgrent();
! 221:
1.1 jfb 222: cvsd_uid = pwd->pw_uid;
223: cvsd_gid = grp->gr_gid;
224:
1.8 jfb 225: signal(SIGHUP, cvsd_sighdlr);
226: signal(SIGINT, cvsd_sighdlr);
227: signal(SIGQUIT, cvsd_sighdlr);
228: signal(SIGTERM, cvsd_sighdlr);
229: signal(SIGCHLD, cvsd_sighdlr);
1.11 jfb 230: signal(SIGPIPE, SIG_IGN);
1.1 jfb 231:
1.10 jfb 232: if (!cvsd_fg && daemon(0, 0) == -1) {
1.1 jfb 233: cvs_log(LP_ERRNO, "failed to become a daemon");
234: exit(EX_OSERR);
235: }
236:
1.18 ! jfb 237: if ((cvsd_repo = cvs_repo_load(cvsd_root, repo_flags)) == NULL) {
! 238: cvs_log(LP_ERR, "failed to load repository");
! 239: exit(EX_OSERR);
! 240: };
! 241:
1.1 jfb 242: if (cvsd_sock_open() < 0) {
243: exit(1);
244: }
245:
246: if (setegid(cvsd_gid) == -1) {
247: cvs_log(LP_ERRNO, "failed to drop group privileges");
248: exit(EX_OSERR);
249: }
250: if (seteuid(cvsd_uid) == -1) {
251: cvs_log(LP_ERRNO, "failed to drop user privileges");
252: exit(EX_OSERR);
253: }
254:
1.8 jfb 255: signal(SIGINFO, cvsd_sighdlr);
1.3 jfb 256: cvsd_parent_loop();
1.1 jfb 257:
258: cvsd_sock_close();
259:
1.18 ! jfb 260: cvs_repo_free(cvsd_repo);
1.1 jfb 261:
1.18 ! jfb 262: cvs_log(LP_NOTICE, "shutting down");
! 263: cvs_log_cleanup();
1.1 jfb 264: return (0);
265: }
266:
267:
268: /*
1.3 jfb 269: * cvsd_child_fork()
1.1 jfb 270: *
1.18 ! jfb 271: * Fork a child process which chroots to the CVS repository's root directory,
! 272: * drops all privileges, and then executes the cvsd-child process, which will
! 273: * handle the incoming CVS requests.
! 274: * On success, returns a pointer to the new child structure,
! 275: * or NULL on failure.
1.1 jfb 276: */
1.18 ! jfb 277: struct cvsd_child*
! 278: cvsd_child_fork(int sock)
1.1 jfb 279: {
1.18 ! jfb 280: int argc, svec[2];
1.1 jfb 281: pid_t pid;
1.18 ! jfb 282: char *argv[16], ubuf[8], gbuf[8];
1.1 jfb 283: struct cvsd_child *chp;
284:
1.3 jfb 285: if (cvsd_chnum == cvsd_chmax) {
286: cvs_log(LP_WARN, "child pool reached limit of processes");
1.18 ! jfb 287: return (NULL);
1.3 jfb 288: }
289:
1.1 jfb 290: if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, svec) == -1) {
291: cvs_log(LP_ERRNO, "failed to create socket pair");
1.18 ! jfb 292: return (NULL);
1.1 jfb 293: }
294:
295: /*
296: * We need to temporarily regain original privileges in order for the
297: * child to chroot().
298: */
299: if (seteuid(0) == -1) {
300: cvs_log(LP_ERRNO, "failed to regain privileges");
1.18 ! jfb 301: return (NULL);
1.1 jfb 302: }
303:
304: pid = fork();
305: if (pid == -1) {
306: cvs_log(LP_ERRNO, "failed to fork child");
307: (void)close(svec[0]);
308: (void)close(svec[1]);
1.18 ! jfb 309: return (NULL);
1.1 jfb 310: }
311:
312: if (pid == 0) {
313: cvsd_privfd = svec[1];
314: (void)close(svec[0]);
315:
1.18 ! jfb 316: /*
! 317: * Move the accepted socket to descriptor 3, where the child
! 318: * expects it to be. This could become troublesome if the
! 319: * descriptor is already taken, but then again, the child
! 320: * shouldn't have access to other descriptors except the
! 321: * connection and its side of the socket pair it shares with
! 322: * the parent.
! 323: */
! 324: if (dup2(sock, CVSD_CHILD_SOCKFD) == -1) {
! 325: cvs_log(LP_ERRNO, "failed to dup child socket");
! 326: exit(EX_OSERR);
! 327: }
! 328: (void)close(sock);
! 329:
! 330: argc = 0;
! 331: argv[argc++] = CVSD_PATH_CHILD;
! 332: argv[argc++] = "-r";
! 333: argv[argc++] = cvsd_root;
! 334: if (cvsd_uid != 0) {
! 335: snprintf(ubuf, sizeof(ubuf), "%d", cvsd_uid);
! 336: argv[argc++] = "-u";
! 337: argv[argc++] = ubuf;
! 338: }
! 339: if (cvsd_gid != 0) {
! 340: snprintf(gbuf, sizeof(gbuf), "%d", cvsd_gid);
! 341: argv[argc++] = "-g";
! 342: argv[argc++] = gbuf;
! 343: }
! 344: argv[argc] = NULL;
! 345:
! 346: execv(CVSD_PATH_CHILD, argv);
! 347: err(1, "FUCK");
! 348: exit(EX_OSERR);
1.1 jfb 349: }
350:
351: cvs_log(LP_INFO, "spawning child %d", pid);
352:
1.18 ! jfb 353: (void)close(svec[1]);
! 354:
! 355: if (seteuid(cvsd_uid) == -1)
1.1 jfb 356: cvs_log(LP_ERRNO, "failed to redrop privs");
357:
358: chp = (struct cvsd_child *)malloc(sizeof(*chp));
359: if (chp == NULL) {
1.18 ! jfb 360: /* XXX kill child */
1.1 jfb 361: cvs_log(LP_ERRNO, "failed to allocate child data");
1.18 ! jfb 362: return (NULL);
1.1 jfb 363: }
364:
365: chp->ch_pid = pid;
366: chp->ch_sock = svec[0];
1.3 jfb 367: chp->ch_state = CVSD_ST_IDLE;
368:
369: TAILQ_INSERT_TAIL(&cvsd_children, chp, ch_list);
1.7 jfb 370: cvsd_chnum++;
1.3 jfb 371:
1.18 ! jfb 372: return (chp);
1.3 jfb 373: }
374:
375:
376: /*
377: * cvsd_child_reap()
378: *
1.7 jfb 379: * Wait for a child's status and perform the proper actions depending on it.
380: * If the child has exited or has been terminated by a signal, it will be
1.18 ! jfb 381: * removed from the list.
1.3 jfb 382: * Returns 0 on success, or -1 on failure.
383: */
384: int
1.7 jfb 385: cvsd_child_reap(void)
1.3 jfb 386: {
1.7 jfb 387: pid_t pid;
388: int status;
389: struct cvsd_child *ch;
1.3 jfb 390:
1.7 jfb 391: pid = wait(&status);
392: if (pid == -1) {
393: cvs_log(LP_ERRNO, "failed to wait for child");
394: return (-1);
395: }
396:
397: TAILQ_FOREACH(ch, &cvsd_children, ch_list) {
398: if (ch->ch_pid == pid) {
399: if (WIFEXITED(status)) {
400: cvs_log(LP_WARN,
401: "child %d exited with status %d",
402: pid, WEXITSTATUS(status));
1.13 deraadt 403: } else if (WIFSIGNALED(status)) {
1.7 jfb 404: cvs_log(LP_WARN,
405: "child %d terminated with signal %d",
406: pid, WTERMSIG(status));
1.13 deraadt 407: } else {
1.7 jfb 408: cvs_log(LP_ERR, "HOLY SHIT!");
409: }
410:
411: signal(SIGCHLD, SIG_IGN);
412: TAILQ_REMOVE(&cvsd_children, ch, ch_list);
413: cvsd_chnum--;
1.8 jfb 414: signal(SIGCHLD, cvsd_sighdlr);
1.7 jfb 415:
416: break;
417: }
418: }
419:
1.3 jfb 420: return (0);
421: }
422:
423:
424: /*
1.1 jfb 425: * cvsd_parent_loop()
426: *
427: * Main loop of the parent cvsd process, which listens on its end of the
1.3 jfb 428: * local socket for requests from the cvs(1) program and on any outstanding
429: * messages from the children.
1.1 jfb 430: */
431: static void
432: cvsd_parent_loop(void)
433: {
1.3 jfb 434: int cfd, timeout, ret;
1.1 jfb 435: nfds_t nfds, i;
436: struct pollfd *pfd;
437: struct cvsd_child *chp;
438:
439: nfds = 0;
440: timeout = INFTIM;
1.3 jfb 441: pfd = NULL;
1.1 jfb 442:
443: for (;;) {
1.10 jfb 444: if (!cvsd_running)
1.3 jfb 445: break;
446:
1.10 jfb 447: if (cvsd_restart) {
1.3 jfb 448: /* restart server */
449: }
1.7 jfb 450:
451: if (cvsd_sigchld) {
452: cvsd_sigchld = 0;
453: cvsd_child_reap();
454: }
1.8 jfb 455: if (cvsd_siginfo) {
456: cvsd_siginfo = 0;
457: cvsd_report();
458: }
1.7 jfb 459:
1.3 jfb 460: nfds = cvsd_chnum + 1;
1.1 jfb 461: pfd = (struct pollfd *)realloc(pfd,
462: nfds * sizeof(struct pollfd));
463: if (pfd == NULL) {
464: cvs_log(LP_ERRNO, "failed to reallocate polling data");
465: return;
466: }
467:
1.3 jfb 468: pfd[0].fd = cvsd_sock;
469: pfd[0].events = POLLIN;
470: pfd[0].revents = 0;
471: i = 1;
1.1 jfb 472: TAILQ_FOREACH(chp, &cvsd_children, ch_list) {
473: pfd[i].fd = chp->ch_sock;
474: pfd[i].events = POLLIN;
475: pfd[i].revents = 0;
476: i++;
477:
1.3 jfb 478: if (i == nfds) /* just a precaution */
1.1 jfb 479: break;
480: }
481:
482: ret = poll(pfd, nfds, timeout);
483: if (ret == -1) {
1.7 jfb 484: if (errno == EINTR)
485: continue;
1.1 jfb 486: cvs_log(LP_ERRNO, "poll error");
487: break;
488: }
489:
1.3 jfb 490: if (pfd[0].revents & (POLLERR|POLLNVAL)) {
491: cvs_log(LP_ERR, "poll error on request socket");
1.13 deraadt 492: } else if (pfd[0].revents & POLLIN) {
1.11 jfb 493: uid_t uid;
494: gid_t gid;
1.13 deraadt 495:
1.18 ! jfb 496: if ((cfd = cvsd_sock_accept(pfd[0].fd)) == -1)
! 497: continue;
! 498:
! 499: if ((chp = cvsd_child_fork(cfd)) == NULL) {
1.3 jfb 500: cvs_log(LP_ALERT,
501: "request queue not implemented");
502: break;
503: }
504:
1.11 jfb 505: if (getpeereid(cfd, &uid, &gid) < 0)
506: err(1, "failed to get UID");
1.3 jfb 507: if (cvsd_sendmsg(chp->ch_sock, CVSD_MSG_PASSFD,
508: &cfd, sizeof(cfd)) < 0)
509: break;
510:
511: /* mark the child as busy */
512: chp->ch_state = CVSD_ST_BUSY;
513: }
514:
1.1 jfb 515: chp = TAILQ_FIRST(&cvsd_children);
1.3 jfb 516: for (i = 1; i < nfds; i++) {
1.1 jfb 517: if (pfd[i].revents & (POLLERR|POLLNVAL)) {
518: cvs_log(LP_ERR,
519: "poll error on child socket (PID %d)",
520: chp->ch_pid);
1.13 deraadt 521: } else if (pfd[i].revents & POLLIN)
1.1 jfb 522: cvsd_msghdlr(chp, pfd[i].fd);
523:
524: chp = TAILQ_NEXT(chp, ch_list);
525: }
526:
527: }
1.7 jfb 528:
529: /* broadcast a shutdown message to children */
530: TAILQ_FOREACH(chp, &cvsd_children, ch_list) {
531: (void)cvsd_sendmsg(chp->ch_sock, CVSD_MSG_SHUTDOWN, NULL, 0);
532: }
1.1 jfb 533: }
534:
535:
536: /*
537: * cvsd_msghdlr()
1.3 jfb 538: *
539: * Handler for messages received from child processes.
540: * Returns 0 on success, or -1 on failure.
1.1 jfb 541: */
542: int
543: cvsd_msghdlr(struct cvsd_child *child, int fd)
544: {
545: uid_t uid;
546: ssize_t ret;
547: char rbuf[CVSD_MSG_MAXLEN];
548: struct group *gr;
549: struct passwd *pw;
550: struct iovec iov[2];
551: struct cvsd_msg msg;
552:
553: ret = read(fd, &msg, sizeof(msg));
554: if (ret == -1) {
555: cvs_log(LP_ERRNO, "failed to read CVS message");
556: return (-1);
1.13 deraadt 557: } else if (ret == 0) {
1.1 jfb 558: cvs_log(LP_WARN, "child closed socket pair");
559: return (0);
560: }
561:
562: if (msg.cm_len > 0) {
563: ret = read(fd, rbuf, msg.cm_len);
564: if (ret != (ssize_t)msg.cm_len) {
565: cvs_log(LP_ERR, "failed to read entire msg");
566: return (-1);
567: }
568: }
569:
570: /* setup the I/O vector for the reply */
571: iov[0].iov_base = &msg;
572: iov[0].iov_len = sizeof(msg);
573:
574: msg.cm_type = CVSD_MSG_ERROR;
575: msg.cm_len = 0;
576:
577: switch (msg.cm_type) {
578: case CVSD_MSG_GETUID:
579: rbuf[ret] = '\0';
1.14 tedu 580: cvs_log(LP_INFO, "getting UID for `%s'", rbuf);
1.1 jfb 581:
582: pw = getpwnam(rbuf);
583: if (pw != NULL) {
584: msg.cm_type = CVSD_MSG_UID;
585: msg.cm_len = sizeof(uid_t);
586: iov[1].iov_len = msg.cm_len;
587: iov[1].iov_base = &(pw->pw_uid);
588: }
589: break;
590: case CVSD_MSG_GETUNAME:
591: memcpy(&uid, rbuf, sizeof(uid));
1.14 tedu 592: cvs_log(LP_INFO, "getting username for UID %u", uid);
1.1 jfb 593: pw = getpwuid(uid);
594: if (pw != NULL) {
595: msg.cm_type = CVSD_MSG_UNAME;
596: msg.cm_len = strlen(pw->pw_name);
597: iov[1].iov_len = msg.cm_len;
598: iov[1].iov_base = pw->pw_name;
599: }
600: break;
1.3 jfb 601: case CVSD_MSG_GETGID:
602: rbuf[ret] = '\0';
1.14 tedu 603: cvs_log(LP_INFO, "getting GID for `%s'", rbuf);
1.3 jfb 604:
605: gr = getgrnam(rbuf);
606: if (gr != NULL) {
607: msg.cm_type = CVSD_MSG_GID;
608: msg.cm_len = sizeof(gid_t);
609: iov[1].iov_len = msg.cm_len;
610: iov[1].iov_base = &(gr->gr_gid);
611: }
612: break;
613: case CVSD_MSG_SETIDLE:
614: child->ch_state = CVSD_ST_IDLE;
615: break;
1.1 jfb 616: default:
617: cvs_log(LP_ERR, "unknown command type %u", msg.cm_type);
618: return (-1);
619: }
620:
621: ret = writev(fd, iov, 2);
622:
623: return (ret);
1.3 jfb 624: }
625:
626:
627: /*
628: * cvsd_set()
629: *
630: * Generic interface to set some of the parameters of the cvs server.
1.7 jfb 631: * When a string is set using cvsd_set(), the original string is copied into
632: * a new buffer.
1.3 jfb 633: * Returns 0 on success, or -1 on failure.
634: */
635: int
636: cvsd_set(int what, ...)
637: {
638: char *str;
1.12 pat 639: int error = 0;
1.3 jfb 640: va_list vap;
641:
1.9 jfb 642: str = NULL;
643:
1.3 jfb 644: va_start(vap, what);
645:
1.9 jfb 646: if ((what == CVSD_SET_ROOT) || (what == CVSD_SET_SOCK) ||
1.11 jfb 647: (what == CVSD_SET_USER) || (what == CVSD_SET_GROUP) ||
648: (what == CVSD_SET_MODDIR)) {
1.7 jfb 649: str = strdup(va_arg(vap, char *));
650: if (str == NULL) {
1.9 jfb 651: cvs_log(LP_ERRNO, "failed to set string");
1.12 pat 652: va_end(vap);
1.7 jfb 653: return (-1);
654: }
1.9 jfb 655: }
656:
657: switch (what) {
658: case CVSD_SET_ROOT:
1.7 jfb 659: if (cvsd_root != NULL)
660: free(cvsd_root);
1.3 jfb 661: cvsd_root = str;
662: break;
1.9 jfb 663: case CVSD_SET_SOCK:
664: if (cvsd_sock_path != NULL)
665: free(cvsd_sock_path);
666: cvsd_sock_path = str;
667: break;
668: case CVSD_SET_USER:
669: if (cvsd_user != NULL)
670: free(cvsd_user);
671: cvsd_user = str;
672: break;
673: case CVSD_SET_GROUP:
674: if (cvsd_group != NULL)
675: free(cvsd_group);
676: cvsd_group = str;
1.11 jfb 677: break;
678: case CVSD_SET_MODDIR:
679: if (cvsd_moddir != NULL)
680: free(cvsd_moddir);
681: cvsd_moddir = str;
1.9 jfb 682: break;
1.3 jfb 683: case CVSD_SET_CHMAX:
684: cvsd_chmax = va_arg(vap, int);
685: /* we should decrease the number of children accordingly */
686: break;
687: case CVSD_SET_ADDR:
1.7 jfb 688: /* this is more like an add than a set */
1.3 jfb 689: break;
690: default:
691: cvs_log(LP_ERR, "invalid field to set");
1.12 pat 692: error = -1;
693: break;
1.3 jfb 694: }
695:
696: va_end(vap);
697:
1.12 pat 698: return (error);
1.8 jfb 699: }
700:
701:
702: /*
703: * cvsd_report()
1.18 ! jfb 704: *
! 705: * Report about the current state of child processes on the repository.
1.8 jfb 706: */
707: static void
708: cvsd_report(void)
709: {
710: u_int nb_idle, nb_busy, nb_unknown;
711: struct cvsd_child *ch;
712:
713: nb_idle = 0;
714: nb_busy = 0;
715: nb_unknown = 0;
716:
717: signal(SIGCHLD, SIG_IGN);
718: TAILQ_FOREACH(ch, &cvsd_children, ch_list) {
719: if (ch->ch_state == CVSD_ST_IDLE)
720: nb_idle++;
721: else if (ch->ch_state == CVSD_ST_BUSY)
722: nb_busy++;
723: else if (ch->ch_state == CVSD_ST_UNKNOWN)
724: nb_unknown++;
725: }
726:
727: cvs_log(LP_WARN, "%u children, %u idle, %u busy, %u unknown",
728: cvsd_chnum, nb_idle, nb_busy, nb_unknown);
729:
730: TAILQ_FOREACH(ch, &cvsd_children, ch_list)
731: cvs_log(LP_WARN, "");
732: signal(SIGCHLD, cvsd_sighdlr);
1.1 jfb 733: }