PageRenderTime 25ms CodeModel.GetById 4ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/modules/xrcmd.c

https://code.google.com/
C | 350 lines | 223 code | 27 blank | 100 comment | 45 complexity | 55fdaa8fd5adf12223e0c8b09af183c1 MD5 | raw file
  1/*****************************************************************************\
  2 *  $Id$
  3 *****************************************************************************
  4 *  Copyright (C) 2001-2006 The Regents of the University of California.
  5 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  6 *  Written by Jim Garlick <garlick@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
 27/*
 28 * This code is based on the BSD rcmd.c with MT safety added, and the 
 29 * interface changed.  Original UC regents header included below.
 30 */
 31
 32/*
 33 * Copyright (c) 1983, 1993, 1994
 34 *	The Regents of the University of California.  All rights reserved.
 35 *
 36 * Redistribution and use in source and binary forms, with or without
 37 * modification, are permitted provided that the following conditions
 38 * are met:
 39 * 1. Redistributions of source code must retain the above copyright
 40 *    notice, this list of conditions and the following disclaimer.
 41 * 2. Redistributions in binary form must reproduce the above copyright
 42 *    notice, this list of conditions and the following disclaimer in the
 43 *    documentation and/or other materials provided with the distribution.
 44 * 3. All advertising materials mentioning features or use of this software
 45 *    must display the following acknowledgement:
 46 *	This product includes software developed by the University of
 47 *	California, Berkeley and its contributors.
 48 * 4. Neither the name of the University nor the names of its contributors
 49 *    may be used to endorse or promote products derived from this software
 50 *    without specific prior written permission.
 51 *
 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 55 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 62 * SUCH DAMAGE.
 63 */
 64
 65/*
 66 * Changes:
 67 *  - MT save 
 68 *  - changed functional interface.
 69 */
 70
 71#if defined(LIBC_SCCS) && !defined(lint)
 72static char sccsid[] = "@(#)rcmd.c	8.3 (Berkeley) 3/26/94";
 73#endif                          /* LIBC_SCCS and not lint */
 74
 75#if     HAVE_CONFIG_H
 76#include "config.h"
 77#endif
 78
 79#include <sys/param.h>
 80#include <sys/types.h>
 81#include <sys/time.h>
 82#include <sys/socket.h>
 83#include <sys/stat.h>
 84#include <stdio.h>
 85#if	HAVE_PTHREAD_H
 86#include <pthread.h>
 87#endif
 88#include <netinet/in.h>
 89#include <arpa/inet.h>
 90
 91#include <signal.h>
 92#if HAVE_FCNTL_H
 93#include <fcntl.h>
 94#endif
 95#include <netdb.h>
 96#if HAVE_UNISTD_H
 97#include <unistd.h>
 98#endif
 99#include <pwd.h>
100#include <errno.h>
101#include <ctype.h>
102#include <string.h>
103#if HAVE_STRINGS_H
104#include <strings.h>            /* AIX FD_SET calls bzero */
105#endif
106
107#include "src/common/err.h"
108#include "src/common/list.h"
109#include "src/common/xpoll.h"
110#include "src/pdsh/dsh.h"
111#include "src/pdsh/mod.h"
112#include "src/pdsh/privsep.h"
113
114#define RSH_PORT 514
115
116#if STATIC_MODULES
117#  define pdsh_module_info xrcmd_module_info
118#  define pdsh_module_priority xrcmd_module_priority
119#endif    
120
121int pdsh_module_priority = DEFAULT_MODULE_PRIORITY;
122
123static int xrcmd_init(opt_t *);
124static int xrcmd_signal(int, void *, int);
125static int xrcmd(char *, char *, char *, char *, char *, int, int *, void **); 
126
127/* 
128 * Export pdsh module operations structure
129 */
130struct pdsh_module_operations xrcmd_module_ops = {
131  (ModInitF)       NULL, 
132  (ModExitF)       NULL, 
133  (ModReadWcollF)  NULL,
134  (ModPostOpF)     NULL,
135};
136
137/*
138 *  Export rcmd module operations
139 */
140struct pdsh_rcmd_operations xrcmd_rcmd_ops = {
141    (RcmdInitF)  xrcmd_init,
142    (RcmdSigF)   xrcmd_signal,
143    (RcmdF)      xrcmd,
144};
145
146/* 
147 * Export module options
148 */
149struct pdsh_module_option xrcmd_module_options[] = 
150 { 
151   PDSH_OPT_TABLE_END
152 };
153
154/* 
155 * Xrcmd module info 
156 */
157struct pdsh_module pdsh_module_info = {
158  "rcmd",
159  "rsh",
160  "Jim Garlick <garlick@llnl.gov>",
161  "BSD rcmd connect method",
162  DSH | PCP, 
163
164  &xrcmd_module_ops,
165  &xrcmd_rcmd_ops,
166  &xrcmd_module_options[0],
167};
168
169static int xrcmd_init(opt_t * opt)
170{
171    /* not implemented */
172    return 0;
173}
174
175/*
176 * Use rcmd backchannel to propagate signals.
177 * 	efd (IN)	file descriptor connected socket (-1 if not used)
178 *	signum (IN)	signal number to send
179 */
180static int xrcmd_signal(int efd, void *arg, int signum)
181{
182    char c;
183
184    if (efd >= 0) {
185        /* set non-blocking mode for write - just take our best shot */
186        if (fcntl(efd, F_SETFL, O_NONBLOCK) < 0)
187            err("%p: fcntl: %m\n");
188        c = (char) signum;
189        write(efd, &c, 1);
190    }
191    return 0;
192}
193
194/*
195 * The rcmd call itself.
196 * 	ahost (IN)	remote hostname
197 *	addr (IN)	4 byte internet address
198 *	locuser (IN)	local username
199 *	remuser (IN)	remote username
200 *	cmd (IN)	command to execute
201 *	rank (IN)	MPI rank for this process
202 *	fd2p (IN/OUT)	if non-NULL, open stderr backchannel on this fd
203 *	s (RETURN)	socket for stdout/sdin or -1 on failure
204 */
205static int
206xrcmd(char *ahost, char *addr, char *locuser, char *remuser,
207      char *cmd, int rank, int *fd2p, void **arg)
208{
209    struct sockaddr_in sin, from;
210    sigset_t oldset, blockme;
211    pid_t pid;
212    int s, lport, timo, rv;
213    char c;
214    struct xpollfd xpfds[2];
215
216    memset (xpfds, 0, sizeof (xpfds));
217
218    pid = getpid();
219
220    sigemptyset(&blockme);
221    sigaddset(&blockme, SIGURG);
222    pthread_sigmask(SIG_BLOCK, &blockme, &oldset);
223    for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
224        s = privsep_rresvport(&lport);
225        if (s < 0) {
226            if (errno == EAGAIN)
227                err("%p: %S: rcmd: socket: all ports in use\n", ahost);
228            else
229                err("%p: %S: rcmd: socket: %m\n", ahost);
230            pthread_sigmask(SIG_SETMASK, &oldset, NULL);
231            return (-1);
232        }
233        fcntl(s, F_SETOWN, pid);
234        memset (&sin, 0, sizeof (sin));
235        sin.sin_family = AF_INET;
236        memcpy(&sin.sin_addr, addr, IP_ADDR_LEN);
237        sin.sin_port = htons(RSH_PORT);
238        rv = connect(s, (struct sockaddr *) &sin, sizeof(sin));
239        if (rv >= 0)
240            break;
241        (void) close(s);
242        if (errno == EADDRINUSE) {
243            lport--;
244            continue;
245        }
246        if (errno == ECONNREFUSED && timo <= 16) {
247            (void) sleep(timo);
248            timo *= 2;
249            continue;
250        }
251        if (errno == EINTR)
252            err("%p: %S: connect: timed out\n", ahost);
253        else
254            err("%p: %S: connect: %m\n", ahost);
255        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
256        return (-1);
257    }
258    lport--;
259    if (fd2p == 0) {
260        write(s, "", 1);
261        lport = 0;
262    } else {
263        char num[8];
264        int s2 = privsep_rresvport(&lport), s3;
265        socklen_t len = sizeof(from);   /* arg to accept */
266
267        if (s2 < 0)
268            goto bad;
269        listen(s2, 1);
270        snprintf(num, sizeof(num), "%d", lport);
271        if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
272            err("%p: %S: rcmd: write (setting up stderr): %m\n", ahost);
273            (void) close(s2);
274            goto bad;
275        }
276        errno = 0;
277        xpfds[0].fd = s;
278        xpfds[1].fd = s2;
279        xpfds[0].events = xpfds[1].events = XPOLLREAD;
280        if (((rv = xpoll(xpfds, 2, -1)) < 0) || rv != 1 || (xpfds[0].revents > 0)) {
281          if (errno != 0)
282            err("%p: %S: rcmd: xpoll (setting up stderr): %m\n", ahost);
283          else
284            err("%p: %S: rcmd: xpoll: protocol failure in circuit setup\n", ahost);
285          (void) close(s2);
286          goto bad;
287        }
288        s3 = accept(s2, (struct sockaddr *) &from, &len);
289        (void) close(s2);
290        if (s3 < 0) {
291            err("%p: %S: rcmd: accept: %m\n", ahost);
292            lport = 0;
293            goto bad;
294        }
295        *fd2p = s3;
296        from.sin_port = ntohs((u_short) from.sin_port);
297        if (from.sin_family != AF_INET ||
298            from.sin_port >= IPPORT_RESERVED ||
299            from.sin_port < IPPORT_RESERVED / 2) {
300            err("%p: %S: socket: protocol failure in circuit setup\n",
301                ahost);
302            goto bad2;
303        }
304    }
305    (void) write(s, locuser, strlen(locuser) + 1);
306    (void) write(s, remuser, strlen(remuser) + 1);
307    (void) write(s, cmd, strlen(cmd) + 1);
308    rv = read(s, &c, 1);
309    if (rv < 0) {
310        if (errno == EINTR)
311            err("%p: %S: read: protocol failure: %s\n",
312                ahost, "timed out");
313        else
314            err("%p: %S: read: protocol failure: %m\n", ahost);
315        goto bad2;
316    } else if (rv != 1) {
317        err("%p: %S: read: protocol failure: %s\n",
318            ahost, "invalid response");
319        goto bad2;
320    }
321    if (c != 0) {
322        /* retrieve error string from remote server */
323        char tmpbuf[LINEBUFSIZE];
324        char *p = tmpbuf;
325
326        while (read(s, &c, 1) == 1) {
327            *p++ = c;
328            if (c == '\n')
329                break;
330        }
331        if (c != '\n')
332            *p++ = '\n';
333        *p++ = '\0';
334        err("%S: %s", ahost, tmpbuf);
335        goto bad2;
336    }
337    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
338    return (s);
339  bad2:
340    if (lport)
341        (void) close(*fd2p);
342  bad:
343    (void) close(s);
344    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
345    return (-1);
346}
347
348/*
349 * vi:tabstop=4 shiftwidth=4 expandtab
350 */