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