]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pmdk/src/librpmem/rpmem_cmd.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2016-2020, Intel Corporation */
5 * rpmem_cmd.c -- simple interface for running an executable in child process
13 #include <sys/types.h>
14 #include <sys/socket.h>
22 #include "rpmem_common.h"
23 #include "rpmem_util.h"
24 #include "rpmem_cmd.h"
27 * rpmem_cmd_init -- initialize command
32 struct rpmem_cmd
*cmd
= calloc(1, sizeof(*cmd
));
34 RPMEM_LOG(ERR
, "allocating command buffer");
44 * rpmem_cmd_fini -- deinitialize command
47 rpmem_cmd_fini(struct rpmem_cmd
*cmd
)
49 for (int i
= 0; i
< cmd
->args
.argc
; i
++)
50 free(cmd
->args
.argv
[i
]);
56 * rpmem_cmd_push -- push back command's argument
59 rpmem_cmd_push(struct rpmem_cmd
*cmd
, const char *arg
)
61 size_t argv_count
= (size_t)cmd
->args
.argc
+ 2;
62 char **argv
= realloc(cmd
->args
.argv
, argv_count
* sizeof(char *));
64 RPMEM_LOG(ERR
, "reallocating command argv");
68 cmd
->args
.argv
= argv
;
70 char *arg_dup
= strdup(arg
);
72 RPMEM_LOG(ERR
, "allocating argument");
76 cmd
->args
.argv
[cmd
->args
.argc
] = arg_dup
;
78 cmd
->args
.argv
[cmd
->args
.argc
] = NULL
;
87 * rpmem_cmd_log -- print executing command
90 rpmem_cmd_log(struct rpmem_cmd
*cmd
)
92 RPMEM_ASSERT(cmd
->args
.argc
> 0);
95 for (int i
= 0; i
< cmd
->args
.argc
; i
++) {
96 size
+= strlen(cmd
->args
.argv
[i
]) + 1;
99 char *buff
= malloc(size
);
101 RPMEM_LOG(ERR
, "allocating log buffer for command");
107 for (int i
= 0; pos
< size
&& i
< cmd
->args
.argc
; i
++) {
108 int ret
= util_snprintf(&buff
[pos
], size
- pos
, "%s%s",
109 cmd
->args
.argv
[i
], i
== cmd
->args
.argc
- 1 ?
112 RPMEM_LOG(ERR
, "!snprintf");
119 RPMEM_LOG(INFO
, "executing command '%s'", buff
);
126 * rpmem_cmd_run -- run command and connect with stdin, stdout and stderr
127 * using unix sockets.
129 * The communication with child process is done via socketpairs on
130 * stdin, stdout and stderr. The socketpairs are used instead of pipes
131 * because reading from disconnected pipe causes a SIGPIPE signal.
132 * When using socketpair it is possible to read data using recv(3)
133 * function with MSG_NOSIGNAL flag, which doesn't send a signal.
136 rpmem_cmd_run(struct rpmem_cmd
*cmd
)
144 /* socketpair for stdin */
145 int ret
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fd_in
);
147 RPMEM_LOG(ERR
, "creating pipe for stdin");
151 /* parent process stdin socket */
152 cmd
->fd_in
= fd_in
[1];
154 /* socketpair for stdout */
155 ret
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fd_out
);
157 RPMEM_LOG(ERR
, "creating pipe for stdout");
161 /* parent process stdout socket */
162 cmd
->fd_out
= fd_out
[0];
164 /* socketpair for stderr */
165 ret
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fd_err
);
167 RPMEM_LOG(ERR
, "creating pipe for stderr");
171 /* socketpair for stderr */
172 cmd
->fd_err
= fd_err
[0];
176 if (cmd
->pid
== -1) {
177 RPMEM_LOG(ERR
, "forking command");
186 execvp(cmd
->args
.argv
[0], cmd
->args
.argv
);
209 * rpmem_cmd_wait -- wait for process to change state
212 rpmem_cmd_wait(struct rpmem_cmd
*cmd
, int *status
)
215 RPMEM_LOG(ERR
, "wrong PID: %i", cmd
->pid
);
220 if (waitpid(cmd
->pid
, status
, 0) != cmd
->pid
) {
221 RPMEM_LOG(ERR
, "!waitpid failed");
229 * rpmem_cmd_term -- close child process's unix sockets
232 rpmem_cmd_term(struct rpmem_cmd
*cmd
)
234 os_close(cmd
->fd_in
);
235 os_close(cmd
->fd_out
);
236 os_close(cmd
->fd_err
);
238 RPMEM_ASSERT(cmd
->pid
> 0);