]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/commands_utils.c
tree-wide: fix includes to fix bionic builds
[mirror_lxc.git] / src / lxc / commands_utils.c
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 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE 1
22 #endif
23 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
24 #include <errno.h>
25 #include <inttypes.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <unistd.h>
32
33 #include "af_unix.h"
34 #include "commands.h"
35 #include "commands_utils.h"
36 #include "config.h"
37 #include "file_utils.h"
38 #include "initutils.h"
39 #include "log.h"
40 #include "lxclock.h"
41 #include "monitor.h"
42 #include "state.h"
43 #include "utils.h"
44
45 lxc_log_define(commands_utils, lxc);
46
47 int lxc_cmd_sock_rcv_state(int state_client_fd, int timeout)
48 {
49 int ret;
50 struct lxc_msg msg;
51 struct timeval out;
52
53 if (timeout >= 0) {
54 memset(&out, 0, sizeof(out));
55 out.tv_sec = timeout;
56 ret = setsockopt(state_client_fd, SOL_SOCKET, SO_RCVTIMEO,
57 (const void *)&out, sizeof(out));
58 if (ret < 0) {
59 SYSERROR("Failed to set %ds timeout on container "
60 "state socket",
61 timeout);
62 return -1;
63 }
64 }
65
66 memset(&msg, 0, sizeof(msg));
67
68 ret = lxc_recv_nointr(state_client_fd, &msg, sizeof(msg), 0);
69 if (ret < 0) {
70 SYSERROR("Failed to receive message");
71 return -1;
72 }
73
74 TRACE("Received state %s from state client %d",
75 lxc_state2str(msg.value), state_client_fd);
76
77 return msg.value;
78 }
79
80 /* Register a new state client and retrieve state from command socket. */
81 int lxc_cmd_sock_get_state(const char *name, const char *lxcpath,
82 lxc_state_t states[MAX_STATE], int timeout)
83 {
84 int ret;
85 int state_client_fd;
86
87 ret = lxc_cmd_add_state_client(name, lxcpath, states, &state_client_fd);
88 if (ret < 0)
89 return -1;
90
91 if (ret < MAX_STATE)
92 return ret;
93
94 ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout);
95 close(state_client_fd);
96 return ret;
97 }
98
99 int lxc_make_abstract_socket_name(char *path, int len, const char *lxcname,
100 const char *lxcpath,
101 const char *hashed_sock_name,
102 const char *suffix)
103 {
104 const char *name;
105 char *tmppath;
106 size_t tmplen;
107 uint64_t hash;
108 int ret;
109
110 name = lxcname;
111 if (!name)
112 name = "";
113
114 if (hashed_sock_name != NULL) {
115 ret =
116 snprintf(path, len, "lxc/%s/%s", hashed_sock_name, suffix);
117 if (ret < 0 || ret >= len) {
118 ERROR("Failed to create abstract socket name");
119 return -1;
120 }
121 return 0;
122 }
123
124 if (!lxcpath) {
125 lxcpath = lxc_global_config_value("lxc.lxcpath");
126 if (!lxcpath) {
127 ERROR("Failed to allocate memory");
128 return -1;
129 }
130 }
131
132 ret = snprintf(path, len, "%s/%s/%s", lxcpath, name, suffix);
133 if (ret < 0) {
134 ERROR("Failed to create abstract socket name");
135 return -1;
136 }
137 if (ret < len)
138 return 0;
139
140 /* ret >= len; lxcpath or name is too long. hash both */
141 tmplen = strlen(name) + strlen(lxcpath) + 2;
142 tmppath = alloca(tmplen);
143 ret = snprintf(tmppath, tmplen, "%s/%s", lxcpath, name);
144 if (ret < 0 || (size_t)ret >= tmplen) {
145 ERROR("Failed to create abstract socket name");
146 return -1;
147 }
148
149 hash = fnv_64a_buf(tmppath, ret, FNV1A_64_INIT);
150 ret = snprintf(path, len, "lxc/%016" PRIx64 "/%s", hash, suffix);
151 if (ret < 0 || ret >= len) {
152 ERROR("Failed to create abstract socket name");
153 return -1;
154 }
155
156 return 0;
157 }
158
159 int lxc_cmd_connect(const char *name, const char *lxcpath,
160 const char *hashed_sock_name, const char *suffix)
161 {
162 int ret, client_fd;
163 char path[LXC_AUDS_ADDR_LEN] = {0};
164 char *offset = &path[1];
165
166 /* -2 here because this is an abstract unix socket so it needs a
167 * leading \0, and we null terminate, so it needs a trailing \0.
168 * Although null termination isn't required by the API, we do it anyway
169 * because we print the sockname out sometimes.
170 */
171 size_t len = sizeof(path) - 2;
172 ret = lxc_make_abstract_socket_name(offset, len, name, lxcpath,
173 hashed_sock_name, suffix);
174 if (ret < 0)
175 return -1;
176
177 /* Get new client fd. */
178 client_fd = lxc_abstract_unix_connect(path);
179 if (client_fd < 0)
180 return -1;
181
182 return client_fd;
183 }
184
185 int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler,
186 lxc_state_t states[MAX_STATE])
187 {
188 int state;
189 struct lxc_state_client *newclient;
190 struct lxc_list *tmplist;
191
192 newclient = malloc(sizeof(*newclient));
193 if (!newclient)
194 return -ENOMEM;
195
196 /* copy requested states */
197 memcpy(newclient->states, states, sizeof(newclient->states));
198 newclient->clientfd = state_client_fd;
199
200 tmplist = malloc(sizeof(*tmplist));
201 if (!tmplist) {
202 free(newclient);
203 return -ENOMEM;
204 }
205
206 state = handler->state;
207 if (states[state] != 1) {
208 lxc_list_add_elem(tmplist, newclient);
209 lxc_list_add_tail(&handler->conf->state_clients, tmplist);
210 } else {
211 free(newclient);
212 free(tmplist);
213 return state;
214 }
215
216 TRACE("added state client %d to state client list", state_client_fd);
217 return MAX_STATE;
218 }