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 } 370