xref: /netbsd-src/external/bsd/am-utils/dist/amd/nfs_start.c (revision 8bae5d409deb915cf7c8f0539fae22ff2cb8a313)
1*8bae5d40Schristos /*	$NetBSD: nfs_start.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
2a53f50b9Schristos 
3a53f50b9Schristos /*
4*8bae5d40Schristos  * Copyright (c) 1997-2014 Erez Zadok
5a53f50b9Schristos  * Copyright (c) 1990 Jan-Simon Pendry
6a53f50b9Schristos  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7a53f50b9Schristos  * Copyright (c) 1990 The Regents of the University of California.
8a53f50b9Schristos  * All rights reserved.
9a53f50b9Schristos  *
10a53f50b9Schristos  * This code is derived from software contributed to Berkeley by
11a53f50b9Schristos  * Jan-Simon Pendry at Imperial College, London.
12a53f50b9Schristos  *
13a53f50b9Schristos  * Redistribution and use in source and binary forms, with or without
14a53f50b9Schristos  * modification, are permitted provided that the following conditions
15a53f50b9Schristos  * are met:
16a53f50b9Schristos  * 1. Redistributions of source code must retain the above copyright
17a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer.
18a53f50b9Schristos  * 2. Redistributions in binary form must reproduce the above copyright
19a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer in the
20a53f50b9Schristos  *    documentation and/or other materials provided with the distribution.
21*8bae5d40Schristos  * 3. Neither the name of the University nor the names of its contributors
22a53f50b9Schristos  *    may be used to endorse or promote products derived from this software
23a53f50b9Schristos  *    without specific prior written permission.
24a53f50b9Schristos  *
25a53f50b9Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26a53f50b9Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27a53f50b9Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28a53f50b9Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29a53f50b9Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30a53f50b9Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31a53f50b9Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32a53f50b9Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33a53f50b9Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34a53f50b9Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35a53f50b9Schristos  * SUCH DAMAGE.
36a53f50b9Schristos  *
37a53f50b9Schristos  *
38a53f50b9Schristos  * File: am-utils/amd/nfs_start.c
39a53f50b9Schristos  *
40a53f50b9Schristos  */
41a53f50b9Schristos 
42a53f50b9Schristos #ifdef HAVE_CONFIG_H
43a53f50b9Schristos # include <config.h>
44a53f50b9Schristos #endif /* HAVE_CONFIG_H */
45a53f50b9Schristos #include <am_defs.h>
46a53f50b9Schristos #include <amd.h>
47a53f50b9Schristos 
48a53f50b9Schristos #ifndef SELECT_MAXWAIT
49a53f50b9Schristos # define SELECT_MAXWAIT 16
50a53f50b9Schristos #endif /* not SELECT_MAXWAIT */
51a53f50b9Schristos 
52a53f50b9Schristos SVCXPRT *nfsxprt = NULL;
53a53f50b9Schristos u_short nfs_port = 0;
54a53f50b9Schristos 
55a53f50b9Schristos #ifndef HAVE_SIGACTION
56a53f50b9Schristos # define MASKED_SIGS	(sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
57a53f50b9Schristos #endif /* not HAVE_SIGACTION */
58a53f50b9Schristos 
59a53f50b9Schristos #ifdef DEBUG
60a53f50b9Schristos /*
61a53f50b9Schristos  * Check that we are not burning resources
62a53f50b9Schristos  */
63a53f50b9Schristos static void
checkup(void)64a53f50b9Schristos checkup(void)
65a53f50b9Schristos {
66a53f50b9Schristos   static int max_fd = 0;
67a53f50b9Schristos   static char *max_mem = NULL;
68a53f50b9Schristos   int next_fd = dup(0);
69a53f50b9Schristos   caddr_t next_mem = sbrk(0);
70a53f50b9Schristos 
71a53f50b9Schristos   close(next_fd);
72a53f50b9Schristos 
73a53f50b9Schristos   if (max_fd < next_fd) {
74a53f50b9Schristos     dlog("%d new fds allocated; total is %d",
75a53f50b9Schristos 	 next_fd - max_fd, next_fd);
76a53f50b9Schristos     max_fd = next_fd;
77a53f50b9Schristos   }
78a53f50b9Schristos   if (max_mem < next_mem) {
79a53f50b9Schristos #ifdef HAVE_GETPAGESIZE
80a53f50b9Schristos     dlog("%#lx bytes of memory allocated; total is %#lx (%ld pages)",
81a53f50b9Schristos 	 (long) (next_mem - max_mem), (unsigned long) next_mem,
82a53f50b9Schristos 	 ((long) next_mem + getpagesize() - 1) / (long) getpagesize());
83a53f50b9Schristos #else /* not HAVE_GETPAGESIZE */
84a53f50b9Schristos     dlog("%#lx bytes of memory allocated; total is %#lx",
85a53f50b9Schristos 	 (long) (next_mem - max_mem), (unsigned long) next_mem);
86a53f50b9Schristos #endif /* not HAVE_GETPAGESIZE */
87a53f50b9Schristos     max_mem = next_mem;
88a53f50b9Schristos 
89a53f50b9Schristos   }
90a53f50b9Schristos }
91a53f50b9Schristos #else  /* not DEBUG */
92a53f50b9Schristos #define checkup()
93a53f50b9Schristos #endif /* not DEBUG */
94a53f50b9Schristos 
95a53f50b9Schristos 
96a53f50b9Schristos static int
97a53f50b9Schristos #ifdef HAVE_SIGACTION
do_select(sigset_t smask,int fds,fd_set * fdp,struct timeval * tvp)98a53f50b9Schristos do_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp)
99a53f50b9Schristos #else /* not HAVE_SIGACTION */
100a53f50b9Schristos do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp)
101a53f50b9Schristos #endif /* not HAVE_SIGACTION */
102a53f50b9Schristos {
103a53f50b9Schristos 
104a53f50b9Schristos   int sig;
105a53f50b9Schristos   int nsel;
106a53f50b9Schristos 
107a53f50b9Schristos   if ((sig = setjmp(select_intr))) {
108a53f50b9Schristos     select_intr_valid = 0;
109a53f50b9Schristos     /* Got a signal */
110a53f50b9Schristos     switch (sig) {
111a53f50b9Schristos     case SIGINT:
112a53f50b9Schristos     case SIGTERM:
113a53f50b9Schristos       amd_state = Finishing;
114a53f50b9Schristos       reschedule_timeout_mp();
115a53f50b9Schristos       break;
116a53f50b9Schristos     }
117a53f50b9Schristos     nsel = -1;
118a53f50b9Schristos     errno = EINTR;
119a53f50b9Schristos   } else {
120a53f50b9Schristos     select_intr_valid = 1;
121a53f50b9Schristos     /*
122a53f50b9Schristos      * Allow interrupts.  If a signal
123a53f50b9Schristos      * occurs, then it will cause a longjmp
124a53f50b9Schristos      * up above.
125a53f50b9Schristos      */
126a53f50b9Schristos #ifdef HAVE_SIGACTION
127a53f50b9Schristos     sigprocmask(SIG_SETMASK, &smask, NULL);
128a53f50b9Schristos #else /* not HAVE_SIGACTION */
129a53f50b9Schristos     (void) sigsetmask(smask);
130a53f50b9Schristos #endif /* not HAVE_SIGACTION */
131a53f50b9Schristos 
132a53f50b9Schristos     /*
133a53f50b9Schristos      * Wait for input
134a53f50b9Schristos      */
135a53f50b9Schristos     nsel = select(fds, fdp, (fd_set *) NULL, (fd_set *) NULL,
136a53f50b9Schristos 		  tvp->tv_sec ? tvp : (struct timeval *) NULL);
137a53f50b9Schristos   }
138a53f50b9Schristos 
139a53f50b9Schristos #ifdef HAVE_SIGACTION
140a53f50b9Schristos   sigprocmask(SIG_BLOCK, &masked_sigs, NULL);
141a53f50b9Schristos #else /* not HAVE_SIGACTION */
142a53f50b9Schristos   (void) sigblock(MASKED_SIGS);
143a53f50b9Schristos #endif /* not HAVE_SIGACTION */
144a53f50b9Schristos 
145a53f50b9Schristos   /*
146a53f50b9Schristos    * Perhaps reload the cache?
147a53f50b9Schristos    */
148a53f50b9Schristos   if (do_mapc_reload < clocktime(NULL)) {
149a53f50b9Schristos     mapc_reload();
150a53f50b9Schristos     do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
151a53f50b9Schristos   }
152a53f50b9Schristos   return nsel;
153a53f50b9Schristos }
154a53f50b9Schristos 
155a53f50b9Schristos 
156a53f50b9Schristos /*
157a53f50b9Schristos  * Determine whether anything is left in
158a53f50b9Schristos  * the RPC input queue.
159a53f50b9Schristos  */
160a53f50b9Schristos static int
rpc_pending_now(void)161a53f50b9Schristos rpc_pending_now(void)
162a53f50b9Schristos {
163a53f50b9Schristos   struct timeval tvv;
164a53f50b9Schristos   int nsel;
165a53f50b9Schristos   fd_set readfds;
166a53f50b9Schristos 
167a53f50b9Schristos   FD_ZERO(&readfds);
168a53f50b9Schristos   FD_SET(fwd_sock, &readfds);
169a53f50b9Schristos 
170a53f50b9Schristos   tvv.tv_sec = tvv.tv_usec = 0;
171a53f50b9Schristos   nsel = select(FD_SETSIZE, &readfds, (fd_set *) NULL, (fd_set *) NULL, &tvv);
172a53f50b9Schristos   if (nsel < 1)
173a53f50b9Schristos     return (0);
174a53f50b9Schristos   if (FD_ISSET(fwd_sock, &readfds))
175a53f50b9Schristos     return (1);
176a53f50b9Schristos 
177a53f50b9Schristos   return (0);
178a53f50b9Schristos }
179a53f50b9Schristos 
180a53f50b9Schristos 
181a53f50b9Schristos static serv_state
run_rpc(void)182a53f50b9Schristos run_rpc(void)
183a53f50b9Schristos {
184a53f50b9Schristos #ifdef HAVE_SIGACTION
185a53f50b9Schristos   sigset_t smask;
186a53f50b9Schristos   sigprocmask(SIG_BLOCK, &masked_sigs, &smask);
187a53f50b9Schristos #else /* not HAVE_SIGACTION */
188a53f50b9Schristos   int smask = sigblock(MASKED_SIGS);
189a53f50b9Schristos #endif /* not HAVE_SIGACTION */
190a53f50b9Schristos 
191a53f50b9Schristos   next_softclock = clocktime(NULL);
192a53f50b9Schristos 
193a53f50b9Schristos   amd_state = Run;
194a53f50b9Schristos 
195a53f50b9Schristos   /*
196a53f50b9Schristos    * Keep on trucking while we are in Run mode.  This state
197a53f50b9Schristos    * is switched to Quit after all the file systems have
198a53f50b9Schristos    * been unmounted.
199a53f50b9Schristos    */
200a53f50b9Schristos   while ((int) amd_state <= (int) Finishing) {
201a53f50b9Schristos     struct timeval tvv;
202a53f50b9Schristos     int nsel;
203a53f50b9Schristos     time_t now;
204a53f50b9Schristos     fd_set readfds;
205a53f50b9Schristos 
206a53f50b9Schristos #ifdef HAVE_SVC_GETREQSET
207a53f50b9Schristos     memmove(&readfds, &svc_fdset, sizeof(svc_fdset));
208a53f50b9Schristos #else /* not HAVE_SVC_GETREQSET */
209a53f50b9Schristos     FD_ZERO(&readfds);
210a53f50b9Schristos # ifdef HAVE_FD_SET_FDS_BITS
211a53f50b9Schristos     readfds.fds_bits[0] = svc_fds;
212a53f50b9Schristos # else /* not HAVE_FD_SET_FDS_BITS */
213a53f50b9Schristos     readfds = svc_fds;
214a53f50b9Schristos # endif  /* not HAVE_FD_SET_FDS_BITS */
215a53f50b9Schristos #endif /* not HAVE_SVC_GETREQSET */
216a53f50b9Schristos     FD_SET(fwd_sock, &readfds);
217a53f50b9Schristos 
218a53f50b9Schristos     checkup();
219a53f50b9Schristos 
220a53f50b9Schristos     /*
221a53f50b9Schristos      * If the full timeout code is not called,
222a53f50b9Schristos      * then recompute the time delta manually.
223a53f50b9Schristos      */
224a53f50b9Schristos     now = clocktime(NULL);
225a53f50b9Schristos 
226a53f50b9Schristos     if (next_softclock <= now) {
227a53f50b9Schristos       if (amd_state == Finishing)
228a53f50b9Schristos 	umount_exported();
229a53f50b9Schristos       tvv.tv_sec = softclock();
230a53f50b9Schristos     } else {
231a53f50b9Schristos       tvv.tv_sec = next_softclock - now;
232a53f50b9Schristos     }
233a53f50b9Schristos     tvv.tv_usec = 0;
234a53f50b9Schristos 
235a53f50b9Schristos     if (amd_state == Finishing && get_exported_ap(0) == NULL) {
236a53f50b9Schristos       flush_mntfs();
237a53f50b9Schristos       amd_state = Quit;
238a53f50b9Schristos       break;
239a53f50b9Schristos     }
240a53f50b9Schristos 
241a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
242a53f50b9Schristos     autofs_add_fdset(&readfds);
243a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
244a53f50b9Schristos 
245a53f50b9Schristos     if (tvv.tv_sec <= 0)
246a53f50b9Schristos       tvv.tv_sec = SELECT_MAXWAIT;
247a53f50b9Schristos     if (tvv.tv_sec) {
248a53f50b9Schristos       dlog("Select waits for %ds", (int) tvv.tv_sec);
249a53f50b9Schristos     } else {
250a53f50b9Schristos       dlog("Select waits for Godot");
251a53f50b9Schristos     }
252a53f50b9Schristos 
253a53f50b9Schristos     nsel = do_select(smask, FD_SETSIZE, &readfds, &tvv);
254a53f50b9Schristos 
255a53f50b9Schristos     switch (nsel) {
256a53f50b9Schristos     case -1:
257a53f50b9Schristos       if (errno == EINTR) {
258a53f50b9Schristos 	dlog("select interrupted");
259a53f50b9Schristos 	continue;
260a53f50b9Schristos       }
261a53f50b9Schristos       plog(XLOG_ERROR, "select: %m");
262a53f50b9Schristos       break;
263a53f50b9Schristos 
264a53f50b9Schristos     case 0:
265a53f50b9Schristos       break;
266a53f50b9Schristos 
267a53f50b9Schristos     default:
268a53f50b9Schristos       /*
269a53f50b9Schristos        * Read all pending NFS responses at once to avoid having responses
270a53f50b9Schristos        * queue up as a consequence of retransmissions.
271a53f50b9Schristos        */
272a53f50b9Schristos       if (FD_ISSET(fwd_sock, &readfds)) {
273a53f50b9Schristos 	FD_CLR(fwd_sock, &readfds);
274a53f50b9Schristos 	--nsel;
275a53f50b9Schristos 	do {
276a53f50b9Schristos 	  fwd_reply();
277a53f50b9Schristos 	} while (rpc_pending_now() > 0);
278a53f50b9Schristos       }
279a53f50b9Schristos 
280a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
281a53f50b9Schristos       if (nsel)
282a53f50b9Schristos 	nsel = autofs_handle_fdset(&readfds, nsel);
283a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
284a53f50b9Schristos 
285a53f50b9Schristos       if (nsel) {
286a53f50b9Schristos 	/*
287a53f50b9Schristos 	 * Anything left must be a normal
288a53f50b9Schristos 	 * RPC request.
289a53f50b9Schristos 	 */
290a53f50b9Schristos #ifdef HAVE_SVC_GETREQSET
291a53f50b9Schristos 	svc_getreqset(&readfds);
292a53f50b9Schristos #else /* not HAVE_SVC_GETREQSET */
293a53f50b9Schristos # ifdef HAVE_FD_SET_FDS_BITS
294a53f50b9Schristos 	svc_getreq(readfds.fds_bits[0]);
295a53f50b9Schristos # else /* not HAVE_FD_SET_FDS_BITS */
296a53f50b9Schristos 	svc_getreq(readfds);
297a53f50b9Schristos # endif /* not HAVE_FD_SET_FDS_BITS */
298a53f50b9Schristos #endif /* not HAVE_SVC_GETREQSET */
299a53f50b9Schristos       }
300a53f50b9Schristos       break;
301a53f50b9Schristos     }
302a53f50b9Schristos   }
303a53f50b9Schristos 
304a53f50b9Schristos #ifdef HAVE_SIGACTION
305a53f50b9Schristos   sigprocmask(SIG_SETMASK, &smask, NULL);
306a53f50b9Schristos #else /* not HAVE_SIGACTION */
307a53f50b9Schristos   (void) sigsetmask(smask);
308a53f50b9Schristos #endif /* not HAVE_SIGACTION */
309a53f50b9Schristos 
310a53f50b9Schristos   if (amd_state == Quit)
311a53f50b9Schristos     amd_state = Done;
312a53f50b9Schristos 
313a53f50b9Schristos   return amd_state;
314a53f50b9Schristos }
315a53f50b9Schristos 
316a53f50b9Schristos 
317a53f50b9Schristos int
mount_automounter(int ppid)318a53f50b9Schristos mount_automounter(int ppid)
319a53f50b9Schristos {
320a53f50b9Schristos   /*
321a53f50b9Schristos    * Old code replaced by rpc-trash patch.
322a53f50b9Schristos    * Erez Zadok <ezk@cs.columbia.edu>
323a53f50b9Schristos    int so = socket(AF_INET, SOCK_DGRAM, 0);
324a53f50b9Schristos    */
325a53f50b9Schristos   SVCXPRT *udp_amqp = NULL, *tcp_amqp = NULL;
326a53f50b9Schristos   int nmount, ret;
327a53f50b9Schristos   int soNFS;
328a53f50b9Schristos   int udp_soAMQ, tcp_soAMQ;
329a53f50b9Schristos   struct netconfig *udp_amqncp, *tcp_amqncp;
330a53f50b9Schristos 
331a53f50b9Schristos   /*
332a53f50b9Schristos    * This must be done first, because it attempts to bind
333a53f50b9Schristos    * to various UDP ports and we don't want anything else
334a53f50b9Schristos    * potentially taking over those ports before we get a chance
335a53f50b9Schristos    * to reserve them.
336a53f50b9Schristos    */
337a53f50b9Schristos   if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS)
338a53f50b9Schristos     restart_automounter_nodes();
339a53f50b9Schristos 
340a53f50b9Schristos   /*
341a53f50b9Schristos    * Start RPC forwarding
342a53f50b9Schristos    */
343a53f50b9Schristos   if (fwd_init() != 0)
344a53f50b9Schristos     return 3;
345a53f50b9Schristos 
346a53f50b9Schristos   /*
347a53f50b9Schristos    * Construct the root automount node
348a53f50b9Schristos    */
349a53f50b9Schristos   make_root_node();
350a53f50b9Schristos 
351a53f50b9Schristos   /*
352a53f50b9Schristos    * Pick up the pieces from a previous run
353a53f50b9Schristos    * This is likely to (indirectly) need the rpc_fwd package
354a53f50b9Schristos    * so it *must* come after the call to fwd_init().
355a53f50b9Schristos    */
356a53f50b9Schristos   if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS)
357a53f50b9Schristos     restart();
358a53f50b9Schristos 
359a53f50b9Schristos   /*
360a53f50b9Schristos    * Create the nfs service for amd
361a53f50b9Schristos    * If nfs_port is already initialized, it means we
362a53f50b9Schristos    * already created the service during restart_automounter_nodes().
363a53f50b9Schristos    */
364a53f50b9Schristos   if (nfs_port == 0) {
365*8bae5d40Schristos     ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_dispatcher,
366*8bae5d40Schristos 	get_nfs_dispatcher_version(nfs_dispatcher));
367a53f50b9Schristos     if (ret != 0)
368a53f50b9Schristos       return ret;
369a53f50b9Schristos   }
370a53f50b9Schristos   xsnprintf(pid_fsname, sizeof(pid_fsname), "%s:(pid%ld,port%u)",
371a53f50b9Schristos 	    am_get_hostname(), (long) am_mypid, nfs_port);
372a53f50b9Schristos 
373a53f50b9Schristos   /* security: if user sets -D noamq, don't even create listening socket */
374a53f50b9Schristos   if (amuDebug(D_AMQ)) {
375a53f50b9Schristos     ret = create_amq_service(&udp_soAMQ,
376a53f50b9Schristos 			     &udp_amqp,
377a53f50b9Schristos 			     &udp_amqncp,
378a53f50b9Schristos 			     &tcp_soAMQ,
379a53f50b9Schristos 			     &tcp_amqp,
380a53f50b9Schristos 			     &tcp_amqncp,
381a53f50b9Schristos 			     gopt.preferred_amq_port);
382a53f50b9Schristos     if (ret != 0)
383a53f50b9Schristos       return ret;
384a53f50b9Schristos   }
385a53f50b9Schristos 
386a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
387a53f50b9Schristos   if (amd_use_autofs) {
388a53f50b9Schristos     /*
389a53f50b9Schristos      * Create the autofs service for amd.
390a53f50b9Schristos      */
391a53f50b9Schristos     ret = create_autofs_service();
392a53f50b9Schristos     /* if autofs service fails it is OK if using a test amd */
393a53f50b9Schristos     if (ret != 0) {
394a53f50b9Schristos       plog(XLOG_WARNING, "autofs service registration failed, turning off autofs support");
395a53f50b9Schristos       amd_use_autofs = 0;
396a53f50b9Schristos     }
397a53f50b9Schristos   }
398a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
399a53f50b9Schristos 
400a53f50b9Schristos   /*
401a53f50b9Schristos    * Mount the top-level auto-mountpoints
402a53f50b9Schristos    */
403a53f50b9Schristos   nmount = mount_exported();
404a53f50b9Schristos 
405a53f50b9Schristos   /*
406a53f50b9Schristos    * Now safe to tell parent that we are up and running
407a53f50b9Schristos    */
408a53f50b9Schristos   if (ppid)
409a53f50b9Schristos     kill(ppid, SIGQUIT);
410a53f50b9Schristos 
411a53f50b9Schristos   if (nmount == 0) {
412a53f50b9Schristos     plog(XLOG_FATAL, "No work to do - quitting");
413a53f50b9Schristos     amd_state = Done;
414a53f50b9Schristos     return 0;
415a53f50b9Schristos   }
416a53f50b9Schristos 
417a53f50b9Schristos   if (amuDebug(D_AMQ)) {
418a53f50b9Schristos     /*
419a53f50b9Schristos      * Complete registration of amq (first TCP service then UDP)
420a53f50b9Schristos      */
421a53f50b9Schristos     int tcp_ok = 0, udp_ok = 0;
422a53f50b9Schristos 
423a53f50b9Schristos     unregister_amq();	 /* unregister leftover Amd, if any, just in case */
424a53f50b9Schristos 
425a53f50b9Schristos     tcp_ok = amu_svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION,
426a53f50b9Schristos 			      amq_program_1, IPPROTO_TCP, tcp_amqncp);
427a53f50b9Schristos     if (!tcp_ok)
428a53f50b9Schristos       plog(XLOG_FATAL,
429a53f50b9Schristos 	   "unable to register (AMQ_PROGRAM=%lu, AMQ_VERSION, tcp)",
430a53f50b9Schristos 	   get_amd_program_number());
431a53f50b9Schristos 
432a53f50b9Schristos     udp_ok = amu_svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION,
433a53f50b9Schristos 			      amq_program_1, IPPROTO_UDP, udp_amqncp);
434a53f50b9Schristos     if (!udp_ok)
435a53f50b9Schristos       plog(XLOG_FATAL,
436a53f50b9Schristos 	   "unable to register (AMQ_PROGRAM=%lu, AMQ_VERSION, udp)",
437a53f50b9Schristos 	   get_amd_program_number());
438a53f50b9Schristos 
439a53f50b9Schristos     /* return error only if both failed */
440a53f50b9Schristos     if (!tcp_ok && !udp_ok) {
441a53f50b9Schristos       amd_state = Done;
442a53f50b9Schristos       return 3;
443a53f50b9Schristos     }
444a53f50b9Schristos   }
445a53f50b9Schristos 
446a53f50b9Schristos   /*
447a53f50b9Schristos    * Start timeout_mp rolling
448a53f50b9Schristos    */
449a53f50b9Schristos   reschedule_timeout_mp();
450a53f50b9Schristos 
451a53f50b9Schristos   /*
452a53f50b9Schristos    * Start the server
453a53f50b9Schristos    */
454a53f50b9Schristos   if (run_rpc() != Done) {
455a53f50b9Schristos     plog(XLOG_FATAL, "run_rpc failed");
456a53f50b9Schristos     amd_state = Done;
457a53f50b9Schristos   }
458a53f50b9Schristos   return 0;
459a53f50b9Schristos }
460