/src/pdsh/rcmd.c
C | 432 lines | 291 code | 87 blank | 54 comment | 62 complexity | f311124f9d0b785b6750311ce82bb47f MD5 | raw file
1/*****************************************************************************\ 2 * $Id$ 3 ***************************************************************************** 4 * Copyright (C) 2005-2006 The Regents of the University of California. 5 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 6 * Written by Mark Grondona <mgrondona@llnl.gov>. 7 * UCRL-CODE-2003-005. 8 * 9 * This file is part of Pdsh, a parallel remote shell program. 10 * For details, see <http://www.llnl.gov/linux/pdsh/>. 11 * 12 * Pdsh is free software; you can redistribute it and/or modify it under 13 * the terms of the GNU General Public License as published by the Free 14 * Software Foundation; either version 2 of the License, or (at your option) 15 * any later version. 16 * 17 * Pdsh is distributed in the hope that it will be useful, but WITHOUT ANY 18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 20 * details. 21 * 22 * You should have received a copy of the GNU General Public License along 23 * with Pdsh; if not, write to the Free Software Foundation, Inc., 24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 25\*****************************************************************************/ 26#if HAVE_CONFIG_H 27# include <config.h> 28#endif 29 30#include <assert.h> 31#include <string.h> 32#include <stdlib.h> 33#include <errno.h> 34 35#include "src/common/err.h" 36#include "src/common/xmalloc.h" 37#include "src/common/xstring.h" 38#include "src/common/list.h" 39#include "opt.h" 40#include "mod.h" 41#include "rcmd.h" 42 43/* 44 * Ordered preference for determining default rcmd method. 45 * Warning: If none of these modules are loaded, there will be no default. 46 */ 47static char * rcmd_rank[] = 48#if defined(RCMD_RANK_LIST) 49 { RCMD_RANK_LIST, NULL }; 50#else 51 { "mrsh", "rsh", "ssh", "krb4", "qsh", "mqsh", "exec", "xcpu", NULL }; 52#endif /* RCMD_RANK_LIST */ 53 54struct rcmd_module { 55 char * name; 56 mod_t mod; 57 struct rcmd_options options; 58 RcmdInitF init; 59 RcmdSigF signal; 60 RcmdF rcmd; 61 RcmdDestroyF rcmd_destroy; 62}; 63 64struct node_rcmd_info { 65 char *hostname; 66 char *username; 67 struct rcmd_module *rmod; 68}; 69 70static List host_info_list = NULL; 71static List rcmd_module_list = NULL; 72 73static struct rcmd_module *default_rcmd_module = NULL; 74static struct rcmd_module *current_rcmd_module = NULL; 75 76static struct node_rcmd_info * 77node_rcmd_info_create (char *hostname, char *user, struct rcmd_module *module) 78{ 79 struct node_rcmd_info *n = Malloc (sizeof (*n)); 80 81 if (!n) 82 return NULL; 83 84 n->hostname = Strdup (hostname); 85 n->username = Strdup (user); 86 n->rmod = module; 87 88 return (n); 89} 90 91static void node_rcmd_info_destroy (struct node_rcmd_info *n) 92{ 93 if (!n) 94 return; 95 96 Free ((void **)&n->hostname); 97 if (n->username) 98 Free ((void **)&n->username); 99 Free ((void **)&n); 100} 101 102struct rcmd_module * rcmd_module_create (mod_t mod) 103{ 104 struct rcmd_module *rmod = Malloc (sizeof (*rmod)); 105 106 rmod->mod = mod; 107 rmod->name = mod_get_name (mod); 108 109 if (!(rmod->init = (RcmdInitF) mod_get_rcmd_init(mod))) { 110 err("Unable to resolve \"rcmd_init\" in module \"%s\"\n", 111 mod_get_name(mod)); 112 goto fail; 113 } 114 115 if (!(rmod->signal = (RcmdSigF) mod_get_rcmd_signal(mod))) { 116 err("Unable to resolve \"rcmd_signal\" in module \"%s\"\n", 117 mod_get_name(mod)); 118 goto fail; 119 } 120 121 if (!(rmod->rcmd = (RcmdF) mod_get_rcmd(mod))) { 122 err("Unable to resolve \"rcmd\" in module \"%s\"\n", 123 mod_get_name(mod)); 124 goto fail; 125 } 126 127 /* 128 * Destroy function not required 129 */ 130 rmod->rcmd_destroy = (RcmdDestroyF) mod_get_rcmd_destroy (mod); 131 132 rmod->options.resolve_hosts = 1; 133 134 return (rmod); 135 136 fail: 137 Free ((void **) &rmod); 138 return (NULL); 139} 140 141static void rcmd_module_destroy (struct rcmd_module *rmod) 142{ 143 Free ((void **) &rmod); 144} 145 146static int find_rcmd_module (struct rcmd_module *x, char *name) 147{ 148 return (strcmp (x->name, name) == 0); 149} 150 151static int find_host (struct node_rcmd_info *x, char *hostname) 152{ 153 return (strcmp (x->hostname, hostname) == 0); 154} 155 156static struct node_rcmd_info * host_rcmd_info (char *host) 157{ 158 if (host_info_list == NULL) 159 return (NULL); 160 161 return (list_find_first (host_info_list, (ListFindF) find_host, host)); 162} 163 164static struct rcmd_module * rcmd_module_register (char *name) 165{ 166 mod_t mod = NULL; 167 struct rcmd_module *rmod = NULL; 168 169 if (rcmd_module_list == NULL) 170 rcmd_module_list = list_create ((ListDelF) rcmd_module_destroy); 171 else 172 rmod = list_find_first (rcmd_module_list, 173 (ListFindF) find_rcmd_module, 174 name); 175 if (rmod != NULL) 176 return (rmod); 177 178 if (!(mod = mod_get_module ("rcmd", name))) { 179 err ("No such rcmd module \"%s\"\n", name); 180 return (NULL); 181 } 182 183 if (!(rmod = rcmd_module_create (mod))) 184 return (NULL); 185 186 if (!list_append (rcmd_module_list, rmod)) { 187 err ("Failed to append rcmd module \"%s\"\n", name); 188 rcmd_module_destroy (rmod); 189 return (NULL); 190 } 191 192 return (rmod); 193} 194 195static int hostlist_register_rcmd (const char *hosts, struct rcmd_module *rmod, 196 char *user) 197{ 198 hostlist_t hl = hostlist_create (hosts); 199 char * host; 200 201 if (hl == NULL) 202 return (-1); 203 204 if (host_info_list == NULL) 205 host_info_list = list_create ((ListDelF) node_rcmd_info_destroy); 206 207 while ((host = hostlist_pop (hl))) { 208 struct node_rcmd_info *n = NULL; 209 210 /* 211 * Do not override previously installed host info. First registered 212 * rcmd type for a host wins. This allows command line to override 213 * everything else. 214 */ 215 if (list_find_first (host_info_list, (ListFindF) find_host, host)) 216 continue; 217 218 if ((n = node_rcmd_info_create (host, user, rmod)) == NULL) 219 errx ("Failed to create rcmd info for host \"%s\"\n", host); 220 221 list_append (host_info_list, n); 222 223 free (host); 224 225 } 226 227 hostlist_destroy (hl); 228 229 return (0); 230} 231 232 233/* 234 * Walk through list of default candidate modules, starting at head, 235 * and return the first module that is loaded. 236 * Unless rcmd_default_module is already registered. 237 */ 238char * rcmd_get_default_module (void) 239{ 240 mod_t mod = NULL; 241 int i = 0; 242 const char *name = NULL; 243 244 if (default_rcmd_module != NULL) 245 return (default_rcmd_module->name); 246 247 while ((name = rcmd_rank[i++]) && !mod) 248 mod = mod_get_module ("rcmd", name); 249 250 return mod ? mod_get_name (mod) : NULL; 251} 252 253int rcmd_register_default_rcmd (char *rcmd_name) 254{ 255 struct rcmd_module *rmod = NULL; 256 if (!(rmod = rcmd_module_register (rcmd_name))) 257 return (-1); 258 default_rcmd_module = rmod; 259 return (0); 260} 261 262int rcmd_register_defaults (char *hosts, char *rcmd_name, char *user) 263{ 264 struct rcmd_module *rmod = NULL; 265 266 if (rcmd_name && !(rmod = rcmd_module_register (rcmd_name))) 267 return (-1); 268 269 /* If host list is NULL, we are registering a new global default 270 * rcmd module. Set the convenience pointer and return 271 */ 272 if (hosts == NULL) { 273 default_rcmd_module = rmod; 274 return (0); 275 } 276 277 if (hostlist_register_rcmd (hosts, rmod, user) < 0) 278 return (-1); 279 280 return (0); 281} 282 283 284struct rcmd_info * rcmd_info_create (struct rcmd_module *rmod) 285{ 286 struct rcmd_info *r = Malloc (sizeof (*r)); 287 288 if (r == NULL) 289 return (NULL); 290 291 r->fd = -1; 292 r->efd = -1; 293 r->rmod = rmod; 294 r->opts = &rmod->options; 295 r->arg = NULL; 296 r->ruser = NULL; 297 298 return (r); 299} 300 301void rcmd_info_destroy (struct rcmd_info *r) 302{ 303 Free ((void **) &r); 304} 305 306struct rcmd_info * rcmd_create (char *host) 307{ 308 struct rcmd_info *rcmd = NULL; 309 struct rcmd_module *rmod = NULL; 310 struct node_rcmd_info *n = NULL; 311 312 if ((n = host_rcmd_info (host))) { 313 rmod = n->rmod; 314 } 315 316 /* 317 * If no rcmd module use default 318 */ 319 if (rmod == NULL) { 320 if ((rmod = default_rcmd_module) == NULL) { 321 err ("%p: No rcmd module for \"%s\"\n", host); 322 return (NULL); 323 } 324 } 325 326 if ((rcmd = rcmd_info_create (rmod)) == NULL) { 327 err ("%p: Unable to allocate rcmd info for \"%s\"\n", host); 328 return (NULL); 329 } 330 331 if (n != NULL && n->username) 332 rcmd->ruser = n->username; 333 334 return (rcmd); 335} 336 337 338int rcmd_connect (struct rcmd_info *rcmd, char *ahost, char *addr, 339 char *locuser, char *remuser, char *cmd, int nodeid, 340 bool error_fd) 341{ 342 /* 343 * rcmd->ruser overrides default 344 */ 345 if (rcmd->ruser) 346 remuser = rcmd->ruser; 347 348 rcmd->fd = (*rcmd->rmod->rcmd) (ahost, addr, locuser, remuser, cmd, nodeid, 349 error_fd ? &rcmd->efd : NULL, &rcmd->arg); 350 return (rcmd->fd); 351} 352 353int rcmd_destroy (struct rcmd_info *rcmd) 354{ 355 int rc = 0; 356 357 if (rcmd == NULL) 358 return (0); 359 if (rcmd->rmod->rcmd_destroy) 360 rc = (*rcmd->rmod->rcmd_destroy) (rcmd->arg); 361 rcmd_info_destroy (rcmd); 362 363 return (rc); 364} 365 366int rcmd_signal (struct rcmd_info *rcmd, int signum) 367{ 368 assert (rcmd != NULL); 369 assert (rcmd->rmod != NULL); 370 371 return (*rcmd->rmod->signal) (rcmd->efd, rcmd->arg, signum); 372} 373 374 375int rcmd_init (opt_t *opt) 376{ 377 struct rcmd_module *r = NULL; 378 ListIterator i; 379 380 if (!rcmd_module_list) { 381 if (default_rcmd_module == NULL) 382 return (-1); 383 current_rcmd_module = default_rcmd_module; 384 (*default_rcmd_module->init) (opt); 385 current_rcmd_module = NULL; 386 return (0); 387 } 388 389 i = list_iterator_create (rcmd_module_list); 390 while ((r = list_next (i))) { 391 current_rcmd_module = r; 392 (*r->init) (opt); 393 current_rcmd_module = NULL; 394 } 395 396 list_iterator_destroy (i); 397 398 return (0); 399} 400 401int rcmd_exit (void) 402{ 403 if (host_info_list) 404 list_destroy (host_info_list); 405 if (rcmd_module_list) 406 list_destroy (rcmd_module_list); 407 408 return (0); 409} 410 411int rcmd_opt_set (int id, void * value) 412{ 413 if (current_rcmd_module == NULL) { 414 errno = ESRCH; 415 return (-1); 416 } 417 418 switch (id) { 419 case RCMD_OPT_RESOLVE_HOSTS: 420 current_rcmd_module->options.resolve_hosts = (long int) value; 421 break; 422 default: 423 errno = EINVAL; 424 return (-1); 425 } 426 427 return (0); 428} 429 430/* 431 * vi: ts=4 sw=4 expandtab 432 */