Merge branch 'vendor/OPENPAM'
[dragonfly.git] / contrib / lvm2 / dist / daemons / clvmd / refresh_clvmd.c
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 */
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 */
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 */
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  */
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[i].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 */
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
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
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 }