Remove UXPDS support
[oweals/cde.git] / cde / programs / dtcm / server / svcmain.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: svcmain.c /main/10 1998/04/06 13:13:49 mgreess $ */
24 /*
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.
29  */
30
31 #if defined(linux)
32 #define _POSIX_C_SOURCE 2
33 #endif
34
35 #include <EUSCompat.h>
36 #include <stdio.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <sys/time.h>
42 #include <sys/resource.h>
43 #ifdef SVR4
44 #ifndef _NETINET_IN_H
45 #include <netinet/in.h>
46 #endif /* _NETINET_IN_H */
47 #endif
48
49 #if defined(SunOS) || defined(USL)
50 #include <netconfig.h>
51 #include <netdir.h>
52 #include <sys/stropts.h>
53 #include <tiuser.h>
54 #endif /* SunOS || USL */
55 #include <sys/param.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <rpc/rpc.h>
59 #include <sys/file.h>
60 #include <sys/signal.h>
61 #include <pwd.h>
62 #include <grp.h>
63 #include "rpcextras.h"
64 #include "log.h"
65 #include "cmscalendar.h"
66 #include "repeat.h"
67 #include "lutil.h"
68 #include "cmsdata.h"
69
70 #ifndef S_IRWXU
71 #define S_IRWXU         (S_IRUSR|S_IWUSR|S_IXUSR)
72 #endif
73 #ifndef S_IRWXG
74 #define S_IRWXG         (S_IRGRP|S_IWGRP|S_IXGRP)
75 #endif
76 #ifndef S_IRWXO
77 #define S_IRWXO         (S_IROTH|S_IWOTH|S_IXOTH)
78 #endif
79
80 #define S_MASK  (S_INPUT|S_HIPRI|S_ERROR|S_HANGUP)
81
82 int debug;
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 */
87
88 char    *pgname;
89
90 uid_t daemon_uid;
91 gid_t daemon_gid;
92
93 /*
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
97  */
98 static int
99 _GetGtime(char *timestr)
100 {
101         int     hour, minute, len, i;
102
103         if (timestr == NULL)
104                 goto error;
105
106         if ((len = strlen(timestr)) > 4)
107                 goto error;
108
109         for (i = 0; i < len; i++) {
110                 if (timestr[i] < '0' || timestr[i] > '9')
111                         goto error;
112         }
113
114         minute = atoi(&timestr[len - 2]);
115         timestr[len - 2] = '\0';
116         hour = atoi(timestr);
117
118         if (hour > 23 || minute > 59)
119                 goto error;
120
121         garbage_collection_time = hour * 60 + minute;
122
123         return (0);
124
125 error:
126         fprintf(stderr, "The time specified is invalid.\n");
127         return (-1);
128 }
129
130 static void
131 parse_args(int argc, char **argv)
132 {
133         int     opt;
134
135         if (pgname = strrchr (argv[0], '/'))
136                 pgname++;
137         else
138                 pgname = argv[0];
139
140         while ((opt = getopt (argc, argv, "dsg:")) != -1)
141         {
142                 switch (opt)
143                 {
144                 case 'd':
145                         debug = 1;
146                         break;
147                 case 's':
148                         standalone = 1;
149                         break;
150                 case 'g':
151                         if (_GetGtime(optarg))
152                                 goto error;
153                         break;
154                 case '?':
155                         goto error;
156                 }
157         }
158
159         if (optind == argc)
160                 return;
161
162 #if defined(_aix)
163         /*
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):
167          *
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
175          * should be empty.
176          */
177
178         else if (optind == 1 && argc >= 3)
179         {
180                 int i,j;
181                 char **argv_r;
182                 
183                 if (argc == 3)
184                   return;
185                   
186                 argv_r = (char **) malloc(argc * sizeof(char *));
187
188                 argv_r[0] = argv[0];
189                 for (i=optind+2, j=1; i<argc; i++,j++)
190                   argv_r[j] = argv[i];
191                 parse_args(argc-2, argv_r);
192
193                 free((void *) argv_r);
194                 return;
195         }
196 #endif
197                 
198 error:
199         fprintf (stderr, "Usage: %s [-d] [-s] [-g hhmm]\n", pgname);
200         exit (-1);
201 }
202
203 static void
204 init_dir()
205 {
206         char *dir = _DtCMS_DEFAULT_DIR;
207         char msgbuf[BUFSIZ];
208         int create_dir;
209         struct stat info;
210         mode_t mode;
211
212         if (geteuid() != 0)
213         {
214                 fprintf (stderr,
215                         "%s: must be run in super-user mode!  Exited.\n",
216                         pgname);
217                 exit (-1);
218         }
219
220         create_dir = 0;
221         if (stat(dir, &info))
222         {
223                 /* if directory does not exist, create the directory */
224                 if ((errno != ENOENT) || mkdir(dir, S_IRWXU|S_IRWXG|S_IRWXO))
225                 {
226                         if (errno == ENOENT)
227                                 sprintf(msgbuf, "%s: cannot create %s.\n%s: %s",
228                                         pgname, dir, pgname, "System error");
229                         else
230                                 sprintf(msgbuf, "%s: cannot access %s.\n%s: %s",
231                                         pgname, dir, pgname, "System error");
232                         perror (msgbuf);
233                         exit (-1);
234                 }
235                 create_dir = 1;
236         }
237
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.
241          */
242         mode = S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
243
244         if (create_dir || info.st_mode != (mode | S_IFDIR)) {
245
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",
249                                 pgname, dir,
250                                 " is wrong but cannot be corrected.", pgname,
251                                 ": This might happen if you are mounting the directory.",
252                                 pgname, ": System error");
253                         perror(msgbuf);
254                         if (create_dir)
255                                 rmdir(dir);
256                         exit(-1);
257                 }
258         }
259
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",
264                                 pgname, dir,
265                                 " is wrong but cannot be corrected.", pgname,
266                                 ": This might happen if you are mounting the directory.",
267                                 pgname, ": System error");
268                         perror(msgbuf);
269                         if (create_dir)
270                                 rmdir(dir);
271                         exit(-1);
272                 }
273         }
274
275         /* Change current directory, so core file can be dumped. */
276         if(-1 == chdir (dir)) {
277                 perror(strerror(errno));
278         }
279 }
280
281 /*
282  * send a SIGHUP signal to the rpc.cmsd that is already running
283  */
284 static void
285 send_hup()
286 {
287         FILE    *fp = NULL;
288         char    buf[BUFSIZ];
289         pid_t   pid, mypid = getpid();
290         extern FILE *popen(const char *, const char *);
291         extern int pclose(FILE *);
292
293         sprintf(buf, "ps -e|grep rpc.cmsd|grep -v grep");
294
295         if ((fp = popen(buf, "r")) == NULL) {
296                 if (debug)
297                         fprintf(stderr, "rpc.cmsd: popen failed\n");
298         } else {
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");
303                                 if (debug)
304                                     fprintf(stderr, "rpc.cmsd: %s %ld\n",
305                                                 "sent SIGHUP to", (long)pid);
306                         }
307                 }
308                 pclose(fp);
309         }
310 }
311
312 /*
313  * We only allow one rpc.cmsd to run on each machine.
314  */
315 static int
316 lock_it()
317 {
318         char *dir = _DtCMS_DEFAULT_DIR;
319         char    buff [MAXPATHLEN];
320         int     error;
321         int     fd;
322 #ifdef SVR4
323         struct flock locker;
324         locker.l_type = F_WRLCK;
325         locker.l_whence = 0;
326         locker.l_start = 0;
327         locker.l_len = 0;
328 #endif /* SVR4 */
329
330         strcpy (buff, dir);
331         strcat (buff, "/.lock.");
332
333         /* 
334          * /var/spool might be mounted.  Use .lock.hostname to
335          * prevent more than one cms running in each host.
336          */
337         strcat(buff, _DtCmGetLocalHost());
338
339         fd = open(buff, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
340         if (fd < 0)
341         {
342                 perror (buff);
343                 exit (-1);
344         }
345
346         /*
347          * Note, we have to use flock() instead of lockf() because cms process
348          * is run in each host.
349          */
350 #ifdef SVR4
351         if (fcntl (fd, F_SETLK, &locker) != 0)
352 #else
353         if (flock (fd, LOCK_EX|LOCK_NB) != 0)
354 #endif /* SVR4 */
355         {
356                 error = errno;
357
358                 close(fd);
359
360                 if (error != EWOULDBLOCK && error != EACCES) {
361
362                         perror ("rpc.cmsd: failed to lock lockfile");
363                         fprintf(stderr, "error = %d\n", error);
364                         exit (-1);
365
366                 } else {
367                         if (debug)
368                                 fprintf(stderr, "rpc.cmsd: %s\n",
369                                     "lock_it failed due to another process");
370                         
371                         /* cms has been running.... */
372                         return(error);
373                 }
374         }
375
376         return (0);
377 }
378
379 static void
380 program(struct svc_req *rqstp, register SVCXPRT *transp)
381 {
382         char *result;
383         char *argument = NULL;
384         program_handle ph = getph();
385         struct rpcgen_table *proc;
386
387         /* set rpc_in_process so that sighup handler won't exit right away */
388         rpc_in_process = 1;
389  
390         /* first do some bounds checking: */
391         if (rqstp->rq_vers >= ph->nvers) {
392                 svcerr_noproc(transp);
393                 goto done;
394         }
395         if (ph->prog[rqstp->rq_vers].nproc == 0) {
396                 svcerr_noproc(transp);
397                 goto done;
398         }
399         if (rqstp->rq_proc >= ph->prog[rqstp->rq_vers].nproc) {
400                 svcerr_noproc(transp);
401                 goto done;
402         }
403
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);
407                 goto done;
408         }
409
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);
415                 goto done;
416         }
417
418         result = (*proc->proc)(argument, rqstp);
419         if (result != NULL && !svc_sendreply(transp, proc->xdr_res, result)) {
420                 svcerr_systemerr(transp);
421         }
422
423         if (!svc_freeargs(transp, proc->xdr_arg, argument)) {
424                 (void)fprintf(stderr, "unable to free arguments");
425                 exit(1);
426         }
427         free(argument);
428
429 done:
430         rpc_in_process = 0;
431
432         /* exit if we have received the SIGHUP signal */
433         if (received_sighup == 1) {
434                 if (debug)
435                         fprintf(stderr, "rpc.cmsd: received SIGHUP, %s",
436                                 "exiting after finished processing\n");
437                 exit(0);
438         }
439 }
440
441 /*
442  * Signal handler for SIGHUP.
443  * If we are in the middle of processing a client request,
444  * finish processing before we exit.
445  */
446 static void
447 sighup_handler(int sig_num)
448 {
449         if (debug)
450                 fprintf(stderr, "rpc.cmsd: sighup received\n");
451
452         if (rpc_in_process == 0) {
453                 if (debug)
454                         fprintf(stderr, "rpc.cmsd: exit from sighup_handler\n");
455                 exit(0);
456         } else {
457                 if (debug)
458                         fprintf(stderr, "rpc.cmsd: set received_sighup to 1\n");
459                 received_sighup = 1;
460         }
461 }
462
463 /*
464  * garbage_collection_time (in min) is the time to do garbage collection
465  * each day
466  * This routine returns the difference between the first garbage collection
467  * time and now so that the calling routine can set the alarm.
468  */
469 static int
470 _GetFirstGarbageCollectionTime()
471 {
472         int n=0, midnight=0, gtime=0;
473
474         n = time(0);
475
476         /* try today first */
477         midnight = next_ndays(n, 0);
478         gtime = next_nmins(midnight, garbage_collection_time);
479
480         if (gtime < n) {
481                 /* the first garbage collection will be done tomorrow */
482                 midnight = next_ndays(n, 1);
483                 gtime = next_nmins(midnight, garbage_collection_time);
484         }
485
486         return (gtime - n);
487 }
488
489 static void
490 init_alarm()
491 {
492         int next;
493         extern void garbage_collect();
494         extern void debug_switch();
495
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);
501 #else
502         signal(SIGUSR1, garbage_collect);
503         signal(SIGALRM, garbage_collect);
504         signal(SIGUSR2, debug_switch);
505 #endif /* SVR4 */
506
507         next = _GetFirstGarbageCollectionTime();
508         alarm((unsigned) next);
509 }
510
511 main(int argc, char **argv)
512 {
513         u_long version;
514         program_handle ph = newph();
515         struct passwd *pw;
516         struct group *gr;
517         struct rlimit rl;
518         struct sockaddr_in saddr;
519         int asize = sizeof (saddr);
520         SVCXPRT *tcp_transp = (SVCXPRT *)-1;
521         SVCXPRT *udp_transp = (SVCXPRT *)-1;
522         int     fd, error;
523
524 #if defined(SunOS) || defined(USL)
525         struct netconfig *nconf_udp;
526         struct netconfig *nconf_tcp;
527         struct t_info info;
528 #if !defined(USL) || (defined(USL) && (OSMAJORVERSION > 1))
529         char mname[FMNAMESZ+1];
530 #endif
531 #endif /* SunOS || USL */
532
533         pw = (struct passwd *)getpwnam("daemon");
534         gr = (struct group *)getgrnam("daemon");
535         if (pw != NULL) 
536                 daemon_uid = pw->pw_uid;
537         else
538                 daemon_uid = 1;
539         if (gr != NULL)
540                 daemon_gid = gr->gr_gid;
541         else 
542                 daemon_gid = 1;
543
544         parse_args(argc, argv);
545
546         /* check to see if we are started by inetd */
547         if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
548
549                 standalone = 0;
550
551 #if defined(SunOS) || defined(USL)
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");
556                         exit(1);
557                 }
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");
562                                 exit(1);
563                         }
564                 } else if (strcmp(mname, "timod") != 0) {
565                         fprintf(stderr, "rpc.cmsd: fd 0 is not timod\n");
566                         exit(1);
567                 }
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");
571                         exit(1);
572                 }
573 #endif /* !USL || (USL && OSMAJORVERSION > 1) */
574
575         } else if (t_getinfo(0, &info) == 0) {
576                 standalone = 0;
577
578 #endif /* SunOS || USL */
579
580         } else
581                 standalone = 1;
582
583         /*
584          * if it is started by inetd, make stderr to be
585          * output to console.
586          */
587         if (!standalone) {
588                 if ((fd = open ("/dev/console", O_WRONLY)) >= 0) {
589                         if (fd != 2) {
590                                 dup2(fd, 2);
591                                 close (fd);
592                         }
593                 }
594         }
595
596         /* Set up private directory and switch euid/egid to daemon. */
597         umask (S_IWOTH);
598         init_dir();
599
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
604                  */
605
606                 send_hup();
607
608                 /* try to lock it again */
609                 if (lock_it() != 0) {
610                         if (debug)
611                                 fprintf(stderr, "cm: rpc.cmsd is still running\n");
612                         exit(0);
613                 }
614
615         } else if (error != 0) {
616                 fprintf(stderr, "rpc.cmsd: rpc.cmsd is already running.\n");
617                 exit(0);
618         }
619
620         /* use signal because we only need it once */
621         signal(SIGHUP, sighup_handler);
622
623
624 #if defined(SunOS) || defined(USL)
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);
630 #endif
631
632 #if defined(SunOS) || defined(USL)
633         nconf_udp = getnetconfigent("udp");
634         nconf_tcp = getnetconfigent("tcp");
635
636         for (version = 0; version < ph->nvers; version++) {
637                 /* don't register unsupported versions: */
638                 if (ph->prog[version].nproc == 0) continue;
639
640                 if (standalone) {
641                         rpcb_unset(ph->program_num, version, NULL);
642                         if (debug)
643                                 fprintf(stderr,
644                                         "rpc.cmsd: rpcb_unset for version %ld\n",
645                                         version);
646                 }
647
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); 
652
653                         if (udp_transp == NULL) {
654                                 t_error("rtable_main.c: svc_tli_create(udp)");
655                                 exit(2);
656                         }
657                 }
658
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");
662                         exit(3);
663                 }
664
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.                      */
669
670                 rpcb_unset(ph->program_num, version, nconf_tcp);
671
672                 if (tcp_transp == (SVCXPRT *)-1) {
673                         tcp_transp = svc_tli_create(RPC_ANYFD, nconf_tcp,
674                                         (struct t_bind *)NULL, 0, 0);
675
676                         if (tcp_transp == NULL) {
677                                 t_error("rtable_main.c: svc_til_create(tcp)");
678                                 exit(2);
679                         }
680                 }
681
682                 if (svc_reg(tcp_transp, ph->program_num, version, program,
683                                 nconf_tcp) == 0) {
684                         t_error("rtable_main.c: svc_reg(tcp)");
685                         exit(3);
686                 }
687         }/*for*/
688
689         if (nconf_udp)
690                 freenetconfigent(nconf_udp);
691         if (nconf_tcp)
692                 freenetconfigent(nconf_tcp);
693
694 #else
695
696         for (version = 0; version < ph->nvers; version++) {
697                 /* don't register unsupported versions: */
698                 if (ph->prog[version].nproc == 0) continue;
699
700 #ifndef HPUX
701                 if (standalone)
702 #endif
703                         (void) pmap_unset(ph->program_num, version);
704
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) || \
708         defined(CSRG_BASED)
709                                         );
710 #else
711                                         ,0,0);
712 #endif
713                         if (udp_transp == NULL) {
714                                 (void)fprintf(stderr,
715                                 "rtable_main.c: cannot create udp service.\n");
716                                 exit(1);
717                         }
718                 }
719
720 #ifndef HPUX
721                 if (!svc_register(udp_transp, ph->program_num, version, program,
722                                 standalone ? IPPROTO_UDP : 0)) {
723 #else
724                 if (!svc_register(udp_transp, ph->program_num, version, program,
725                                 IPPROTO_UDP)) {
726 #endif
727                         (void)fprintf(stderr, "rtable_main.c: unable to register");
728                         exit(1);
729                 }
730
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.                      */
735
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");
741                                 exit(1);
742                         }
743                 }
744
745                 if (!svc_register(tcp_transp, ph->program_num, version, program,
746                                 IPPROTO_TCP)) {
747                         (void)fprintf(stderr, "rtable_main.c: unable to register(tcp)");
748                         exit(1);
749                 }
750         }
751
752 #endif /* SunOS || USL */
753
754 #ifndef AIX
755 #ifdef HPUX
756         setgid (daemon_gid);
757         setuid (daemon_uid);
758 #else
759         if(-1 == setegid (daemon_gid)) {
760                 perror(strerror(errno));
761         }
762         if(-1 == seteuid (daemon_uid)) {
763                 perror(strerror(errno));
764         }
765 #endif /* HPUX */
766 #endif /* AIX */
767
768         init_time();
769         init_alarm();
770         _DtCm_init_hash();
771
772         svc_run();
773
774         (void)fprintf(stderr, "rpc.cmsd: svc_run returned\n");
775         return(1);
776 }
777