PageRenderTime 50ms CodeModel.GetById 2ms app.highlight 43ms RepoModel.GetById 2ms app.codeStats 0ms

/src/pdsh/rcmd.c

https://code.google.com/
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 */