1 /* $NetBSD: refresh_clvmd.c,v 1.1.1.2 2009/12/02 00:27:06 haad Exp $ */
2
3 /*
4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6 *
7 * This file is part of LVM2.
8 *
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU General Public License v.2.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 /*
19 * Tell all clvmds in a cluster to refresh their toolcontext
20 */
21
22 #define _GNU_SOURCE
23 #define _FILE_OFFSET_BITS 64
24
25 #include <configure.h>
26 #include <stddef.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <libdevmapper.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <limits.h>
35
36 #include "clvm.h"
37 #include "refresh_clvmd.h"
38
39 typedef struct lvm_response {
40 char node[255];
41 char *response;
42 int status;
43 int len;
44 } lvm_response_t;
45
46 /*
47 * This gets stuck at the start of memory we allocate so we
48 * can sanity-check it at deallocation time
49 */
50 #define LVM_SIGNATURE 0x434C564D
51
52 static int _clvmd_sock = -1;
53
54 /* Open connection to the clvm daemon */
_open_local_sock(void)55 static int _open_local_sock(void)
56 {
57 int local_socket;
58 struct sockaddr_un sockaddr;
59
60 /* Open local socket */
61 if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
62 fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
63 return -1;
64 }
65
66 memset(&sockaddr, 0, sizeof(sockaddr));
67 memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
68
69 sockaddr.sun_family = AF_UNIX;
70
71 if (connect(local_socket,(struct sockaddr *) &sockaddr,
72 sizeof(sockaddr))) {
73 int saved_errno = errno;
74
75 fprintf(stderr, "connect() failed on local socket: %s\n",
76 strerror(errno));
77 if (close(local_socket))
78 return -1;
79
80 errno = saved_errno;
81 return -1;
82 }
83
84 return local_socket;
85 }
86
87 /* Send a request and return the status */
_send_request(const char * inbuf,int inlen,char ** retbuf)88 static int _send_request(const char *inbuf, int inlen, char **retbuf)
89 {
90 char outbuf[PIPE_BUF];
91 struct clvm_header *outheader = (struct clvm_header *) outbuf;
92 int len;
93 int off;
94 int buflen;
95 int err;
96
97 /* Send it to CLVMD */
98 rewrite:
99 if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
100 if (err == -1 && errno == EINTR)
101 goto rewrite;
102 fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
103 return 0;
104 }
105
106 /* Get the response */
107 reread:
108 if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
109 if (errno == EINTR)
110 goto reread;
111 fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
112 return 0;
113 }
114
115 if (len == 0) {
116 fprintf(stderr, "EOF reading CLVMD");
117 errno = ENOTCONN;
118 return 0;
119 }
120
121 /* Allocate buffer */
122 buflen = len + outheader->arglen;
123 *retbuf = dm_malloc(buflen);
124 if (!*retbuf) {
125 errno = ENOMEM;
126 return 0;
127 }
128
129 /* Copy the header */
130 memcpy(*retbuf, outbuf, len);
131 outheader = (struct clvm_header *) *retbuf;
132
133 /* Read the returned values */
134 off = 1; /* we've already read the first byte */
135 while (off <= outheader->arglen && len > 0) {
136 len = read(_clvmd_sock, outheader->args + off,
137 buflen - off - offsetof(struct clvm_header, args));
138 if (len > 0)
139 off += len;
140 }
141
142 /* Was it an error ? */
143 if (outheader->status != 0) {
144 errno = outheader->status;
145
146 /* Only return an error here if there are no node-specific
147 errors present in the message that might have more detail */
148 if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
149 fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
150 return 0;
151 }
152
153 }
154
155 return 1;
156 }
157
158 /* Build the structure header and parse-out wildcard node names */
_build_header(struct clvm_header * head,int cmd,const char * node,int len)159 static void _build_header(struct clvm_header *head, int cmd, const char *node,
160 int len)
161 {
162 head->cmd = cmd;
163 head->status = 0;
164 head->flags = 0;
165 head->clientid = 0;
166 head->arglen = len;
167
168 if (node) {
169 /*
170 * Allow a couple of special node names:
171 * "*" for all nodes,
172 * "." for the local node only
173 */
174 if (strcmp(node, "*") == 0) {
175 head->node[0] = '\0';
176 } else if (strcmp(node, ".") == 0) {
177 head->node[0] = '\0';
178 head->flags = CLVMD_FLAG_LOCAL;
179 } else
180 strcpy(head->node, node);
181 } else
182 head->node[0] = '\0';
183 }
184
185 /*
186 * Send a message to a(or all) node(s) in the cluster and wait for replies
187 */
_cluster_request(char cmd,const char * node,void * data,int len,lvm_response_t ** response,int * num)188 static int _cluster_request(char cmd, const char *node, void *data, int len,
189 lvm_response_t ** response, int *num)
190 {
191 char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
192 char *inptr;
193 char *retbuf = NULL;
194 int status;
195 int i;
196 int num_responses = 0;
197 struct clvm_header *head = (struct clvm_header *) outbuf;
198 lvm_response_t *rarray;
199
200 *num = 0;
201
202 if (_clvmd_sock == -1)
203 _clvmd_sock = _open_local_sock();
204
205 if (_clvmd_sock == -1)
206 return 0;
207
208 _build_header(head, cmd, node, len);
209 memcpy(head->node + strlen(head->node) + 1, data, len);
210
211 status = _send_request(outbuf, sizeof(struct clvm_header) +
212 strlen(head->node) + len, &retbuf);
213 if (!status)
214 goto out;
215
216 /* Count the number of responses we got */
217 head = (struct clvm_header *) retbuf;
218 inptr = head->args;
219 while (inptr[0]) {
220 num_responses++;
221 inptr += strlen(inptr) + 1;
222 inptr += sizeof(int);
223 inptr += strlen(inptr) + 1;
224 }
225
226 /*
227 * Allocate response array.
228 * With an extra pair of INTs on the front to sanity
229 * check the pointer when we are given it back to free
230 */
231 *response = dm_malloc(sizeof(lvm_response_t) * num_responses +
232 sizeof(int) * 2);
233 if (!*response) {
234 errno = ENOMEM;
235 status = 0;
236 goto out;
237 }
238
239 rarray = *response;
240
241 /* Unpack the response into an lvm_response_t array */
242 inptr = head->args;
243 i = 0;
244 while (inptr[0]) {
245 strcpy(rarray[i].node, inptr);
246 inptr += strlen(inptr) + 1;
247
248 memcpy(&rarray[i].status, inptr, sizeof(int));
249 inptr += sizeof(int);
250
251 rarray[i].response = dm_malloc(strlen(inptr) + 1);
252 if (rarray[i].response == NULL) {
253 /* Free up everything else and return error */
254 int j;
255 for (j = 0; j < i; j++)
256 dm_free(rarray[j].response);
257 free(*response);
258 errno = ENOMEM;
259 status = -1;
260 goto out;
261 }
262
263 strcpy(rarray[i].response, inptr);
264 rarray[i].len = strlen(inptr);
265 inptr += strlen(inptr) + 1;
266 i++;
267 }
268 *num = num_responses;
269 *response = rarray;
270
271 out:
272 if (retbuf)
273 dm_free(retbuf);
274
275 return status;
276 }
277
278 /* Free reply array */
_cluster_free_request(lvm_response_t * response,int num)279 static int _cluster_free_request(lvm_response_t * response, int num)
280 {
281 int i;
282
283 for (i = 0; i < num; i++) {
284 dm_free(response[i].response);
285 }
286
287 dm_free(response);
288
289 return 1;
290 }
291
refresh_clvmd()292 int refresh_clvmd()
293 {
294 int num_responses;
295 char args[1]; // No args really.
296 lvm_response_t *response;
297 int saved_errno;
298 int status;
299 int i;
300
301 status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &response, &num_responses);
302
303 /* If any nodes were down then display them and return an error */
304 for (i = 0; i < num_responses; i++) {
305 if (response[i].status == EHOSTDOWN) {
306 fprintf(stderr, "clvmd not running on node %s",
307 response[i].node);
308 status = 0;
309 errno = response[i].status;
310 } else if (response[i].status) {
311 fprintf(stderr, "Error resetting node %s: %s",
312 response[i].node,
313 response[i].response[0] ?
314 response[i].response :
315 strerror(response[i].status));
316 status = 0;
317 errno = response[i].status;
318 }
319 }
320
321 saved_errno = errno;
322 _cluster_free_request(response, num_responses);
323 errno = saved_errno;
324
325 return status;
326 }
327
debug_clvmd(int level,int clusterwide)328 int debug_clvmd(int level, int clusterwide)
329 {
330 int num_responses;
331 char args[1];
332 const char *nodes;
333 lvm_response_t *response;
334 int saved_errno;
335 int status;
336 int i;
337
338 args[0] = level;
339 if (clusterwide)
340 nodes = "*";
341 else
342 nodes = ".";
343
344 status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses);
345
346 /* If any nodes were down then display them and return an error */
347 for (i = 0; i < num_responses; i++) {
348 if (response[i].status == EHOSTDOWN) {
349 fprintf(stderr, "clvmd not running on node %s",
350 response[i].node);
351 status = 0;
352 errno = response[i].status;
353 } else if (response[i].status) {
354 fprintf(stderr, "Error setting debug on node %s: %s",
355 response[i].node,
356 response[i].response[0] ?
357 response[i].response :
358 strerror(response[i].status));
359 status = 0;
360 errno = response[i].status;
361 }
362 }
363
364 saved_errno = errno;
365 _cluster_free_request(response, num_responses);
366 errno = saved_errno;
367
368 return status;
369 }
370