Add GNU LGPL headers to all .c .C and .h files
[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 librararies 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 #include <EUSCompat.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #ifdef SVR4
40 #ifndef _NETINET_IN_H
41 #include <netinet/in.h>
42 #endif /* _NETINET_IN_H */
43 #endif
44
45 #if defined(SunOS) || defined(USL) || defined(__uxp__)
46 #include <netconfig.h>
47 #include <netdir.h>
48 #include <sys/stropts.h>
49 #include <tiuser.h>
50 #endif /* SunOS || USL || __uxp__ */
51 #include <sys/param.h>
52 #include <sys/stat.h>
53 #include <fcntl.h>
54 #include <rpc/rpc.h>
55 #include <sys/file.h>
56 #include <sys/signal.h>
57 #include <pwd.h>
58 #include <grp.h>
59 #include "rpcextras.h"
60 #include "log.h"
61 #include "cmscalendar.h"
62 #include "repeat.h"
63 #include "lutil.h"
64 #include "cmsdata.h"
65
66 #ifndef S_IRWXU
67 #define S_IRWXU         (S_IRUSR|S_IWUSR|S_IXUSR)
68 #endif
69 #ifndef S_IRWXG
70 #define S_IRWXG         (S_IRGRP|S_IWGRP|S_IXGRP)
71 #endif
72 #ifndef S_IRWXO
73 #define S_IRWXO         (S_IROTH|S_IWOTH|S_IXOTH)
74 #endif
75
76 #define S_MASK  (S_INPUT|S_HIPRI|S_ERROR|S_HANGUP)
77
78 int debug;
79 static int standalone;                  /* default is 0 */
80 static int received_sighup = 0;         /* 1 means we get SIGHUP */
81 static int rpc_in_process = 0;          /* 1 means processing client request */
82 static int garbage_collection_time = 240; /* in min; default time is 4:00am */
83
84 char    *pgname;
85
86 uid_t daemon_uid;
87 gid_t daemon_gid;
88
89 /*
90  * get garbage collection time
91  * the given string should be in the format hhmm
92  * where hh is 0 - 23 and mm is 00 - 59
93  */
94 static int
95 _GetGtime(char *timestr)
96 {
97         int     hour, minute, len, i;
98
99         if (timestr == NULL)
100                 goto error;
101
102         if ((len = strlen(timestr)) > 4)
103                 goto error;
104
105         for (i = 0; i < len; i++) {
106                 if (timestr[i] < '0' || timestr[i] > '9')
107                         goto error;
108         }
109
110         minute = atoi(&timestr[len - 2]);
111         timestr[len - 2] = NULL;
112         hour = atoi(timestr);
113
114         if (hour > 23 || minute > 59)
115                 goto error;
116
117         garbage_collection_time = hour * 60 + minute;
118
119         return (0);
120
121 error:
122         fprintf(stderr, "The time specified is invalid.\n");
123         return (-1);
124 }
125
126 static void
127 parse_args(int argc, char **argv)
128 {
129         int     opt;
130
131         if (pgname = strrchr (argv[0], '/'))
132                 pgname++;
133         else
134                 pgname = argv[0];
135
136         while ((opt = getopt (argc, argv, "dsg:")) != -1)
137         {
138                 switch (opt)
139                 {
140                 case 'd':
141                         debug = 1;
142                         break;
143                 case 's':
144                         standalone = 1;
145                         break;
146                 case 'g':
147                         if (_GetGtime(optarg))
148                                 goto error;
149                         break;
150                 case '?':
151                         goto error;
152                 }
153         }
154
155         if (optind == argc)
156                 return;
157
158 #if defined(_aix)
159         /*
160          * rpc.cmsd gets started by the inetd.
161          * On AIX inetd requires that two arguments be supplied to the RPC
162          * programs as follows (from the inetd.conf man page):
163          *
164          * ServerArgs      Specifies the command line arguments that the
165          * inetd daemon should use to execute the server. The maximum number
166          * of arguments is five. The first argument specifies the name of the
167          * server used.  If the SocketType parameter is sunrpc_tcp or
168          * sunrpc_udp, * the second argument specifies the program name and
169          * the third argument specifies the version of the program. For
170          * services that the inetd daemon provides internally, this field
171          * should be empty.
172          */
173
174         else if (optind == 1 && argc >= 3)
175         {
176                 int i,j;
177                 char **argv_r;
178                 
179                 if (argc == 3)
180                   return;
181                   
182                 argv_r = (char **) malloc(argc * sizeof(char *));
183
184                 argv_r[0] = argv[0];
185                 for (i=optind+2, j=1; i<argc; i++,j++)
186                   argv_r[j] = argv[i];
187                 parse_args(argc-2, argv_r);
188
189                 free((void *) argv_r);
190                 return;
191         }
192 #endif
193                 
194 error:
195         fprintf (stderr, "Usage: %s [-d] [-s] [-g hhmm]\n", pgname);
196         exit (-1);
197 }
198
199 static void
200 init_dir()
201 {
202         char *dir = _DtCMS_DEFAULT_DIR;
203         char msgbuf[BUFSIZ];
204         int create_dir;
205         struct stat info;
206         mode_t mode;
207
208         if (geteuid() != 0)
209         {
210                 fprintf (stderr,
211                         "%s: must be run in super-user mode!  Exited.\n",
212                         pgname);
213                 exit (-1);
214         }
215
216         create_dir = 0;
217         if (stat(dir, &info))
218         {
219                 /* if directory does not exist, create the directory */
220                 if ((errno != ENOENT) || mkdir(dir, S_IRWXU|S_IRWXG|S_IRWXO))
221                 {
222                         if (errno == ENOENT)
223                                 sprintf(msgbuf, "%s: cannot create %s.\n%s: %s",
224                                         pgname, dir, pgname, "System error");
225                         else
226                                 sprintf(msgbuf, "%s: cannot access %s.\n%s: %s",
227                                         pgname, dir, pgname, "System error");
228                         perror (msgbuf);
229                         exit (-1);
230                 }
231                 create_dir = 1;
232         }
233
234         /* if dir is just created, we need to do chmod and chown.
235          * Otherwise, only do chmod and/or chown if permssion and/or
236          * ownership is wrong.
237          */
238         mode = S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
239
240         if (create_dir || info.st_mode != (mode | S_IFDIR)) {
241
242                 /* set directory permission to be "rwxrwsrwt" */
243                 if (chmod(dir, mode)) {
244                         sprintf(msgbuf, "%s: Permission on %s%s\n%s%s\n%s%s",
245                                 pgname, dir,
246                                 " is wrong but cannot be corrected.", pgname,
247                                 ": This might happen if you are mounting the directory.",
248                                 pgname, ": System error");
249                         perror(msgbuf);
250                         if (create_dir)
251                                 rmdir(dir);
252                         exit(-1);
253                 }
254         }
255
256         if (create_dir || info.st_uid!=daemon_uid || info.st_gid!=daemon_gid) {
257                 /* set directory ownership to: owner = 1, group = 1 */
258                 if (chown(dir, daemon_uid, daemon_gid)) {
259                         sprintf(msgbuf, "%s: Ownership on %s%s\n%s%s\n%s%s",
260                                 pgname, dir,
261                                 " is wrong but cannot be corrected.", pgname,
262                                 ": This might happen if you are mounting the directory.",
263                                 pgname, ": System error");
264                         perror(msgbuf);
265                         if (create_dir)
266                                 rmdir(dir);
267                         exit(-1);
268                 }
269         }
270
271         /* Change current directory, so core file can be dumped. */
272         chdir (dir);
273 }
274
275 /*
276  * send a SIGHUP signal to the rpc.cmsd that is already running
277  */
278 static void
279 send_hup()
280 {
281         FILE    *fp = NULL;
282         char    buf[BUFSIZ];
283         pid_t   pid, mypid = getpid();
284         extern FILE *popen(const char *, const char *);
285         extern int pclose(FILE *);
286
287         sprintf(buf, "ps -e|grep rpc.cmsd|grep -v grep");
288
289         if ((fp = popen(buf, "r")) == NULL) {
290                 if (debug)
291                         fprintf(stderr, "rpc.cmsd: popen failed\n");
292         } else {
293                 while (fgets(buf, sizeof(buf), fp) != NULL) {
294                         if ((pid = atol(buf)) != mypid) {
295                                 if (kill(pid, SIGHUP))
296                                     perror("rpc.cmsd: failed to send SIGHUP");
297                                 if (debug)
298                                     fprintf(stderr, "rpc.cmsd: %s %ld\n",
299                                                 "sent SIGHUP to", (long)pid);
300                         }
301                 }
302                 pclose(fp);
303         }
304 }
305
306 /*
307  * We only allow one rpc.cmsd to run on each machine.
308  */
309 static int
310 lock_it()
311 {
312         char *dir = _DtCMS_DEFAULT_DIR;
313         char    buff [MAXPATHLEN];
314         int     error;
315         int     fd;
316 #ifdef SVR4
317         struct flock locker;
318         locker.l_type = F_WRLCK;
319         locker.l_whence = 0;
320         locker.l_start = 0;
321         locker.l_len = 0;
322 #endif /* SVR4 */
323
324         strcpy (buff, dir);
325         strcat (buff, "/.lock.");
326
327         /* 
328          * /var/spool might be mounted.  Use .lock.hostname to
329          * prevent more than one cms running in each host.
330          */
331         strcat(buff, _DtCmGetLocalHost());
332
333         fd = open(buff, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
334         if (fd < 0)
335         {
336                 perror (buff);
337                 exit (-1);
338         }
339
340         /*
341          * Note, we have to use flock() instead of lockf() because cms process
342          * is run in each host.
343          */
344 #ifdef SVR4
345         if (fcntl (fd, F_SETLK, &locker) != 0)
346 #else
347         if (flock (fd, LOCK_EX|LOCK_NB) != 0)
348 #endif /* SVR4 */
349         {
350                 error = errno;
351
352                 close(fd);
353
354                 if (error != EWOULDBLOCK && error != EACCES) {
355
356                         perror ("rpc.cmsd: failed to lock lockfile");
357                         fprintf(stderr, "error = %d\n", error);
358                         exit (-1);
359
360                 } else {
361                         if (debug)
362                                 fprintf(stderr, "rpc.cmsd: %s\n",
363                                     "lock_it failed due to another process");
364                         
365                         /* cms has been running.... */
366                         return(error);
367                 }
368         }
369
370         return (0);
371 }
372
373 static void
374 program(struct svc_req *rqstp, register SVCXPRT *transp)
375 {
376         char *result;
377         char *argument = NULL;
378         program_handle ph = getph();
379         struct rpcgen_table *proc;
380
381         /* set rpc_in_process so that sighup handler won't exit right away */
382         rpc_in_process = 1;
383  
384         /* first do some bounds checking: */
385         if (rqstp->rq_vers >= ph->nvers) {
386                 svcerr_noproc(transp);
387                 goto done;
388         }
389         if (ph->prog[rqstp->rq_vers].nproc == 0) {
390                 svcerr_noproc(transp);
391                 goto done;
392         }
393         if (rqstp->rq_proc >= ph->prog[rqstp->rq_vers].nproc) {
394                 svcerr_noproc(transp);
395                 goto done;
396         }
397
398         if (rqstp->rq_proc == NULLPROC) {
399                 if (debug) fprintf(stderr, "rpc.cmsd: ping\n");
400                 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL);
401                 goto done;
402         }
403
404         /* assert - the program number, version and proc numbers are valid */
405         proc = &(ph->prog[rqstp->rq_vers].vers[rqstp->rq_proc]);
406         argument = (char*)calloc(proc->len_arg, sizeof(char));
407         if (!svc_getargs(transp, proc->xdr_arg, argument)) {
408                 svcerr_decode(transp);
409                 goto done;
410         }
411
412         result = (*proc->proc)(argument, rqstp);
413         if (result != NULL && !svc_sendreply(transp, proc->xdr_res, result)) {
414                 svcerr_systemerr(transp);
415         }
416
417         if (!svc_freeargs(transp, proc->xdr_arg, argument)) {
418                 (void)fprintf(stderr, "unable to free arguments");
419                 exit(1);
420         }
421         free(argument);
422
423 done:
424         rpc_in_process = 0;
425
426         /* exit if we have received the SIGHUP signal */
427         if (received_sighup == 1) {
428                 if (debug)
429                         fprintf(stderr, "rpc.cmsd: received SIGHUP, %s",
430                                 "exiting after finished processing\n");
431                 exit(0);
432         }
433 }
434
435 /*
436  * Signal handler for SIGHUP.
437  * If we are in the middle of processing a client request,
438  * finish processing before we exit.
439  */
440 static void
441 sighup_handler(int sig_num)
442 {
443         if (debug)
444                 fprintf(stderr, "rpc.cmsd: sighup received\n");
445
446         if (rpc_in_process == 0) {
447                 if (debug)
448                         fprintf(stderr, "rpc.cmsd: exit from sighup_handler\n");
449                 exit(0);
450         } else {
451                 if (debug)
452                         fprintf(stderr, "rpc.cmsd: set received_sighup to 1\n");
453                 received_sighup = 1;
454         }
455 }
456
457 /*
458  * garbage_collection_time (in min) is the time to do garbage collection
459  * each day
460  * This routine returns the difference between the first garbage collection
461  * time and now so that the calling routine can set the alarm.
462  */
463 static int
464 _GetFirstGarbageCollectionTime()
465 {
466         int n=0, midnight=0, gtime=0;
467
468         n = time(0);
469
470         /* try today first */
471         midnight = next_ndays(n, 0);
472         gtime = next_nmins(midnight, garbage_collection_time);
473
474         if (gtime < n) {
475                 /* the first garbage collection will be done tomorrow */
476                 midnight = next_ndays(n, 1);
477                 gtime = next_nmins(midnight, garbage_collection_time);
478         }
479
480         return (gtime - n);
481 }
482
483 static void
484 init_alarm()
485 {
486         int next;
487         extern void garbage_collect();
488         extern void debug_switch();
489
490 #if defined(SVR4) && !defined(linux)
491         extern void (*sigset(int, void (*)(int)))(int);
492         sigset(SIGUSR1, garbage_collect);
493         sigset(SIGALRM, garbage_collect);
494         sigset(SIGUSR2, debug_switch);
495 #else
496         signal(SIGUSR1, garbage_collect);
497         signal(SIGALRM, garbage_collect);
498         signal(SIGUSR2, debug_switch);
499 #endif /* SVR4 */
500
501         next = _GetFirstGarbageCollectionTime();
502         alarm((unsigned) next);
503 }
504
505 main(int argc, char **argv)
506 {
507         u_long version;
508         program_handle ph = newph();
509         struct passwd *pw;
510         struct group *gr;
511         struct rlimit rl;
512         struct sockaddr_in saddr;
513         int asize = sizeof (saddr);
514         SVCXPRT *tcp_transp = (SVCXPRT *)-1;
515         SVCXPRT *udp_transp = (SVCXPRT *)-1;
516         int     fd, error;
517
518 #if defined(SunOS) || defined(USL) || defined(__uxp__)
519         struct netconfig *nconf_udp;
520         struct netconfig *nconf_tcp;
521         struct t_info info;
522 #if !defined(USL) || (defined(USL) && (OSMAJORVERSION > 1))
523         char mname[FMNAMESZ+1];
524 #endif
525 #endif /* SunOS || USL */
526
527         pw = (struct passwd *)getpwnam("daemon");
528         gr = (struct group *)getgrnam("daemon");
529         if (pw != NULL) 
530                 daemon_uid = pw->pw_uid;
531         else
532                 daemon_uid = 1;
533         if (gr != NULL)
534                 daemon_gid = gr->gr_gid;
535         else 
536                 daemon_gid = 1;
537
538         parse_args(argc, argv);
539
540         /* check to see if we are started by inetd */
541         if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
542
543                 standalone = 0;
544
545 #if defined(SunOS) || defined(USL) || defined(__uxp__)
546 #if !defined(USL) || (defined(USL) && (OSMAJORVERSION > 1))
547                 /* we need a TLI endpoint rather than a socket */
548                 if (ioctl(0, I_LOOK, mname) != 0) {
549                         perror("rpc.cmsd: ioctl failed to get module name");
550                         exit(1);
551                 }
552                 if (strcmp(mname, "sockmod") == 0) {
553                         /* Change socket fd to TLI fd */
554                         if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) {
555                                 perror("rpc.cmsd: ioctl I_POP/I_PUSH failed");
556                                 exit(1);
557                         }
558                 } else if (strcmp(mname, "timod") != 0) {
559                         fprintf(stderr, "rpc.cmsd: fd 0 is not timod\n");
560                         exit(1);
561                 }
562 #else  /* !USL || (USL && OSMAJORVERSION > 1) */
563                 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) {
564                         perror("rpc.cmsd: ioctl I_POP/I_PUSH failed");
565                         exit(1);
566                 }
567 #endif /* !USL || (USL && OSMAJORVERSION > 1) */
568
569         } else if (t_getinfo(0, &info) == 0) {
570                 standalone = 0;
571
572 #endif /* SunOS || USL */
573
574         } else
575                 standalone = 1;
576
577         /*
578          * if it is started by inetd, make stderr to be
579          * output to console.
580          */
581         if (!standalone) {
582                 if ((fd = open ("/dev/console", O_WRONLY)) >= 0) {
583                         if (fd != 2) {
584                                 dup2(fd, 2);
585                                 close (fd);
586                         }
587                 }
588         }
589
590         /* Set up private directory and switch euid/egid to daemon. */
591         umask (S_IWOTH);
592         init_dir();
593
594         /* Don't allow multiple cms processes running in the same host. */
595         if ((error = lock_it()) != 0 && !standalone) {
596                 /* we are invoked by inetd but another rpc.cmsd
597                  * is alreay running, so send SIGHUP to it
598                  */
599
600                 send_hup();
601
602                 /* try to lock it again */
603                 if (lock_it() != 0) {
604                         if (debug)
605                                 fprintf(stderr, "cm: rpc.cmsd is still running\n");
606                         exit(0);
607                 }
608
609         } else if (error != 0) {
610                 fprintf(stderr, "rpc.cmsd: rpc.cmsd is already running.\n");
611                 exit(0);
612         }
613
614         /* use signal because we only need it once */
615         signal(SIGHUP, sighup_handler);
616
617
618 #if defined(SunOS) || defined(USL) || defined(__uxp__)
619         /* raise the soft limit of number of file descriptor */
620         /* this is to prevent the backend from running out of open file des */
621         getrlimit(RLIMIT_NOFILE, &rl);
622         rl.rlim_cur = (rl.rlim_max <= 256) ? rl.rlim_max : 256;
623         setrlimit(RLIMIT_NOFILE, &rl);
624 #endif
625
626 #if defined(SunOS) || defined(USL) || defined(__uxp__)
627         nconf_udp = getnetconfigent("udp");
628         nconf_tcp = getnetconfigent("tcp");
629
630         for (version = 0; version < ph->nvers; version++) {
631                 /* don't register unsupported versions: */
632                 if (ph->prog[version].nproc == 0) continue;
633
634                 if (standalone) {
635                         rpcb_unset(ph->program_num, version, NULL);
636                         if (debug)
637                                 fprintf(stderr,
638                                         "rpc.cmsd: rpcb_unset for version %ld\n",
639                                         version);
640                 }
641
642                 /* brought up by inetd, use fd 0 which must be a TLI fd */
643                 if (udp_transp == (SVCXPRT *)-1) {
644                         udp_transp = svc_tli_create(standalone ? RPC_ANYFD : 0,
645                                 nconf_udp, (struct t_bind*) NULL, 0, 0); 
646
647                         if (udp_transp == NULL) {
648                                 t_error("rtable_main.c: svc_tli_create(udp)");
649                                 exit(2);
650                         }
651                 }
652
653                 if (svc_reg(udp_transp, ph->program_num, version, program,
654                                 standalone ? nconf_udp : NULL) == 0) {
655                         t_error("rtable_main.c: svc_reg");
656                         exit(3);
657                 }
658
659                 /* Set up tcp for calls that potentially return */
660                 /* large amount of data.  This transport is not */
661                 /* registered with inetd so need to register it */
662                 /* with rpcbind ourselves.                      */
663
664                 rpcb_unset(ph->program_num, version, nconf_tcp);
665
666                 if (tcp_transp == (SVCXPRT *)-1) {
667                         tcp_transp = svc_tli_create(RPC_ANYFD, nconf_tcp,
668                                         (struct t_bind *)NULL, 0, 0);
669
670                         if (tcp_transp == NULL) {
671                                 t_error("rtable_main.c: svc_til_create(tcp)");
672                                 exit(2);
673                         }
674                 }
675
676                 if (svc_reg(tcp_transp, ph->program_num, version, program,
677                                 nconf_tcp) == 0) {
678                         t_error("rtable_main.c: svc_reg(tcp)");
679                         exit(3);
680                 }
681         }/*for*/
682
683         if (nconf_udp)
684                 freenetconfigent(nconf_udp);
685         if (nconf_tcp)
686                 freenetconfigent(nconf_tcp);
687
688 #else
689
690         for (version = 0; version < ph->nvers; version++) {
691                 /* don't register unsupported versions: */
692                 if (ph->prog[version].nproc == 0) continue;
693
694 #ifndef HPUX
695                 if (standalone)
696 #endif
697                         (void) pmap_unset(ph->program_num, version);
698
699                 if (udp_transp == (SVCXPRT *)-1) {
700                         udp_transp = svcudp_create(standalone ? RPC_ANYSOCK : 0
701 #if defined(_AIX) || defined(hpV4) || defined(__osf__) || defined(linux)
702                                         );
703 #else
704                                         ,0,0);
705 #endif
706                         if (udp_transp == NULL) {
707                                 (void)fprintf(stderr,
708                                 "rtable_main.c: cannot create udp service.\n");
709                                 exit(1);
710                         }
711                 }
712
713 #ifndef HPUX
714                 if (!svc_register(udp_transp, ph->program_num, version, program,
715                                 standalone ? IPPROTO_UDP : 0)) {
716 #else
717                 if (!svc_register(udp_transp, ph->program_num, version, program,
718                                 IPPROTO_UDP)) {
719 #endif
720                         (void)fprintf(stderr, "rtable_main.c: unable to register");
721                         exit(1);
722                 }
723
724                 /* Set up tcp for calls that potentially return */
725                 /* large amount of data.  This transport is not */
726                 /* registered with inetd so need to register it */
727                 /* with rpcbind ourselves.                      */
728
729                 if (tcp_transp == (SVCXPRT *)-1) {
730                         tcp_transp = svctcp_create(RPC_ANYSOCK, 0, 0);
731                         if (tcp_transp == NULL) {
732                                 (void)fprintf(stderr,
733                                 "rtable_main.c: cannot create tcp service.\n");
734                                 exit(1);
735                         }
736                 }
737
738                 if (!svc_register(tcp_transp, ph->program_num, version, program,
739                                 IPPROTO_TCP)) {
740                         (void)fprintf(stderr, "rtable_main.c: unable to register(tcp)");
741                         exit(1);
742                 }
743         }
744
745 #endif /* SunOS || USL */
746
747 #ifndef AIX
748 #ifdef HPUX
749         setgid (daemon_gid);
750         setuid (daemon_uid);
751 #else
752         setegid (daemon_gid);
753         seteuid (daemon_uid);
754 #endif /* HPUX */
755 #endif /* AIX */
756
757         init_time();
758         init_alarm();
759         _DtCm_init_hash();
760
761         svc_run();
762
763         (void)fprintf(stderr, "rpc.cmsd: svc_run returned\n");
764         return(1);
765 }
766