]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pmdk/src/librpmem/rpmem_ssh.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2016-2020, Intel Corporation */
5 * rpmem_ssh.c -- rpmem ssh transport layer source file
14 #include <sys/types.h>
20 #include "rpmem_common.h"
21 #include "rpmem_ssh.h"
22 #include "rpmem_cmd.h"
23 #include "rpmem_util.h"
25 #define ERR_BUFF_LEN 4095
27 /* +1 in order to be sure it is always null-terminated */
28 static char error_str
[ERR_BUFF_LEN
+ 1];
31 struct rpmem_cmd
*cmd
;
35 * get_ssh -- return ssh command name
40 char *cmd
= os_getenv(RPMEM_SSH_ENV
);
48 * get_user_at_node -- returns string containing user@node
51 get_user_at_node(const struct rpmem_target_info
*info
)
53 char *user_at_node
= NULL
;
55 if (info
->flags
& RPMEM_HAS_USER
) {
56 size_t ulen
= strlen(info
->user
);
57 size_t nlen
= strlen(info
->node
);
58 size_t len
= ulen
+ 1 + nlen
+ 1;
59 user_at_node
= malloc(len
);
62 int ret
= util_snprintf(user_at_node
, len
, "%s@%s",
63 info
->user
, info
->node
);
67 user_at_node
= strdup(info
->node
);
80 * get_cmd -- return an RPMEM_CMD with appended list of arguments
83 get_cmd(const char **argv
)
85 const char *env_cmd
= rpmem_util_cmd_get();
86 char *cmd
= strdup(env_cmd
);
90 size_t cmd_len
= strlen(cmd
) + 1;
93 while ((arg
= *argv
++) != NULL
) {
94 size_t len
= strlen(arg
);
95 size_t new_cmd_len
= cmd_len
+ len
+ 1;
96 char *tmp
= realloc(cmd
, new_cmd_len
);
102 /* append the argument to the command */
103 cmd
[cmd_len
- 1] = ' ';
104 memcpy(&cmd
[cmd_len
], arg
, len
);
105 cmd
[cmd_len
+ len
] = '\0';
107 cmd_len
= new_cmd_len
;
117 * valist_to_argv -- convert va_list to argv array
120 valist_to_argv(va_list args
)
122 const char **argv
= malloc(sizeof(const char *));
130 while ((arg
= va_arg(args
, const char *)) != NULL
) {
132 const char **tmp
= realloc(argv
,
133 (nargs
+ 1) * sizeof(const char *));
138 argv
[nargs
- 1] = arg
;
149 * rpmem_ssh_execv -- open ssh connection and run $RPMEMD_CMD with
150 * additional NULL-terminated list of arguments.
153 rpmem_ssh_execv(const struct rpmem_target_info
*info
, const char **argv
)
155 struct rpmem_ssh
*rps
= calloc(1, sizeof(*rps
));
159 char *user_at_node
= get_user_at_node(info
);
163 rps
->cmd
= rpmem_cmd_init();
167 char *cmd
= get_cmd(argv
);
171 int ret
= rpmem_cmd_push(rps
->cmd
, get_ssh());
175 if (info
->flags
& RPMEM_HAS_SERVICE
) {
176 /* port number is optional */
177 ret
= rpmem_cmd_push(rps
->cmd
, "-p");
180 ret
= rpmem_cmd_push(rps
->cmd
, info
->service
);
186 * Disable allocating pseudo-terminal in order to transfer binary
189 ret
= rpmem_cmd_push(rps
->cmd
, "-T");
193 if (info
->flags
& RPMEM_FLAGS_USE_IPV4
) {
194 ret
= rpmem_cmd_push(rps
->cmd
, "-4");
199 /* fail if password required for authentication */
200 ret
= rpmem_cmd_push(rps
->cmd
, "-oBatchMode=yes");
204 ret
= rpmem_cmd_push(rps
->cmd
, user_at_node
);
208 ret
= rpmem_cmd_push(rps
->cmd
, cmd
);
212 ret
= rpmem_cmd_run(rps
->cmd
);
224 rpmem_cmd_fini(rps
->cmd
);
234 * rpmem_ssh_exec -- open ssh connection and run $RPMEMD_CMD with
235 * additional NULL-terminated list of arguments.
238 rpmem_ssh_exec(const struct rpmem_target_info
*info
, ...)
240 struct rpmem_ssh
*ssh
;
243 va_start(args
, info
);
245 const char **argv
= valist_to_argv(args
);
247 ssh
= rpmem_ssh_execv(info
, argv
);
259 * rpmem_ssh_open -- open ssh connection with specified node and wait for status
262 rpmem_ssh_open(const struct rpmem_target_info
*info
)
264 struct rpmem_ssh
*ssh
= rpmem_ssh_exec(info
, NULL
);
269 * Read initial status from invoked command.
270 * This is for synchronization purposes and to make it possible
271 * to inform client that command's initialization failed.
274 int ret
= rpmem_ssh_recv(ssh
, &status
, sizeof(status
));
276 if (ret
== 1 || errno
== ECONNRESET
)
277 ERR("%s", rpmem_ssh_strerror(ssh
, errno
));
279 ERR("!%s", info
->node
);
280 goto err_recv_status
;
284 ERR("%s: unexpected status received -- '%d'",
290 RPMEM_LOG(INFO
, "received status: %u", status
);
295 rpmem_ssh_close(ssh
);
300 * rpmem_ssh_close -- close ssh connection
303 rpmem_ssh_close(struct rpmem_ssh
*rps
)
307 rpmem_cmd_term(rps
->cmd
);
308 rv
= rpmem_cmd_wait(rps
->cmd
, &ret
);
312 rpmem_cmd_fini(rps
->cmd
);
316 return WEXITSTATUS(ret
);
318 if (WIFSIGNALED(ret
)) {
319 ERR("signal received -- %d", WTERMSIG(ret
));
323 ERR("exit status -- %d", WEXITSTATUS(ret
));
329 * rpmem_ssh_send -- send data using ssh transport layer
331 * The data is encoded using base64.
334 rpmem_ssh_send(struct rpmem_ssh
*rps
, const void *buff
, size_t len
)
336 int ret
= rpmem_xwrite(rps
->cmd
->fd_in
, buff
, len
, MSG_NOSIGNAL
);
339 } else if (ret
< 0) {
348 * rpmem_ssh_recv -- receive data using ssh transport layer
350 * The received data is decoded using base64.
353 rpmem_ssh_recv(struct rpmem_ssh
*rps
, void *buff
, size_t len
)
355 int ret
= rpmem_xread(rps
->cmd
->fd_out
, buff
,
359 } else if (ret
< 0) {
368 * rpmem_ssh_monitor -- check connection state of ssh
376 rpmem_ssh_monitor(struct rpmem_ssh
*rps
, int nonblock
)
379 int flags
= MSG_PEEK
;
381 flags
|= MSG_DONTWAIT
;
383 int ret
= rpmem_xread(rps
->cmd
->fd_out
, &buff
, sizeof(buff
), flags
);
391 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
401 * rpmem_ssh_strerror -- read error using stderr channel
404 rpmem_ssh_strerror(struct rpmem_ssh
*rps
, int oerrno
)
408 while ((ret
= read(rps
->cmd
->fd_err
, error_str
+ len
,
409 ERR_BUFF_LEN
- len
))) {
411 return "reading error string failed";
415 error_str
[len
] = '\0';
420 char buff
[UTIL_MAX_ERR_MSG
];
421 util_strerror(oerrno
, buff
, UTIL_MAX_ERR_MSG
);
422 ret
= util_snprintf(error_str
, ERR_BUFF_LEN
,
425 ret
= util_snprintf(error_str
, ERR_BUFF_LEN
,
431 /* get rid of new line and carriage return chars */
432 char *cr
= strchr(error_str
, '\r');
436 char *nl
= strchr(error_str
, '\n');