1/*	$NetBSD: amq_subr.c,v 1.1.1.2 2009/03/20 20:26:49 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 *    must display the following acknowledgment:
23 *      This product includes software developed by the University of
24 *      California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 *    may be used to endorse or promote products derived from this software
27 *    without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 *
42 * File: am-utils/amd/amq_subr.c
43 *
44 */
45/*
46 * Auxiliary routines for amq tool
47 */
48
49#ifdef HAVE_CONFIG_H
50# include <config.h>
51#endif /* HAVE_CONFIG_H */
52#include <am_defs.h>
53#include <amd.h>
54
55/* forward definitions */
56bool_t xdr_amq_mount_tree_node(XDR *xdrs, amq_mount_tree *objp);
57bool_t xdr_amq_mount_subtree(XDR *xdrs, amq_mount_tree *objp);
58
59
60voidp
61amqproc_null_1_svc(voidp argp, struct svc_req *rqstp)
62{
63  static char res;
64
65  return (voidp) &res;
66}
67
68
69/*
70 * Return a sub-tree of mounts
71 */
72amq_mount_tree_p *
73amqproc_mnttree_1_svc(voidp argp, struct svc_req *rqstp)
74{
75  static am_node *mp;
76
77  mp = find_ap(*(char **) argp);
78  return (amq_mount_tree_p *) ((void *)&mp);
79}
80
81
82/*
83 * Unmount a single node
84 */
85int *
86amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp)
87{
88  static int res = AMQ_UMNT_OK;
89  am_node *mp = find_ap(*(char **) argp);
90
91  if (mp)
92    forcibly_timeout_mp(mp);
93
94  return &res;
95}
96
97
98/*
99 * Synchronously unmount a single node - parent side.
100 */
101int *
102amqproc_sync_umnt_1_svc_parent(voidp argp, struct svc_req *rqstp)
103{
104  amqproc_umnt_1_svc(argp, rqstp);
105  return NULL;
106}
107
108
109/*
110 * Synchronously unmount a single node - child side.
111 */
112amq_sync_umnt *
113amqproc_sync_umnt_1_svc_child(voidp argp, struct svc_req *rqstp)
114{
115  static amq_sync_umnt rv;
116  amq_sync_umnt buf;
117  ssize_t n;
118
119  am_node *mp = find_ap(*(char **) argp);
120
121  memset(&rv, 0, sizeof(rv));
122  rv.au_etype = AMQ_UMNT_READ;
123  if (mp && mp->am_fd[0] >= 0) {
124    n = read(mp->am_fd[0], &buf, sizeof(buf));
125    if (n == sizeof(buf))
126      rv = buf;
127  }
128  return &rv;
129}
130
131
132/*
133 * Synchronously unmount a single node - use if we can't fork (asynchronous).
134 */
135amq_sync_umnt *
136amqproc_sync_umnt_1_svc_async(voidp argp, struct svc_req *rqstp)
137{
138  static amq_sync_umnt rv;
139
140  memset(&rv, 0, sizeof(rv));
141  rv.au_etype = AMQ_UMNT_FORK;
142  rv.au_errno = errno;
143
144  amqproc_umnt_1_svc(argp, rqstp);
145
146  return &rv;
147}
148
149
150/*
151 * Return global statistics
152 */
153amq_mount_stats *
154amqproc_stats_1_svc(voidp argp, struct svc_req *rqstp)
155{
156  return (amq_mount_stats *) ((void *)&amd_stats);
157}
158
159
160/*
161 * Return the entire tree of mount nodes
162 */
163amq_mount_tree_list *
164amqproc_export_1_svc(voidp argp, struct svc_req *rqstp)
165{
166  static amq_mount_tree_list aml;
167  static am_node *mp;
168
169  mp = get_exported_ap(0);
170  aml.amq_mount_tree_list_val = (amq_mount_tree_p *) ((void *) &mp);
171  aml.amq_mount_tree_list_len = 1;	/* XXX */
172
173  return &aml;
174}
175
176
177int *
178amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp)
179{
180  static int rc;
181  amq_setopt *opt = (amq_setopt *) argp;
182
183  rc = 0;
184
185  switch (opt->as_opt) {
186
187  case AMOPT_DEBUG:
188    if (debug_option(opt->as_str))
189      rc = EINVAL;
190    break;
191
192  case AMOPT_LOGFILE:
193    if (gopt.logfile && opt->as_str
194	&& STREQ(gopt.logfile, opt->as_str)) {
195      if (switch_to_logfile(opt->as_str, orig_umask, 0))
196	rc = EINVAL;
197    } else {
198      rc = EACCES;
199    }
200    break;
201
202  case AMOPT_XLOG:
203    if (switch_option(opt->as_str))
204      rc = EINVAL;
205    break;
206
207  case AMOPT_FLUSHMAPC:
208    if (amd_state == Run) {
209      plog(XLOG_INFO, "amq says flush cache");
210      do_mapc_reload = 0;
211      flush_nfs_fhandle_cache((fserver *) NULL);
212      flush_srvr_nfs_cache((fserver *) NULL);
213    }
214    break;
215  }
216
217  return &rc;
218}
219
220
221amq_mount_info_list *
222amqproc_getmntfs_1_svc(voidp argp, struct svc_req *rqstp)
223{
224  return (amq_mount_info_list *) ((void *)&mfhead);	/* XXX */
225}
226
227
228amq_string *
229amqproc_getvers_1_svc(voidp argp, struct svc_req *rqstp)
230{
231  static amq_string res;
232
233  res = get_version_string();
234  return &res;
235}
236
237
238/* get PID of remote amd */
239int *
240amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp)
241{
242  static int res;
243
244  res = getpid();
245  return &res;
246}
247
248
249/*
250 * Process PAWD string of remote pawd tool.
251 *
252 * We repeat the resolution of the string until the resolved string resolves
253 * to itself.  This ensures that we follow path resolutions through all
254 * possible Amd mount points until we reach some sort of convergence.  To
255 * prevent possible infinite loops, we break out of this loop if the strings
256 * do not converge after MAX_PAWD_TRIES times.
257 */
258amq_string *
259amqproc_pawd_1_svc(voidp argp, struct svc_req *rqstp)
260{
261  static amq_string res;
262#define MAX_PAWD_TRIES 10
263  int index, len, maxagain = MAX_PAWD_TRIES;
264  am_node *mp;
265  char *mountpoint;
266  char *dir = *(char **) argp;
267  static char tmp_buf[MAXPATHLEN];
268  char prev_buf[MAXPATHLEN];
269
270  tmp_buf[0] = prev_buf[0] = '\0'; /* default is empty string: no match */
271  do {
272    for (mp = get_first_exported_ap(&index);
273	 mp;
274	 mp = get_next_exported_ap(&index)) {
275      if (STREQ(mp->am_mnt->mf_ops->fs_type, "toplvl"))
276	continue;
277      if (STREQ(mp->am_mnt->mf_ops->fs_type, "auto"))
278	continue;
279      mountpoint = (mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
280      len = strlen(mountpoint);
281      if (len == 0)
282	continue;
283      if (!NSTREQ(mountpoint, dir, len))
284	continue;
285      if (dir[len] != '\0' && dir[len] != '/')
286	continue;
287      xstrlcpy(tmp_buf, mp->am_path, sizeof(tmp_buf));
288      xstrlcat(tmp_buf, &dir[len], sizeof(tmp_buf));
289      break;
290    } /* end of "for" loop */
291    /* once tmp_buf and prev_buf are equal, break out of "do" loop */
292    if (STREQ(tmp_buf, prev_buf))
293      break;
294    else
295      xstrlcpy(prev_buf, tmp_buf, sizeof(prev_buf));
296  } while (--maxagain);
297  /* check if we couldn't resolve the string after MAX_PAWD_TRIES times */
298  if (maxagain <= 0)
299    plog(XLOG_WARNING, "path \"%s\" did not resolve after %d tries",
300	 tmp_buf, MAX_PAWD_TRIES);
301
302  res = tmp_buf;
303  return &res;
304}
305
306
307/*
308 * XDR routines.
309 */
310
311
312bool_t
313xdr_amq_setopt(XDR *xdrs, amq_setopt *objp)
314{
315  if (!xdr_enum(xdrs, (enum_t *) ((voidp) &objp->as_opt))) {
316    return (FALSE);
317  }
318  if (!xdr_string(xdrs, &objp->as_str, AMQ_STRLEN)) {
319    return (FALSE);
320  }
321  return (TRUE);
322}
323
324
325/*
326 * More XDR routines  - Should be used for OUTPUT ONLY.
327 */
328bool_t
329xdr_amq_mount_tree_node(XDR *xdrs, amq_mount_tree *objp)
330{
331  am_node *mp = (am_node *) objp;
332  long mtime;
333
334  if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_info)) {
335    return (FALSE);
336  }
337  if (!xdr_amq_string(xdrs, &mp->am_path)) {
338    return (FALSE);
339  }
340  if (!xdr_amq_string(xdrs, mp->am_link ? &mp->am_link : &mp->am_mnt->mf_mount)) {
341    return (FALSE);
342  }
343  if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_ops->fs_type)) {
344    return (FALSE);
345  }
346  mtime = mp->am_stats.s_mtime;
347  if (!xdr_long(xdrs, &mtime)) {
348    return (FALSE);
349  }
350  if (!xdr_u_short(xdrs, &mp->am_stats.s_uid)) {
351    return (FALSE);
352  }
353  if (!xdr_int(xdrs, &mp->am_stats.s_getattr)) {
354    return (FALSE);
355  }
356  if (!xdr_int(xdrs, &mp->am_stats.s_lookup)) {
357    return (FALSE);
358  }
359  if (!xdr_int(xdrs, &mp->am_stats.s_readdir)) {
360    return (FALSE);
361  }
362  if (!xdr_int(xdrs, &mp->am_stats.s_readlink)) {
363    return (FALSE);
364  }
365  if (!xdr_int(xdrs, &mp->am_stats.s_statfs)) {
366    return (FALSE);
367  }
368  return (TRUE);
369}
370
371
372bool_t
373xdr_amq_mount_subtree(XDR *xdrs, amq_mount_tree *objp)
374{
375  am_node *mp = (am_node *) objp;
376
377  if (!xdr_amq_mount_tree_node(xdrs, objp)) {
378    return (FALSE);
379  }
380  if (!xdr_pointer(xdrs,
381		   (char **) ((voidp) &mp->am_osib),
382		   sizeof(amq_mount_tree),
383		   (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
384    return (FALSE);
385  }
386  if (!xdr_pointer(xdrs,
387		   (char **) ((voidp) &mp->am_child),
388		   sizeof(amq_mount_tree),
389		   (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
390    return (FALSE);
391  }
392  return (TRUE);
393}
394
395
396bool_t
397xdr_amq_mount_tree(XDR *xdrs, amq_mount_tree *objp)
398{
399  am_node *mp = (am_node *) objp;
400  am_node *mnil = NULL;
401
402  if (!xdr_amq_mount_tree_node(xdrs, objp)) {
403    return (FALSE);
404  }
405  if (!xdr_pointer(xdrs,
406		   (char **) ((voidp) &mnil),
407		   sizeof(amq_mount_tree),
408		   (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
409    return (FALSE);
410  }
411  if (!xdr_pointer(xdrs,
412		   (char **) ((voidp) &mp->am_child),
413		   sizeof(amq_mount_tree),
414		   (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
415    return (FALSE);
416  }
417  return (TRUE);
418}
419
420
421bool_t
422xdr_amq_mount_tree_p(XDR *xdrs, amq_mount_tree_p *objp)
423{
424  if (!xdr_pointer(xdrs, (char **) objp, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) {
425    return (FALSE);
426  }
427  return (TRUE);
428}
429
430
431bool_t
432xdr_amq_mount_stats(XDR *xdrs, amq_mount_stats *objp)
433{
434  if (!xdr_int(xdrs, &objp->as_drops)) {
435    return (FALSE);
436  }
437  if (!xdr_int(xdrs, &objp->as_stale)) {
438    return (FALSE);
439  }
440  if (!xdr_int(xdrs, &objp->as_mok)) {
441    return (FALSE);
442  }
443  if (!xdr_int(xdrs, &objp->as_merr)) {
444    return (FALSE);
445  }
446  if (!xdr_int(xdrs, &objp->as_uerr)) {
447    return (FALSE);
448  }
449  return (TRUE);
450}
451
452
453
454bool_t
455xdr_amq_mount_tree_list(XDR *xdrs, amq_mount_tree_list *objp)
456{
457  if (!xdr_array(xdrs,
458		 (char **) ((voidp) &objp->amq_mount_tree_list_val),
459		 (u_int *) &objp->amq_mount_tree_list_len,
460		 ~0,
461		 sizeof(amq_mount_tree_p),
462		 (XDRPROC_T_TYPE) xdr_amq_mount_tree_p)) {
463    return (FALSE);
464  }
465  return (TRUE);
466}
467
468
469
470/*
471 * Compute length of list
472 */
473bool_t
474xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead)
475{
476  mntfs *mf;
477  u_int len = 0;
478
479  for (mf = AM_LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
480    if (!(mf->mf_fsflags & FS_AMQINFO))
481      continue;
482    len++;
483  }
484  xdr_u_int(xdrs, &len);
485
486  /*
487   * Send individual data items
488   */
489  for (mf = AM_LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
490    int up;
491    if (!(mf->mf_fsflags & FS_AMQINFO))
492      continue;
493
494    if (!xdr_amq_string(xdrs, &mf->mf_ops->fs_type)) {
495      return (FALSE);
496    }
497    if (!xdr_amq_string(xdrs, &mf->mf_mount)) {
498      return (FALSE);
499    }
500    if (!xdr_amq_string(xdrs, &mf->mf_info)) {
501      return (FALSE);
502    }
503    if (!xdr_amq_string(xdrs, &mf->mf_server->fs_host)) {
504      return (FALSE);
505    }
506    if (!xdr_int(xdrs, &mf->mf_error)) {
507      return (FALSE);
508    }
509    if (!xdr_int(xdrs, &mf->mf_refc)) {
510      return (FALSE);
511    }
512    if (FSRV_ERROR(mf->mf_server) || FSRV_ISDOWN(mf->mf_server))
513      up = 0;
514    else if (FSRV_ISUP(mf->mf_server))
515      up = 1;
516    else
517      up = -1;
518    if (!xdr_int(xdrs, &up)) {
519      return (FALSE);
520    }
521  }
522  return (TRUE);
523}
524
525
526bool_t
527xdr_pri_free(XDRPROC_T_TYPE xdr_args, caddr_t args_ptr)
528{
529  XDR xdr;
530
531  xdr.x_op = XDR_FREE;
532  return ((*xdr_args) (&xdr, (caddr_t *) args_ptr));
533}
534