Annotation of src/usr.bin/cvs/cvsd.c, Revision 1.4
1.1 jfb 1: /* $OpenBSD$ */
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: #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"
49: #include "cvsd.h"
50:
51:
52: static void cvsd_parent_loop (void);
53: static void cvsd_child_loop (void);
54: static int cvsd_privdrop (void);
55:
56:
57: extern char *__progname;
58:
59:
60:
61: int foreground = 0;
62:
1.3 jfb 63: volatile sig_atomic_t running = 0;
1.1 jfb 64: volatile sig_atomic_t restart = 0;
65:
66:
67: uid_t cvsd_uid = -1;
68: gid_t cvsd_gid = -1;
69:
70:
71: char *cvsd_root = NULL;
1.3 jfb 72: char *cvsd_conffile = CVSD_CONF;
1.1 jfb 73:
74:
75: static int cvsd_privfd = -1;
76:
77:
78:
79: static TAILQ_HEAD(,cvsd_child) cvsd_children;
80: static volatile sig_atomic_t cvsd_chnum = 0;
81: static volatile sig_atomic_t cvsd_chmin = CVSD_CHILD_DEFMIN;
82: static volatile sig_atomic_t cvsd_chmax = CVSD_CHILD_DEFMAX;
83:
84:
1.3 jfb 85: void usage (void);
86: void sighup_handler (int);
87: void sigint_handler (int);
88: void sigchld_handler (int);
89: int cvsd_msghdlr (struct cvsd_child *, int);
90:
91:
1.1 jfb 92: /*
93: * sighup_handler()
94: *
95: * Handler for the SIGHUP signal.
96: */
97:
98: void
99: sighup_handler(int signo)
100: {
101: restart = 1;
102: }
103:
104:
105: /*
106: * sigint_handler()
107: *
108: * Handler for the SIGINT signal.
109: */
110:
111: void
112: sigint_handler(int signo)
113: {
114: }
115:
116:
117: /*
118: * sigchld_handler()
119: *
120: */
121:
122: void
123: sigchld_handler(int signo)
124: {
125: int status;
126:
127: wait(&status);
128:
129: }
130:
131:
132: /*
133: * usage()
134: *
135: * Display program usage.
136: */
137:
138: void
139: usage(void)
140: {
141: fprintf(stderr,
1.3 jfb 142: "Usage: %s [-dfpv] [-c config] [-r root] [-s path]\n"
1.1 jfb 143: "\t-d\t\tStart the server in debugging mode (very verbose)\n"
144: "\t-f\t\tStay in foreground instead of becoming a daemon\n"
145: "\t-p\t\tPerform permission and ownership check on the repository\n"
146: "\t-r root\tUse <root> as the root directory of the repository\n"
147: "\t-s path\tUse <path> as the path for the CVS server socket\n"
148: "\t-v\t\tBe verbose\n",
149: __progname);
150: }
151:
152:
153: int
154: main(int argc, char **argv)
155: {
156: u_int i;
157: int ret, checkrepo;
158: struct passwd *pwd;
159: struct group *grp;
160:
161: checkrepo = 0;
162:
163: if (cvs_log_init(LD_STD|LD_SYSLOG, LF_PID) < 0)
164: err(1, "failed to initialize logging mechanism");
165:
1.3 jfb 166: while ((ret = getopt(argc, argv, "a:c:dfpr:s:v")) != -1) {
1.1 jfb 167: switch (ret) {
1.3 jfb 168: case 'c':
169: cvsd_conffile = optarg;
1.1 jfb 170: break;
171: case 'd':
172: cvs_log_filter(LP_FILTER_UNSET, LP_DEBUG);
173: cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
174: break;
175: case 'f':
176: foreground = 1;
177: break;
178: case 'p':
179: checkrepo = 1;
180: break;
181: case 'r':
182: cvsd_root = optarg;
183: break;
184: case 's':
185: cvsd_sock_path = optarg;
186: break;
187: case 'v':
188: cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
189: break;
190: default:
191: usage();
192: exit(EX_USAGE);
193: }
194: }
195:
196: argc -= optind;
197: argv += optind;
198:
1.3 jfb 199: if (cvs_conf_read(cvsd_conffile) < 0)
200: errx(1, "error parsing configuration file `%s'", cvsd_conffile);
1.1 jfb 201:
202: if (cvsd_root == NULL)
203: errx(1, "no CVS root directory specified");
204:
205: if (argc > 0)
206: errx(EX_USAGE, "unrecognized trailing arguments");
207:
208: TAILQ_INIT(&cvsd_children);
209:
210: pwd = getpwnam(CVSD_USER);
211: if (pwd == NULL)
212: err(EX_NOUSER, "failed to get user `%s'", CVSD_USER);
213:
214: grp = getgrnam(CVSD_GROUP);
215: if (grp == NULL)
216: err(EX_NOUSER, "failed to get group `%s'", CVSD_GROUP);
217:
218: cvsd_uid = pwd->pw_uid;
219: cvsd_gid = grp->gr_gid;
220:
221: signal(SIGHUP, sighup_handler);
222: signal(SIGINT, sigint_handler);
223: signal(SIGQUIT, sigint_handler);
224: signal(SIGTERM, sigint_handler);
225:
226: if (!foreground && daemon(0, 0) == -1) {
227: cvs_log(LP_ERRNO, "failed to become a daemon");
228: exit(EX_OSERR);
229: }
230:
231: if (cvsd_sock_open() < 0) {
232: exit(1);
233: }
234:
235: if (setegid(cvsd_gid) == -1) {
236: cvs_log(LP_ERRNO, "failed to drop group privileges");
237: exit(EX_OSERR);
238: }
239: if (seteuid(cvsd_uid) == -1) {
240: cvs_log(LP_ERRNO, "failed to drop user privileges");
241: exit(EX_OSERR);
242: }
243:
244: if (checkrepo && cvsd_checkperms("/") != 0) {
245: cvs_log(LP_ERR,
246: "exiting due to permission errors on repository");
247: exit(1);
248: }
249:
250: /* spawn the initial pool of children */
1.3 jfb 251: for (i = 0; i < (u_int)cvsd_chmin; i++) {
252: ret = cvsd_child_fork(NULL);
1.1 jfb 253: if (ret == -1) {
254: cvs_log(LP_ERR, "failed to spawn child");
255: exit(EX_OSERR);
256: }
257: }
258:
1.3 jfb 259: cvsd_parent_loop();
1.1 jfb 260:
261: cvs_log(LP_NOTICE, "shutting down");
262: cvs_log_cleanup();
263:
264: cvsd_sock_close();
265:
266: return (0);
267: }
268:
269:
270: /*
271: * cvsd_privdrop()
272: *
273: * Drop privileges.
274: */
275:
276: int
277: cvsd_privdrop(void)
278: {
279: cvs_log(LP_INFO, "dropping privileges to %s:%s", CVSD_USER,
280: CVSD_GROUP);
1.2 jfb 281: if (setgid(cvsd_gid) == -1) {
1.1 jfb 282: cvs_log(LP_ERRNO, "failed to drop group privileges to %s",
283: CVSD_GROUP);
284: return (-1);
285: }
286:
1.2 jfb 287: if (setuid(cvsd_uid) == -1) {
1.1 jfb 288: cvs_log(LP_ERRNO, "failed to drop user privileges to %s",
289: CVSD_USER);
290: return (-1);
291: }
292:
293: return (0);
294: }
295:
296:
297: /*
298: * cvsd_checkperms()
299: *
300: * Check permissions on the CVS repository and log warnings for any
301: * weird of loose permissions.
302: * Returns the number of warnings on success, or -1 on failure.
303: */
304:
305: int
306: cvsd_checkperms(const char *path)
307: {
308: int fd, nbwarn, ret;
309: mode_t fmode;
310: long base;
311: void *dp, *endp;
312: char buf[1024], spath[MAXPATHLEN];
313: struct stat st;
314: struct dirent *dep;
315:
316: nbwarn = 0;
317:
318: cvs_log(LP_DEBUG, "checking permissions on `%s'", path);
319:
320: if (stat(path, &st) == -1) {
321: cvs_log(LP_ERRNO, "failed to stat `%s'", path);
322: return (-1);
323: }
324:
325: if (S_ISDIR(st.st_mode))
326: fmode = CVSD_DPERM;
327: else
328: fmode = CVSD_FPERM;
329:
330: if (st.st_uid != cvsd_uid) {
331: cvs_log(LP_WARN, "owner of `%s' is not %s", path, CVSD_USER);
332: nbwarn++;
333: }
334:
335: if (st.st_gid != cvsd_gid) {
336: cvs_log(LP_WARN, "group of `%s' is not %s", path, CVSD_GROUP);
337: nbwarn++;
338: }
339:
340: if (st.st_mode & S_IWGRP) {
341: cvs_log(LP_WARN, "file `%s' is group-writable", path,
342: fmode);
343: nbwarn++;
344: }
345:
346: if (st.st_mode & S_IWOTH) {
347: cvs_log(LP_WARN, "file `%s' is world-writable", path,
348: fmode);
349: nbwarn++;
350: }
351:
352: if (S_ISDIR(st.st_mode)) {
353: fd = open(path, O_RDONLY, 0);
354: if (fd == -1) {
355: cvs_log(LP_ERRNO, "failed to open directory `%s'",
356: path);
357: return (nbwarn);
358: }
359: /* recurse */
360: ret = getdirentries(fd, buf, sizeof(buf), &base);
361: if (ret == -1) {
362: cvs_log(LP_ERRNO,
363: "failed to get directory entries for `%s'", path);
364: (void)close(fd);
365: return (nbwarn);
366: }
367:
368: dp = buf;
369: endp = buf + ret;
370:
371: while (dp < endp) {
372: dep = (struct dirent *)dp;
373: dp += dep->d_reclen;
374:
375: if ((dep->d_namlen == 1) && (dep->d_name[0] == '.'))
376: continue;
377: if ((dep->d_namlen == 2) && (dep->d_name[0] == '.') &&
378: (dep->d_name[1] == '.'))
379: continue;
380:
381: /* skip the CVSROOT directory */
382: if (strcmp(dep->d_name, CVS_PATH_ROOT) == 0)
383: continue;
384:
385: snprintf(spath, sizeof(spath), "%s/%s", path,
386: dep->d_name);
387: ret = cvsd_checkperms(spath);
388: if (ret == -1)
389: nbwarn++;
390: else
391: nbwarn += ret;
392: }
393: (void)close(fd);
394: }
395:
396:
397: return (nbwarn);
398: }
399:
400:
401: /*
1.3 jfb 402: * cvsd_child_fork()
1.1 jfb 403: *
404: * Fork a child process which chroots to the CVS repository's root directory.
405: * We need to temporarily regain privileges in order to chroot.
1.3 jfb 406: * If the <chpp> argument is not NULL, a reference to the newly created child
407: * structure will be returned.
408: * On success, returns 0 in the child process context, 1 in the parent's
409: * context, or -1 on failure.
1.1 jfb 410: */
411:
412: int
1.3 jfb 413: cvsd_child_fork(struct cvsd_child **chpp)
1.1 jfb 414: {
415: int svec[2];
416: pid_t pid;
417: struct cvsd_child *chp;
418:
1.3 jfb 419: if (cvsd_chnum == cvsd_chmax) {
420: cvs_log(LP_WARN, "child pool reached limit of processes");
421: return (-1);
422: }
423:
1.1 jfb 424: if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, svec) == -1) {
425: cvs_log(LP_ERRNO, "failed to create socket pair");
426: return (-1);
427: }
428:
429: /*
430: * We need to temporarily regain original privileges in order for the
431: * child to chroot().
432: */
433: if (seteuid(0) == -1) {
434: cvs_log(LP_ERRNO, "failed to regain privileges");
435: return (-1);
436: }
437:
438: pid = fork();
439: if (pid == -1) {
440: cvs_log(LP_ERRNO, "failed to fork child");
441: (void)close(svec[0]);
442: (void)close(svec[1]);
443: return (-1);
444: }
445:
446: if (pid == 0) {
447: cvsd_privfd = svec[1];
448: (void)close(svec[0]);
449:
450: cvs_log(LP_INFO, "changing root to %s", cvsd_root);
451: if (chroot(cvsd_root) == -1) {
452: cvs_log(LP_ERRNO, "failed to chroot to `%s'",
453: cvsd_root);
454: exit(EX_OSERR);
455: }
456: (void)chdir("/");
457:
1.2 jfb 458: if (cvsd_privdrop() < 0)
1.1 jfb 459: exit(EX_OSERR);
460:
461: setproctitle("%s [child %d]", __progname, getpid());
462:
463: cvsd_child_loop();
464:
465: return (0);
466: }
467:
468: cvs_log(LP_INFO, "spawning child %d", pid);
469:
470: if (seteuid(cvsd_uid) == -1) {
471: cvs_log(LP_ERRNO, "failed to redrop privs");
472: return (-1);
473: }
474:
475: chp = (struct cvsd_child *)malloc(sizeof(*chp));
476: if (chp == NULL) {
477: cvs_log(LP_ERRNO, "failed to allocate child data");
478: return (-1);
479: }
480:
481: chp->ch_pid = pid;
482: chp->ch_sock = svec[0];
1.3 jfb 483: chp->ch_state = CVSD_ST_IDLE;
484:
485: TAILQ_INSERT_TAIL(&cvsd_children, chp, ch_list);
486:
487: if (chpp != NULL)
488: *chpp = chp;
1.1 jfb 489: (void)close(svec[1]);
1.3 jfb 490: return (1);
491: }
492:
493:
494: /*
495: * cvsd_child_reap()
496: *
497: * Returns 0 on success, or -1 on failure.
498: */
499:
500: int
501: cvsd_child_reap(struct cvsd_child *ch)
502: {
503:
504:
505: return (0);
506: }
507:
508:
509: /*
510: * cvsd_child_get()
511: *
512: * Find a child process in idle state and return a pointer to the child's
513: * structure. If there are no available child processes, a new one will be
514: * created unless the number of children has attained the maximum, in which
515: * case NULL is returned.
516: */
517:
518: struct cvsd_child*
519: cvsd_child_get(void)
520: {
521: struct cvsd_child *chp;
1.1 jfb 522:
1.3 jfb 523: TAILQ_FOREACH(chp, &cvsd_children, ch_list)
524: if (chp->ch_state == CVSD_ST_IDLE)
525: return (chp);
526:
527: /* no available child, attempt to fork a new one */
528: chp = NULL;
529: if ((cvsd_chnum < cvsd_chmax) && (cvsd_child_fork(&chp) < 0))
530: return (NULL);
531:
532: return (chp);
1.1 jfb 533: }
534:
535:
1.3 jfb 536:
1.1 jfb 537: /*
538: * cvsd_parent_loop()
539: *
540: * Main loop of the parent cvsd process, which listens on its end of the
1.3 jfb 541: * local socket for requests from the cvs(1) program and on any outstanding
542: * messages from the children.
1.1 jfb 543: */
544:
545: static void
546: cvsd_parent_loop(void)
547: {
1.3 jfb 548: int cfd, timeout, ret;
1.1 jfb 549: nfds_t nfds, i;
550: struct pollfd *pfd;
551: struct cvsd_child *chp;
552:
553: nfds = 0;
554: timeout = INFTIM;
1.3 jfb 555: pfd = NULL;
1.1 jfb 556:
557: for (;;) {
1.3 jfb 558: if (!running)
559: break;
560:
561: if (restart) {
562: /* restart server */
563: }
564: nfds = cvsd_chnum + 1;
1.1 jfb 565: pfd = (struct pollfd *)realloc(pfd,
566: nfds * sizeof(struct pollfd));
567: if (pfd == NULL) {
568: cvs_log(LP_ERRNO, "failed to reallocate polling data");
569: return;
570: }
571:
1.3 jfb 572: pfd[0].fd = cvsd_sock;
573: pfd[0].events = POLLIN;
574: pfd[0].revents = 0;
575: i = 1;
1.1 jfb 576: TAILQ_FOREACH(chp, &cvsd_children, ch_list) {
577: pfd[i].fd = chp->ch_sock;
578: pfd[i].events = POLLIN;
579: pfd[i].revents = 0;
580: i++;
581:
1.3 jfb 582: if (i == nfds) /* just a precaution */
1.1 jfb 583: break;
584: }
585:
586: ret = poll(pfd, nfds, timeout);
587: if (ret == -1) {
588: cvs_log(LP_ERRNO, "poll error");
589: break;
590: }
591:
1.3 jfb 592: if (pfd[0].revents & (POLLERR|POLLNVAL)) {
593: cvs_log(LP_ERR, "poll error on request socket");
594: }
595: else if (pfd[0].revents & POLLIN) {
596: cfd = cvsd_sock_accept(pfd[0].fd);
597: if (cfd == -1)
598: chp = cvsd_child_get();
599: if (chp == NULL) {
600: cvs_log(LP_ALERT,
601: "request queue not implemented");
602: break;
603: }
604:
605: if (cvsd_sendmsg(chp->ch_sock, CVSD_MSG_PASSFD,
606: &cfd, sizeof(cfd)) < 0)
607: break;
608:
609: /* mark the child as busy */
610: chp->ch_state = CVSD_ST_BUSY;
611: }
612:
1.1 jfb 613: chp = TAILQ_FIRST(&cvsd_children);
1.3 jfb 614: for (i = 1; i < nfds; i++) {
1.1 jfb 615: if (pfd[i].revents & (POLLERR|POLLNVAL)) {
616: cvs_log(LP_ERR,
617: "poll error on child socket (PID %d)",
618: chp->ch_pid);
619: }
1.3 jfb 620: else if (pfd[i].revents & POLLIN)
1.1 jfb 621: cvsd_msghdlr(chp, pfd[i].fd);
622:
623: chp = TAILQ_NEXT(chp, ch_list);
624: }
625:
626: }
627: }
628:
629:
630: /*
631: * cvsd_child_loop()
632: *
633: */
634:
635: static void
636: cvsd_child_loop(void)
637: {
638: int ret, timeout;
639: struct pollfd pfd[1];
640:
641: pfd[0].fd = cvsd_privfd;
642: pfd[0].events = POLLIN;
643: timeout = INFTIM;
644:
645: for (;;) {
646: ret = poll(pfd, 1, timeout);
647: if (ret == -1) {
648: }
649: else if (ret == 0) {
650: cvs_log(LP_INFO, "parent process closed descriptor");
651: break;
652: }
653: cvs_log(LP_INFO, "polling");
654:
1.3 jfb 655: if (pfd[0].revents & (POLLERR|POLLNVAL)) {
656: cvs_log(LP_ERR, "poll error");
657: break;
658: }
1.1 jfb 659: }
660:
661: exit(0);
662: }
663:
664:
665: /*
666: * cvsd_msghdlr()
1.3 jfb 667: *
668: * Handler for messages received from child processes.
669: * Returns 0 on success, or -1 on failure.
1.1 jfb 670: */
671:
672: int
673: cvsd_msghdlr(struct cvsd_child *child, int fd)
674: {
675: uid_t uid;
676: ssize_t ret;
677: char rbuf[CVSD_MSG_MAXLEN];
678: struct group *gr;
679: struct passwd *pw;
680: struct iovec iov[2];
681: struct cvsd_msg msg;
682:
683: ret = read(fd, &msg, sizeof(msg));
684: if (ret == -1) {
685: cvs_log(LP_ERRNO, "failed to read CVS message");
686: return (-1);
687: }
688: else if (ret == 0) {
689: cvs_log(LP_WARN, "child closed socket pair");
690: return (0);
691: }
692:
693: if (msg.cm_len > 0) {
694: ret = read(fd, rbuf, msg.cm_len);
695: if (ret != (ssize_t)msg.cm_len) {
696: cvs_log(LP_ERR, "failed to read entire msg");
697: return (-1);
698: }
699: }
700:
701: /* setup the I/O vector for the reply */
702: iov[0].iov_base = &msg;
703: iov[0].iov_len = sizeof(msg);
704:
705: msg.cm_type = CVSD_MSG_ERROR;
706: msg.cm_len = 0;
707:
708: switch (msg.cm_type) {
709: case CVSD_MSG_GETUID:
710: rbuf[ret] = '\0';
711: cvs_log(LP_INFO, "getting UID for `%s'", rbuf);
712:
713: pw = getpwnam(rbuf);
714: if (pw != NULL) {
715: msg.cm_type = CVSD_MSG_UID;
716: msg.cm_len = sizeof(uid_t);
717: iov[1].iov_len = msg.cm_len;
718: iov[1].iov_base = &(pw->pw_uid);
719: }
720: break;
721: case CVSD_MSG_GETUNAME:
722: memcpy(&uid, rbuf, sizeof(uid));
723: cvs_log(LP_INFO, "getting username for UID %u", uid);
724: pw = getpwuid(uid);
725: if (pw != NULL) {
726: msg.cm_type = CVSD_MSG_UNAME;
727: msg.cm_len = strlen(pw->pw_name);
728: iov[1].iov_len = msg.cm_len;
729: iov[1].iov_base = pw->pw_name;
730: }
731: break;
1.3 jfb 732: case CVSD_MSG_GETGID:
733: rbuf[ret] = '\0';
734: cvs_log(LP_INFO, "getting GID for `%s'", rbuf);
735:
736: gr = getgrnam(rbuf);
737: if (gr != NULL) {
738: msg.cm_type = CVSD_MSG_GID;
739: msg.cm_len = sizeof(gid_t);
740: iov[1].iov_len = msg.cm_len;
741: iov[1].iov_base = &(gr->gr_gid);
742: }
743: break;
744: case CVSD_MSG_SETIDLE:
745: child->ch_state = CVSD_ST_IDLE;
746: break;
1.1 jfb 747: default:
748: cvs_log(LP_ERR, "unknown command type %u", msg.cm_type);
749: return (-1);
750: }
751:
752: ret = writev(fd, iov, 2);
753:
754: return (ret);
1.3 jfb 755: }
756:
757:
758: /*
759: * cvsd_set()
760: *
761: * Generic interface to set some of the parameters of the cvs server.
762: * Returns 0 on success, or -1 on failure.
763: */
764:
765: int
766: cvsd_set(int what, ...)
767: {
768: char *str;
769: va_list vap;
770:
771: va_start(vap, what);
772:
773: switch (what) {
774: case CVSD_SET_ROOT:
775: str = va_arg(vap, char *);
776: cvsd_root = str;
777: break;
778: case CVSD_SET_CHMIN:
779: cvsd_chmin = va_arg(vap, int);
780: /* we should increase the number of children accordingly */
781: break;
782: case CVSD_SET_CHMAX:
783: cvsd_chmax = va_arg(vap, int);
784: /* we should decrease the number of children accordingly */
785: break;
786: case CVSD_SET_ADDR:
787: /* this is more like and add than a set */
788: break;
789: case CVSD_SET_SOCK:
790: cvsd_sock_path = va_arg(vap, char *);
791: if (cvsd_sock_open() < 0)
792: return (-1);
793: break;
794: default:
795: cvs_log(LP_ERR, "invalid field to set");
796: return (-1);
797: }
798:
799: va_end(vap);
800:
801: return (0);
1.1 jfb 802: }