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