Home | History | Annotate | Line # | Download | only in clvmd
      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