rpc.statd(8): Fix 2 cases where syslog() was passed too many args.
[dragonfly.git] / usr.sbin / rpc.statd / procs.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1995
3 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed for the FreeBSD project
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
1de703da 32 * $FreeBSD: src/usr.sbin/rpc.statd/procs.c,v 1.4.2.2 2002/07/11 17:41:28 alfred Exp $
2e3ed54d 33 * $DragonFly: src/usr.sbin/rpc.statd/procs.c,v 1.3 2005/11/25 00:32:49 swildner Exp $
984263bc
MD
34 */
35
984263bc
MD
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include <rpc/rpc.h>
42#include <syslog.h>
43#include <netdb.h> /* for gethostbyname() */
44
45#include "statd.h"
46
47/* sm_stat_1 --------------------------------------------------------------- */
48/*
49 Purpose: RPC call to enquire if a host can be monitored
50 Returns: TRUE for any hostname that can be looked up to give
51 an address.
52*/
53
2e3ed54d
SW
54struct sm_stat_res *
55sm_stat_1_svc(sm_name *arg, struct svc_req *req)
984263bc
MD
56{
57 static sm_stat_res res;
58
59 if (debug) syslog(LOG_DEBUG, "stat called for host %s", arg->mon_name);
60
61 if (gethostbyname(arg->mon_name)) res.res_stat = stat_succ;
62 else
63 {
64 syslog(LOG_ERR, "invalid hostname to sm_stat: %s", arg->mon_name);
65 res.res_stat = stat_fail;
66 }
67
68 res.state = status_info->ourState;
69 return (&res);
70}
71
72/* sm_mon_1 ---------------------------------------------------------------- */
73/*
74 Purpose: RPC procedure to establish a monitor request
75 Returns: Success, unless lack of resources prevents
76 the necessary structures from being set up
77 to record the request, or if the hostname is not
78 valid (as judged by gethostbyname())
79*/
80
2e3ed54d
SW
81struct sm_stat_res *
82sm_mon_1_svc(mon *arg, struct svc_req *req)
984263bc
MD
83{
84 static sm_stat_res res;
85 HostInfo *hp;
86 MonList *lp;
87
88 if (debug)
89 {
90 syslog(LOG_DEBUG, "monitor request for host %s", arg->mon_id.mon_name);
91 syslog(LOG_DEBUG, "recall host: %s prog: %d ver: %d proc: %d",
4a65f651 92 arg->mon_id.my_id.my_name,
984263bc
MD
93 arg->mon_id.my_id.my_prog, arg->mon_id.my_id.my_vers,
94 arg->mon_id.my_id.my_proc);
95 }
96
97 res.res_stat = stat_fail; /* Assume fail until set otherwise */
98 res.state = status_info->ourState;
99
100 /* Find existing host entry, or create one if not found */
101 /* If find_host() fails, it will have logged the error already. */
102 if (!gethostbyname(arg->mon_id.mon_name))
103 {
104 syslog(LOG_ERR, "Invalid hostname to sm_mon: %s", arg->mon_id.mon_name);
105 }
106 else if ((hp = find_host(arg->mon_id.mon_name, TRUE)))
107 {
108 lp = (MonList *)malloc(sizeof(MonList));
109 if (!lp)
110 {
111 syslog(LOG_ERR, "Out of memory");
112 }
113 else
114 {
115 strncpy(lp->notifyHost, arg->mon_id.my_id.my_name, SM_MAXSTRLEN);
116 lp->notifyProg = arg->mon_id.my_id.my_prog;
117 lp->notifyVers = arg->mon_id.my_id.my_vers;
118 lp->notifyProc = arg->mon_id.my_id.my_proc;
119 memcpy(lp->notifyData, arg->priv, sizeof(lp->notifyData));
120
121 lp->next = hp->monList;
122 hp->monList = lp;
123 sync_file();
124
125 res.res_stat = stat_succ; /* Report success */
126 }
127 }
128
129 return (&res);
130}
131
132/* do_unmon ---------------------------------------------------------------- */
133/*
134 Purpose: Remove a monitor request from a host
135 Returns: TRUE if found, FALSE if not found.
136 Notes: Common code from sm_unmon_1_svc and sm_unmon_all_1_svc
137 In the unlikely event of more than one identical monitor
138 request, all are removed.
139*/
140
2e3ed54d
SW
141static int
142do_unmon(HostInfo *hp, my_id *idp)
984263bc
MD
143{
144 MonList *lp, *next;
145 MonList *last = NULL;
146 int result = FALSE;
147
148 lp = hp->monList;
149 while (lp)
150 {
151 if (!strncasecmp(idp->my_name, lp->notifyHost, SM_MAXSTRLEN)
152 && (idp->my_prog == lp->notifyProg) && (idp->my_proc == lp->notifyProc)
153 && (idp->my_vers == lp->notifyVers))
154 {
155 /* found one. Unhook from chain and free. */
156 next = lp->next;
157 if (last) last->next = next;
158 else hp->monList = next;
159 free(lp);
160 lp = next;
161 result = TRUE;
162 }
163 else
164 {
165 last = lp;
166 lp = lp->next;
167 }
168 }
169 return (result);
170}
171
172/* sm_unmon_1 -------------------------------------------------------------- */
173/*
174 Purpose: RPC procedure to release a monitor request.
175 Returns: Local machine's status number
176 Notes: The supplied mon_id should match the value passed in an
177 earlier call to sm_mon_1
178*/
179
2e3ed54d
SW
180struct sm_stat *
181sm_unmon_1_svc(mon_id *arg, struct svc_req *req)
984263bc
MD
182{
183 static sm_stat res;
184 HostInfo *hp;
185
186 if (debug)
187 {
188 syslog(LOG_DEBUG, "un-monitor request for host %s", arg->mon_name);
189 syslog(LOG_DEBUG, "recall host: %s prog: %d ver: %d proc: %d",
4a65f651 190 arg->my_id.my_name, arg->my_id.my_prog,
984263bc
MD
191 arg->my_id.my_vers, arg->my_id.my_proc);
192 }
193
194 if ((hp = find_host(arg->mon_name, FALSE)))
195 {
196 if (do_unmon(hp, &arg->my_id)) sync_file();
197 else
198 {
199 syslog(LOG_ERR, "unmon request from %s, no matching monitor",
200 arg->my_id.my_name);
201 }
202 }
203 else syslog(LOG_ERR, "unmon request from %s for unknown host %s",
204 arg->my_id.my_name, arg->mon_name);
205
206 res.state = status_info->ourState;
207
208 return (&res);
209}
210
211/* sm_unmon_all_1 ---------------------------------------------------------- */
212/*
213 Purpose: RPC procedure to release monitor requests.
214 Returns: Local machine's status number
215 Notes: Releases all monitor requests (if any) from the specified
216 host and program number.
217*/
218
2e3ed54d
SW
219struct sm_stat *
220sm_unmon_all_1_svc(my_id *arg, struct svc_req *req)
984263bc
MD
221{
222 static sm_stat res;
223 HostInfo *hp;
224 int i;
225
226 if (debug)
227 {
228 syslog(LOG_DEBUG, "unmon_all for host: %s prog: %d ver: %d proc: %d",
229 arg->my_name, arg->my_prog, arg->my_vers, arg->my_proc);
230 }
231
232 for (i = status_info->noOfHosts, hp = status_info->hosts; i; i--, hp++)
233 {
234 do_unmon(hp, arg);
235 }
236 sync_file();
237
238 res.state = status_info->ourState;
239
240 return (&res);
241}
242
243/* sm_simu_crash_1 --------------------------------------------------------- */
244/*
245 Purpose: RPC procedure to simulate a crash
246 Returns: Nothing
247 Notes: Standardised mechanism for debug purposes
248 The specification says that we should drop all of our
249 status information (apart from the list of monitored hosts
250 on disc). However, this would confuse the rpc.lockd
251 which would be unaware that all of its monitor requests
252 had been silently junked. Hence we in fact retain all
253 current requests and simply increment the status counter
254 and inform all hosts on the monitor list.
255*/
256
2e3ed54d
SW
257void *
258sm_simu_crash_1_svc(void *v, struct svc_req *req)
984263bc
MD
259{
260 static char dummy;
261 int work_to_do;
262 HostInfo *hp;
263 int i;
264
265 if (debug) syslog(LOG_DEBUG, "simu_crash called!!");
266
267 /* Simulate crash by setting notify-required flag on all monitored */
268 /* hosts, and incrementing our status number. notify_hosts() is */
269 /* then called to fork a process to do the notifications. */
270
271 for (i = status_info->noOfHosts, hp = status_info->hosts; i ; i--, hp++)
272 {
273 if (hp->monList)
274 {
275 work_to_do = TRUE;
276 hp->notifyReqd = TRUE;
277 }
278 }
279 status_info->ourState += 2; /* always even numbers if not crashed */
280
281 if (work_to_do) notify_hosts();
282
283 return (&dummy);
284}
285
286/* sm_notify_1 ------------------------------------------------------------- */
287/*
288 Purpose: RPC procedure notifying local statd of the crash of another
289 Returns: Nothing
290 Notes: There is danger of deadlock, since it is quite likely that
291 the client procedure that we call will in turn call us
292 to remove or adjust the monitor request.
293 We therefore fork() a process to do the notifications.
294 Note that the main HostInfo structure is in a mmap()
295 region and so will be shared with the child, but the
296 monList pointed to by the HostInfo is in normal memory.
297 Hence if we read the monList before forking, we are
298 protected from the parent servicing other requests
299 that modify the list.
300*/
301
2e3ed54d
SW
302void *
303sm_notify_1_svc(stat_chge *arg, struct svc_req *req)
984263bc
MD
304{
305 struct timeval timeout = { 20, 0 }; /* 20 secs timeout */
306 CLIENT *cli;
307 static char dummy;
308 sm_status tx_arg; /* arg sent to callback procedure */
309 MonList *lp;
310 HostInfo *hp;
311 pid_t pid;
312
313 if (debug) syslog(LOG_DEBUG, "notify from host %s, new state %d",
314 arg->mon_name, arg->state);
315
316 hp = find_host(arg->mon_name, FALSE);
317 if (!hp)
318 {
319 /* Never heard of this host - why is it notifying us? */
320 syslog(LOG_ERR, "Unsolicited notification from host %s", arg->mon_name);
321 return (&dummy);
322 }
323 lp = hp->monList;
324 if (!lp) return (&dummy); /* We know this host, but have no */
325 /* outstanding requests. */
326 pid = fork();
327 if (pid == -1)
328 {
329 syslog(LOG_ERR, "Unable to fork notify process - %s", strerror(errno));
330 return (NULL);
331 }
332 if (pid) return (&dummy); /* Parent returns */
333
334 while (lp)
335 {
336 tx_arg.mon_name = arg->mon_name;
337 tx_arg.state = arg->state;
338 memcpy(tx_arg.priv, lp->notifyData, sizeof(tx_arg.priv));
339 cli = clnt_create(lp->notifyHost, lp->notifyProg, lp->notifyVers, "udp");
340 if (!cli)
341 {
342 syslog(LOG_ERR, "Failed to contact host %s%s", lp->notifyHost,
343 clnt_spcreateerror(""));
344 }
345 else
346 {
63ab6604
SW
347 if (clnt_call(cli, lp->notifyProc, (xdrproc_t)xdr_sm_status, &tx_arg,
348 (xdrproc_t)xdr_void, &dummy, timeout) != RPC_SUCCESS)
984263bc
MD
349 {
350 syslog(LOG_ERR, "Failed to call rpc.statd client at host %s",
351 lp->notifyHost);
352 }
353 clnt_destroy(cli);
354 }
355 lp = lp->next;
356 }
357
358 exit (0); /* Child quits */
359}