2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: svcmain.c /main/10 1998/04/06 13:13:49 mgreess $ */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company
26 * (c) Copyright 1993, 1994 International Business Machines Corp.
27 * (c) Copyright 1993, 1994 Novell, Inc.
28 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
32 #define _POSIX_C_SOURCE 2
35 #include <EUSCompat.h>
42 #include <sys/resource.h>
45 #include <netinet/in.h>
46 #endif /* _NETINET_IN_H */
49 #if defined(SunOS) || defined(USL) || defined(__uxp__)
50 #include <netconfig.h>
52 #include <sys/stropts.h>
54 #endif /* SunOS || USL || __uxp__ */
55 #include <sys/param.h>
60 #include <sys/signal.h>
63 #include "rpcextras.h"
65 #include "cmscalendar.h"
71 #define S_IRWXU (S_IRUSR|S_IWUSR|S_IXUSR)
74 #define S_IRWXG (S_IRGRP|S_IWGRP|S_IXGRP)
77 #define S_IRWXO (S_IROTH|S_IWOTH|S_IXOTH)
80 #define S_MASK (S_INPUT|S_HIPRI|S_ERROR|S_HANGUP)
83 static int standalone; /* default is 0 */
84 static int received_sighup = 0; /* 1 means we get SIGHUP */
85 static int rpc_in_process = 0; /* 1 means processing client request */
86 static int garbage_collection_time = 240; /* in min; default time is 4:00am */
94 * get garbage collection time
95 * the given string should be in the format hhmm
96 * where hh is 0 - 23 and mm is 00 - 59
99 _GetGtime(char *timestr)
101 int hour, minute, len, i;
106 if ((len = strlen(timestr)) > 4)
109 for (i = 0; i < len; i++) {
110 if (timestr[i] < '0' || timestr[i] > '9')
114 minute = atoi(×tr[len - 2]);
115 timestr[len - 2] = '\0';
116 hour = atoi(timestr);
118 if (hour > 23 || minute > 59)
121 garbage_collection_time = hour * 60 + minute;
126 fprintf(stderr, "The time specified is invalid.\n");
131 parse_args(int argc, char **argv)
135 if (pgname = strrchr (argv[0], '/'))
140 while ((opt = getopt (argc, argv, "dsg:")) != -1)
151 if (_GetGtime(optarg))
164 * rpc.cmsd gets started by the inetd.
165 * On AIX inetd requires that two arguments be supplied to the RPC
166 * programs as follows (from the inetd.conf man page):
168 * ServerArgs Specifies the command line arguments that the
169 * inetd daemon should use to execute the server. The maximum number
170 * of arguments is five. The first argument specifies the name of the
171 * server used. If the SocketType parameter is sunrpc_tcp or
172 * sunrpc_udp, * the second argument specifies the program name and
173 * the third argument specifies the version of the program. For
174 * services that the inetd daemon provides internally, this field
178 else if (optind == 1 && argc >= 3)
186 argv_r = (char **) malloc(argc * sizeof(char *));
189 for (i=optind+2, j=1; i<argc; i++,j++)
191 parse_args(argc-2, argv_r);
193 free((void *) argv_r);
199 fprintf (stderr, "Usage: %s [-d] [-s] [-g hhmm]\n", pgname);
206 char *dir = _DtCMS_DEFAULT_DIR;
215 "%s: must be run in super-user mode! Exited.\n",
221 if (stat(dir, &info))
223 /* if directory does not exist, create the directory */
224 if ((errno != ENOENT) || mkdir(dir, S_IRWXU|S_IRWXG|S_IRWXO))
227 sprintf(msgbuf, "%s: cannot create %s.\n%s: %s",
228 pgname, dir, pgname, "System error");
230 sprintf(msgbuf, "%s: cannot access %s.\n%s: %s",
231 pgname, dir, pgname, "System error");
238 /* if dir is just created, we need to do chmod and chown.
239 * Otherwise, only do chmod and/or chown if permssion and/or
240 * ownership is wrong.
242 mode = S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
244 if (create_dir || info.st_mode != (mode | S_IFDIR)) {
246 /* set directory permission to be "rwxrwsrwt" */
247 if (chmod(dir, mode)) {
248 sprintf(msgbuf, "%s: Permission on %s%s\n%s%s\n%s%s",
250 " is wrong but cannot be corrected.", pgname,
251 ": This might happen if you are mounting the directory.",
252 pgname, ": System error");
260 if (create_dir || info.st_uid!=daemon_uid || info.st_gid!=daemon_gid) {
261 /* set directory ownership to: owner = 1, group = 1 */
262 if (chown(dir, daemon_uid, daemon_gid)) {
263 sprintf(msgbuf, "%s: Ownership on %s%s\n%s%s\n%s%s",
265 " is wrong but cannot be corrected.", pgname,
266 ": This might happen if you are mounting the directory.",
267 pgname, ": System error");
275 /* Change current directory, so core file can be dumped. */
276 if(-1 == chdir (dir)) {
277 perror(strerror(errno));
282 * send a SIGHUP signal to the rpc.cmsd that is already running
289 pid_t pid, mypid = getpid();
290 extern FILE *popen(const char *, const char *);
291 extern int pclose(FILE *);
293 sprintf(buf, "ps -e|grep rpc.cmsd|grep -v grep");
295 if ((fp = popen(buf, "r")) == NULL) {
297 fprintf(stderr, "rpc.cmsd: popen failed\n");
299 while (fgets(buf, sizeof(buf), fp) != NULL) {
300 if ((pid = atol(buf)) != mypid) {
301 if (kill(pid, SIGHUP))
302 perror("rpc.cmsd: failed to send SIGHUP");
304 fprintf(stderr, "rpc.cmsd: %s %ld\n",
305 "sent SIGHUP to", (long)pid);
313 * We only allow one rpc.cmsd to run on each machine.
318 char *dir = _DtCMS_DEFAULT_DIR;
319 char buff [MAXPATHLEN];
324 locker.l_type = F_WRLCK;
331 strcat (buff, "/.lock.");
334 * /var/spool might be mounted. Use .lock.hostname to
335 * prevent more than one cms running in each host.
337 strcat(buff, _DtCmGetLocalHost());
339 fd = open(buff, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
347 * Note, we have to use flock() instead of lockf() because cms process
348 * is run in each host.
351 if (fcntl (fd, F_SETLK, &locker) != 0)
353 if (flock (fd, LOCK_EX|LOCK_NB) != 0)
360 if (error != EWOULDBLOCK && error != EACCES) {
362 perror ("rpc.cmsd: failed to lock lockfile");
363 fprintf(stderr, "error = %d\n", error);
368 fprintf(stderr, "rpc.cmsd: %s\n",
369 "lock_it failed due to another process");
371 /* cms has been running.... */
380 program(struct svc_req *rqstp, register SVCXPRT *transp)
383 char *argument = NULL;
384 program_handle ph = getph();
385 struct rpcgen_table *proc;
387 /* set rpc_in_process so that sighup handler won't exit right away */
390 /* first do some bounds checking: */
391 if (rqstp->rq_vers >= ph->nvers) {
392 svcerr_noproc(transp);
395 if (ph->prog[rqstp->rq_vers].nproc == 0) {
396 svcerr_noproc(transp);
399 if (rqstp->rq_proc >= ph->prog[rqstp->rq_vers].nproc) {
400 svcerr_noproc(transp);
404 if (rqstp->rq_proc == NULLPROC) {
405 if (debug) fprintf(stderr, "rpc.cmsd: ping\n");
406 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL);
410 /* assert - the program number, version and proc numbers are valid */
411 proc = &(ph->prog[rqstp->rq_vers].vers[rqstp->rq_proc]);
412 argument = (char*)calloc(proc->len_arg, sizeof(char));
413 if (!svc_getargs(transp, proc->xdr_arg, argument)) {
414 svcerr_decode(transp);
418 result = (*proc->proc)(argument, rqstp);
419 if (result != NULL && !svc_sendreply(transp, proc->xdr_res, result)) {
420 svcerr_systemerr(transp);
423 if (!svc_freeargs(transp, proc->xdr_arg, argument)) {
424 (void)fprintf(stderr, "unable to free arguments");
432 /* exit if we have received the SIGHUP signal */
433 if (received_sighup == 1) {
435 fprintf(stderr, "rpc.cmsd: received SIGHUP, %s",
436 "exiting after finished processing\n");
442 * Signal handler for SIGHUP.
443 * If we are in the middle of processing a client request,
444 * finish processing before we exit.
447 sighup_handler(int sig_num)
450 fprintf(stderr, "rpc.cmsd: sighup received\n");
452 if (rpc_in_process == 0) {
454 fprintf(stderr, "rpc.cmsd: exit from sighup_handler\n");
458 fprintf(stderr, "rpc.cmsd: set received_sighup to 1\n");
464 * garbage_collection_time (in min) is the time to do garbage collection
466 * This routine returns the difference between the first garbage collection
467 * time and now so that the calling routine can set the alarm.
470 _GetFirstGarbageCollectionTime()
472 int n=0, midnight=0, gtime=0;
476 /* try today first */
477 midnight = next_ndays(n, 0);
478 gtime = next_nmins(midnight, garbage_collection_time);
481 /* the first garbage collection will be done tomorrow */
482 midnight = next_ndays(n, 1);
483 gtime = next_nmins(midnight, garbage_collection_time);
493 extern void garbage_collect();
494 extern void debug_switch();
496 #if defined(SVR4) && !defined(linux)
497 extern void (*sigset(int, void (*)(int)))(int);
498 sigset(SIGUSR1, garbage_collect);
499 sigset(SIGALRM, garbage_collect);
500 sigset(SIGUSR2, debug_switch);
502 signal(SIGUSR1, garbage_collect);
503 signal(SIGALRM, garbage_collect);
504 signal(SIGUSR2, debug_switch);
507 next = _GetFirstGarbageCollectionTime();
508 alarm((unsigned) next);
511 main(int argc, char **argv)
514 program_handle ph = newph();
518 struct sockaddr_in saddr;
519 int asize = sizeof (saddr);
520 SVCXPRT *tcp_transp = (SVCXPRT *)-1;
521 SVCXPRT *udp_transp = (SVCXPRT *)-1;
524 #if defined(SunOS) || defined(USL) || defined(__uxp__)
525 struct netconfig *nconf_udp;
526 struct netconfig *nconf_tcp;
528 #if !defined(USL) || (defined(USL) && (OSMAJORVERSION > 1))
529 char mname[FMNAMESZ+1];
531 #endif /* SunOS || USL */
533 pw = (struct passwd *)getpwnam("daemon");
534 gr = (struct group *)getgrnam("daemon");
536 daemon_uid = pw->pw_uid;
540 daemon_gid = gr->gr_gid;
544 parse_args(argc, argv);
546 /* check to see if we are started by inetd */
547 if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
551 #if defined(SunOS) || defined(USL) || defined(__uxp__)
552 #if !defined(USL) || (defined(USL) && (OSMAJORVERSION > 1))
553 /* we need a TLI endpoint rather than a socket */
554 if (ioctl(0, I_LOOK, mname) != 0) {
555 perror("rpc.cmsd: ioctl failed to get module name");
558 if (strcmp(mname, "sockmod") == 0) {
559 /* Change socket fd to TLI fd */
560 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) {
561 perror("rpc.cmsd: ioctl I_POP/I_PUSH failed");
564 } else if (strcmp(mname, "timod") != 0) {
565 fprintf(stderr, "rpc.cmsd: fd 0 is not timod\n");
568 #else /* !USL || (USL && OSMAJORVERSION > 1) */
569 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) {
570 perror("rpc.cmsd: ioctl I_POP/I_PUSH failed");
573 #endif /* !USL || (USL && OSMAJORVERSION > 1) */
575 } else if (t_getinfo(0, &info) == 0) {
578 #endif /* SunOS || USL */
584 * if it is started by inetd, make stderr to be
588 if ((fd = open ("/dev/console", O_WRONLY)) >= 0) {
596 /* Set up private directory and switch euid/egid to daemon. */
600 /* Don't allow multiple cms processes running in the same host. */
601 if ((error = lock_it()) != 0 && !standalone) {
602 /* we are invoked by inetd but another rpc.cmsd
603 * is alreay running, so send SIGHUP to it
608 /* try to lock it again */
609 if (lock_it() != 0) {
611 fprintf(stderr, "cm: rpc.cmsd is still running\n");
615 } else if (error != 0) {
616 fprintf(stderr, "rpc.cmsd: rpc.cmsd is already running.\n");
620 /* use signal because we only need it once */
621 signal(SIGHUP, sighup_handler);
624 #if defined(SunOS) || defined(USL) || defined(__uxp__)
625 /* raise the soft limit of number of file descriptor */
626 /* this is to prevent the backend from running out of open file des */
627 getrlimit(RLIMIT_NOFILE, &rl);
628 rl.rlim_cur = (rl.rlim_max <= 256) ? rl.rlim_max : 256;
629 setrlimit(RLIMIT_NOFILE, &rl);
632 #if defined(SunOS) || defined(USL) || defined(__uxp__)
633 nconf_udp = getnetconfigent("udp");
634 nconf_tcp = getnetconfigent("tcp");
636 for (version = 0; version < ph->nvers; version++) {
637 /* don't register unsupported versions: */
638 if (ph->prog[version].nproc == 0) continue;
641 rpcb_unset(ph->program_num, version, NULL);
644 "rpc.cmsd: rpcb_unset for version %ld\n",
648 /* brought up by inetd, use fd 0 which must be a TLI fd */
649 if (udp_transp == (SVCXPRT *)-1) {
650 udp_transp = svc_tli_create(standalone ? RPC_ANYFD : 0,
651 nconf_udp, (struct t_bind*) NULL, 0, 0);
653 if (udp_transp == NULL) {
654 t_error("rtable_main.c: svc_tli_create(udp)");
659 if (svc_reg(udp_transp, ph->program_num, version, program,
660 standalone ? nconf_udp : NULL) == 0) {
661 t_error("rtable_main.c: svc_reg");
665 /* Set up tcp for calls that potentially return */
666 /* large amount of data. This transport is not */
667 /* registered with inetd so need to register it */
668 /* with rpcbind ourselves. */
670 rpcb_unset(ph->program_num, version, nconf_tcp);
672 if (tcp_transp == (SVCXPRT *)-1) {
673 tcp_transp = svc_tli_create(RPC_ANYFD, nconf_tcp,
674 (struct t_bind *)NULL, 0, 0);
676 if (tcp_transp == NULL) {
677 t_error("rtable_main.c: svc_til_create(tcp)");
682 if (svc_reg(tcp_transp, ph->program_num, version, program,
684 t_error("rtable_main.c: svc_reg(tcp)");
690 freenetconfigent(nconf_udp);
692 freenetconfigent(nconf_tcp);
696 for (version = 0; version < ph->nvers; version++) {
697 /* don't register unsupported versions: */
698 if (ph->prog[version].nproc == 0) continue;
703 (void) pmap_unset(ph->program_num, version);
705 if (udp_transp == (SVCXPRT *)-1) {
706 udp_transp = svcudp_create(standalone ? RPC_ANYSOCK : 0
707 #if defined(_AIX) || defined(hpV4) || defined(__osf__) || defined(linux) || \
713 if (udp_transp == NULL) {
714 (void)fprintf(stderr,
715 "rtable_main.c: cannot create udp service.\n");
721 if (!svc_register(udp_transp, ph->program_num, version, program,
722 standalone ? IPPROTO_UDP : 0)) {
724 if (!svc_register(udp_transp, ph->program_num, version, program,
727 (void)fprintf(stderr, "rtable_main.c: unable to register");
731 /* Set up tcp for calls that potentially return */
732 /* large amount of data. This transport is not */
733 /* registered with inetd so need to register it */
734 /* with rpcbind ourselves. */
736 if (tcp_transp == (SVCXPRT *)-1) {
737 tcp_transp = svctcp_create(RPC_ANYSOCK, 0, 0);
738 if (tcp_transp == NULL) {
739 (void)fprintf(stderr,
740 "rtable_main.c: cannot create tcp service.\n");
745 if (!svc_register(tcp_transp, ph->program_num, version, program,
747 (void)fprintf(stderr, "rtable_main.c: unable to register(tcp)");
752 #endif /* SunOS || USL */
759 if(-1 == setegid (daemon_gid)) {
760 perror(strerror(errno));
762 if(-1 == seteuid (daemon_uid)) {
763 perror(strerror(errno));
774 (void)fprintf(stderr, "rpc.cmsd: svc_run returned\n");