]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/commands_utils.c
tree-wide: s/strncpy()/strlcpy()/g
[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
CB
40
41lxc_log_define(lxc_commands_utils, lxc);
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) {
55 SYSERROR("Failed to set %ds timeout on containter "
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
9dfa4041 72 ERROR("Failed to receive message: %s", strerror(errno));
92e35018
CB
73 return -1;
74 }
75
9dfa4041 76 if (ret < 0)
92e35018 77 return -1;
92e35018 78
9dfa4041 79 TRACE("Received state %s from state client %d",
92e35018
CB
80 lxc_state2str(msg.value), state_client_fd);
81
82 return msg.value;
83}
84
85/* Register a new state client and retrieve state from command socket. */
86int lxc_cmd_sock_get_state(const char *name, const char *lxcpath,
87 lxc_state_t states[MAX_STATE], int timeout)
88{
89 int ret;
90 int state_client_fd;
91
92 ret = lxc_cmd_add_state_client(name, lxcpath, states, &state_client_fd);
93 if (ret < 0)
94 return -1;
95
96 if (ret < MAX_STATE)
97 return ret;
98
99 ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout);
100 close(state_client_fd);
101 return ret;
102}
bbf5cf35
CB
103
104int lxc_make_abstract_socket_name(char *path, int len, const char *lxcname,
105 const char *lxcpath,
106 const char *hashed_sock_name,
107 const char *suffix)
108{
109 const char *name;
110 char *tmppath;
111 size_t tmplen;
112 uint64_t hash;
113 int ret;
114
115 name = lxcname;
116 if (!name)
117 name = "";
118
119 if (hashed_sock_name != NULL) {
120 ret =
121 snprintf(path, len, "lxc/%s/%s", hashed_sock_name, suffix);
122 if (ret < 0 || ret >= len) {
123 ERROR("Failed to create abstract socket name");
124 return -1;
125 }
126 return 0;
127 }
128
129 if (!lxcpath) {
130 lxcpath = lxc_global_config_value("lxc.lxcpath");
131 if (!lxcpath) {
132 ERROR("Failed to allocate memory");
133 return -1;
134 }
135 }
136
137 ret = snprintf(path, len, "%s/%s/%s", lxcpath, name, suffix);
138 if (ret < 0) {
139 ERROR("Failed to create abstract socket name");
140 return -1;
141 }
142 if (ret < len)
143 return 0;
144
145 /* ret >= len; lxcpath or name is too long. hash both */
146 tmplen = strlen(name) + strlen(lxcpath) + 2;
147 tmppath = alloca(tmplen);
148 ret = snprintf(tmppath, tmplen, "%s/%s", lxcpath, name);
149 if (ret < 0 || (size_t)ret >= tmplen) {
150 ERROR("Failed to create abstract socket name");
151 return -1;
152 }
153
154 hash = fnv_64a_buf(tmppath, ret, FNV1A_64_INIT);
155 ret = snprintf(path, len, "lxc/%016" PRIx64 "/%s", hash, suffix);
156 if (ret < 0 || ret >= len) {
157 ERROR("Failed to create abstract socket name");
158 return -1;
159 }
160
161 return 0;
162}
c01c2be6
CB
163
164int lxc_cmd_connect(const char *name, const char *lxcpath,
9dfa4041 165 const char *hashed_sock_name, const char *suffix)
c01c2be6
CB
166{
167 int ret, client_fd;
168 char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = {0};
169 char *offset = &path[1];
c01c2be6
CB
170
171 /* -2 here because this is an abstract unix socket so it needs a
172 * leading \0, and we null terminate, so it needs a trailing \0.
173 * Although null termination isn't required by the API, we do it anyway
174 * because we print the sockname out sometimes.
175 */
2945ea97 176 size_t len = sizeof(path) - 2;
c01c2be6 177 ret = lxc_make_abstract_socket_name(offset, len, name, lxcpath,
9dfa4041 178 hashed_sock_name, suffix);
c01c2be6
CB
179 if (ret < 0)
180 return -1;
181
182 /* Get new client fd. */
183 client_fd = lxc_abstract_unix_connect(path);
184 if (client_fd < 0) {
185 if (errno == ECONNREFUSED)
186 return -ECONNREFUSED;
187 return -1;
188 }
189
190 return client_fd;
191}
192
193int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler,
194 lxc_state_t states[MAX_STATE])
195{
bc631984 196 int state;
d39b10eb 197 struct lxc_state_client *newclient;
c01c2be6
CB
198 struct lxc_list *tmplist;
199
200 newclient = malloc(sizeof(*newclient));
201 if (!newclient)
202 return -ENOMEM;
203
204 /* copy requested states */
205 memcpy(newclient->states, states, sizeof(newclient->states));
206 newclient->clientfd = state_client_fd;
207
208 tmplist = malloc(sizeof(*tmplist));
209 if (!tmplist) {
210 free(newclient);
211 return -ENOMEM;
212 }
213
bc631984
CB
214 state = handler->state;
215 if (states[state] != 1) {
216 lxc_list_add_elem(tmplist, newclient);
217 lxc_list_add_tail(&handler->conf->state_clients, tmplist);
bc631984 218 } else {
bc631984 219 free(newclient);
44552fb2 220 free(tmplist);
bc631984
CB
221 return state;
222 }
c01c2be6
CB
223
224 TRACE("added state client %d to state client list", state_client_fd);
bc631984 225 return MAX_STATE;
c01c2be6 226}