]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/commands_utils.c
Fix typo
[mirror_lxc.git] / src / lxc / commands_utils.c
CommitLineData
92e35018
CB
1/* liblxcapi
2 *
3 * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2017 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#define _GNU_SOURCE
bbf5cf35 21#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
92e35018 22#include <errno.h>
bbf5cf35 23#include <inttypes.h>
92e35018 24#include <stdio.h>
bbf5cf35 25#include <stdlib.h>
92e35018
CB
26#include <string.h>
27#include <unistd.h>
28#include <sys/socket.h>
29#include <sys/un.h>
30
c01c2be6 31#include "af_unix.h"
92e35018
CB
32#include "commands.h"
33#include "commands_utils.h"
c01c2be6 34#include "initutils.h"
92e35018 35#include "log.h"
f3a2945e 36#include "lxclock.h"
92e35018
CB
37#include "monitor.h"
38#include "state.h"
bbf5cf35 39#include "utils.h"
92e35018 40
ac2cecc4 41lxc_log_define(commands_utils, lxc);
92e35018
CB
42
43int lxc_cmd_sock_rcv_state(int state_client_fd, int timeout)
44{
45 int ret;
46 struct lxc_msg msg;
47 struct timeval out;
48
ee8377bd
CB
49 if (timeout >= 0) {
50 memset(&out, 0, sizeof(out));
51 out.tv_sec = timeout;
52 ret = setsockopt(state_client_fd, SOL_SOCKET, SO_RCVTIMEO,
53 (const void *)&out, sizeof(out));
54 if (ret < 0) {
e01516d7 55 SYSERROR("Failed to set %ds timeout on container "
ee8377bd
CB
56 "state socket",
57 timeout);
58 return -1;
59 }
92e35018
CB
60 }
61
62 memset(&msg, 0, sizeof(msg));
63
64again:
65 ret = recv(state_client_fd, &msg, sizeof(msg), 0);
66 if (ret < 0) {
ee8377bd
CB
67 if (errno == EINTR) {
68 TRACE("Caught EINTR; retrying");
92e35018 69 goto again;
ee8377bd 70 }
92e35018 71
6d1400b5 72 SYSERROR("Failed to receive message");
92e35018
CB
73 return -1;
74 }
75
9dfa4041 76 TRACE("Received state %s from state client %d",
92e35018
CB
77 lxc_state2str(msg.value), state_client_fd);
78
79 return msg.value;
80}
81
82/* Register a new state client and retrieve state from command socket. */
83int lxc_cmd_sock_get_state(const char *name, const char *lxcpath,
84 lxc_state_t states[MAX_STATE], int timeout)
85{
86 int ret;
87 int state_client_fd;
88
89 ret = lxc_cmd_add_state_client(name, lxcpath, states, &state_client_fd);
90 if (ret < 0)
91 return -1;
92
93 if (ret < MAX_STATE)
94 return ret;
95
96 ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout);
97 close(state_client_fd);
98 return ret;
99}
bbf5cf35
CB
100
101int lxc_make_abstract_socket_name(char *path, int len, const char *lxcname,
102 const char *lxcpath,
103 const char *hashed_sock_name,
104 const char *suffix)
105{
106 const char *name;
107 char *tmppath;
108 size_t tmplen;
109 uint64_t hash;
110 int ret;
111
112 name = lxcname;
113 if (!name)
114 name = "";
115
116 if (hashed_sock_name != NULL) {
117 ret =
118 snprintf(path, len, "lxc/%s/%s", hashed_sock_name, suffix);
119 if (ret < 0 || ret >= len) {
120 ERROR("Failed to create abstract socket name");
121 return -1;
122 }
123 return 0;
124 }
125
126 if (!lxcpath) {
127 lxcpath = lxc_global_config_value("lxc.lxcpath");
128 if (!lxcpath) {
129 ERROR("Failed to allocate memory");
130 return -1;
131 }
132 }
133
134 ret = snprintf(path, len, "%s/%s/%s", lxcpath, name, suffix);
135 if (ret < 0) {
136 ERROR("Failed to create abstract socket name");
137 return -1;
138 }
139 if (ret < len)
140 return 0;
141
142 /* ret >= len; lxcpath or name is too long. hash both */
143 tmplen = strlen(name) + strlen(lxcpath) + 2;
144 tmppath = alloca(tmplen);
145 ret = snprintf(tmppath, tmplen, "%s/%s", lxcpath, name);
146 if (ret < 0 || (size_t)ret >= tmplen) {
147 ERROR("Failed to create abstract socket name");
148 return -1;
149 }
150
151 hash = fnv_64a_buf(tmppath, ret, FNV1A_64_INIT);
152 ret = snprintf(path, len, "lxc/%016" PRIx64 "/%s", hash, suffix);
153 if (ret < 0 || ret >= len) {
154 ERROR("Failed to create abstract socket name");
155 return -1;
156 }
157
158 return 0;
159}
c01c2be6
CB
160
161int lxc_cmd_connect(const char *name, const char *lxcpath,
9dfa4041 162 const char *hashed_sock_name, const char *suffix)
c01c2be6
CB
163{
164 int ret, client_fd;
165 char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = {0};
166 char *offset = &path[1];
c01c2be6
CB
167
168 /* -2 here because this is an abstract unix socket so it needs a
169 * leading \0, and we null terminate, so it needs a trailing \0.
170 * Although null termination isn't required by the API, we do it anyway
171 * because we print the sockname out sometimes.
172 */
2945ea97 173 size_t len = sizeof(path) - 2;
c01c2be6 174 ret = lxc_make_abstract_socket_name(offset, len, name, lxcpath,
9dfa4041 175 hashed_sock_name, suffix);
c01c2be6
CB
176 if (ret < 0)
177 return -1;
178
179 /* Get new client fd. */
180 client_fd = lxc_abstract_unix_connect(path);
181 if (client_fd < 0) {
182 if (errno == ECONNREFUSED)
183 return -ECONNREFUSED;
184 return -1;
185 }
186
187 return client_fd;
188}
189
190int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler,
191 lxc_state_t states[MAX_STATE])
192{
bc631984 193 int state;
d39b10eb 194 struct lxc_state_client *newclient;
c01c2be6
CB
195 struct lxc_list *tmplist;
196
197 newclient = malloc(sizeof(*newclient));
198 if (!newclient)
199 return -ENOMEM;
200
201 /* copy requested states */
202 memcpy(newclient->states, states, sizeof(newclient->states));
203 newclient->clientfd = state_client_fd;
204
205 tmplist = malloc(sizeof(*tmplist));
206 if (!tmplist) {
207 free(newclient);
208 return -ENOMEM;
209 }
210
bc631984
CB
211 state = handler->state;
212 if (states[state] != 1) {
213 lxc_list_add_elem(tmplist, newclient);
214 lxc_list_add_tail(&handler->conf->state_clients, tmplist);
bc631984 215 } else {
bc631984 216 free(newclient);
44552fb2 217 free(tmplist);
bc631984
CB
218 return state;
219 }
c01c2be6
CB
220
221 TRACE("added state client %d to state client list", state_client_fd);
bc631984 222 return MAX_STATE;
c01c2be6 223}