xref: /dragonfly/contrib/lvm2/dist/daemons/clvmd/refresh_clvmd.c (revision e1c190724ab50463680fb1098d889713e47c79ae)
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