geom_ctl.c revision 272461
161981Sbrian/*-
261981Sbrian * Copyright (c) 2003 Poul-Henning Kamp
361981Sbrian * All rights reserved.
461981Sbrian *
561981Sbrian * Redistribution and use in source and binary forms, with or without
661981Sbrian * modification, are permitted provided that the following conditions
761981Sbrian * are met:
861981Sbrian * 1. Redistributions of source code must retain the above copyright
961981Sbrian *    notice, this list of conditions and the following disclaimer.
1061981Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1161981Sbrian *    notice, this list of conditions and the following disclaimer in the
1261981Sbrian *    documentation and/or other materials provided with the distribution.
1361981Sbrian * 3. The names of the authors may not be used to endorse or promote
1461981Sbrian *    products derived from this software without specific prior written
1561981Sbrian *    permission.
1661981Sbrian *
1761981Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1861981Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1961981Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2061981Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2161981Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2261981Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2361981Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2461981Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2565843Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2665843Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2765843Sbrian * SUCH DAMAGE.
2865843Sbrian *
2965843Sbrian * $FreeBSD: releng/10.1/lib/libgeom/geom_ctl.c 214129 2010-10-21 10:38:14Z pjd $
3065843Sbrian */
3165843Sbrian
3265843Sbrian#include <stdio.h>
3365843Sbrian#include <fcntl.h>
3465843Sbrian#include <errno.h>
3561981Sbrian#include <stdint.h>
3661981Sbrian#include <sys/types.h>
3761981Sbrian#include <stdarg.h>
3861981Sbrian#include <unistd.h>
3961981Sbrian#include <string.h>
4061981Sbrian#include <stdlib.h>
4161981Sbrian#include <paths.h>
4261981Sbrian
4361981Sbrian#include <sys/queue.h>
4461981Sbrian
4561981Sbrian#define GCTL_TABLE 1
4661981Sbrian#include <libgeom.h>
4761981Sbrian
4861981Sbrian/*
4961981Sbrian * Global pointer to a string that is used to avoid an errorneous free in
5061981Sbrian * gctl_free.
5161981Sbrian */
5261981Sbrianstatic char nomemmsg[] = "Could not allocate memory";
5361981Sbrian
5461981Sbrianvoid
5561981Sbriangctl_dump(struct gctl_req *req, FILE *f)
5661981Sbrian{
5761981Sbrian	unsigned int i;
5861981Sbrian	int j;
5961981Sbrian	struct gctl_req_arg *ap;
6061981Sbrian
6161981Sbrian	if (req == NULL) {
6261981Sbrian		fprintf(f, "Dump of gctl request at NULL\n");
6361981Sbrian		return;
6461981Sbrian	}
6561981Sbrian	fprintf(f, "Dump of gctl request at %p:\n", req);
6661981Sbrian	if (req->error != NULL)
6761981Sbrian		fprintf(f, "  error:\t\"%s\"\n", req->error);
6861981Sbrian	else
6961981Sbrian		fprintf(f, "  error:\tNULL\n");
7061981Sbrian	for (i = 0; i < req->narg; i++) {
7161981Sbrian		ap = &req->arg[i];
7261981Sbrian		fprintf(f, "  param:\t\"%s\" (%d)", ap->name, ap->nlen);
7361981Sbrian		fprintf(f, " [%s%s",
7474314Sbrian		    ap->flag & GCTL_PARAM_RD ? "R" : "",
7561981Sbrian		    ap->flag & GCTL_PARAM_WR ? "W" : "");
7661981Sbrian		fflush(f);
7761981Sbrian		if (ap->flag & GCTL_PARAM_ASCII)
7861981Sbrian			fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value);
7961981Sbrian		else if (ap->len > 0) {
8061981Sbrian			fprintf(f, "%d] = ", ap->len);
8162054Sbrian			fflush(f);
8277496Sbrian			for (j = 0; j < ap->len; j++) {
8377492Sbrian				fprintf(f, " %02x", ((u_char *)ap->value)[j]);
8461981Sbrian			}
8561981Sbrian		} else {
8661981Sbrian			fprintf(f, "0] = %p", ap->value);
8761981Sbrian		}
8861981Sbrian		fprintf(f, "\n");
8961981Sbrian	}
9061981Sbrian}
9161981Sbrian
9261981Sbrian/*
9362644Ssheldonh * Set an error message, if one does not already exist.
9461981Sbrian */
9561981Sbrianstatic void
9661981Sbriangctl_set_error(struct gctl_req *req, const char *error, ...)
9761981Sbrian{
9861981Sbrian	va_list ap;
9961981Sbrian
10061981Sbrian	if (req->error != NULL)
10161981Sbrian		return;
10261981Sbrian	va_start(ap, error);
10361981Sbrian	vasprintf(&req->error, error, ap);
10461981Sbrian	va_end(ap);
10594342Sgshapiro}
10661981Sbrian
10761981Sbrian/*
10861981Sbrian * Check that a malloc operation succeeded, and set a consistent error
10987514Scjc * message if not.
11061981Sbrian */
11161981Sbrianstatic void
11261981Sbriangctl_check_alloc(struct gctl_req *req, void *ptr)
11362274Sbrian{
11461981Sbrian
11575809Sdirk	if (ptr != NULL)
11675809Sdirk		return;
11775809Sdirk	gctl_set_error(req, nomemmsg);
11875809Sdirk	if (req->error == NULL)
11972677Speter		req->error = nomemmsg;
12072677Speter}
12194342Sgshapiro
12272677Speter/*
12361981Sbrian * Allocate a new request handle of the specified type.
12461981Sbrian * XXX: Why bother checking the type ?
12561981Sbrian */
12661981Sbrianstruct gctl_req *
12787514Scjcgctl_get_handle(void)
12887514Scjc{
12987514Scjc
13087514Scjc	return (calloc(1, sizeof(struct gctl_req)));
13187514Scjc}
13287514Scjc
13387514Scjc/*
13487514Scjc * Allocate space for another argument.
13587514Scjc */
13687514Scjcstatic struct gctl_req_arg *
13787514Scjcgctl_new_arg(struct gctl_req *req)
13887514Scjc{
13987514Scjc	struct gctl_req_arg *ap;
14087514Scjc
14187514Scjc	req->narg++;
14287514Scjc	req->arg = reallocf(req->arg, sizeof *ap * req->narg);
14387514Scjc	gctl_check_alloc(req, req->arg);
14487514Scjc	if (req->arg == NULL) {
14587514Scjc		req->narg = 0;
14687514Scjc		return (NULL);
14787514Scjc	}
14887514Scjc	ap = req->arg + (req->narg - 1);
14987514Scjc	memset(ap, 0, sizeof *ap);
15087514Scjc	return (ap);
15187514Scjc}
15287514Scjc
15387514Scjcstatic void
15487514Scjcgctl_param_add(struct gctl_req *req, const char *name, int len, void *value,
15587514Scjc    int flag)
15687514Scjc{
15787514Scjc	struct gctl_req_arg *ap;
15887514Scjc
15987514Scjc	if (req == NULL || req->error != NULL)
16087514Scjc		return;
16187514Scjc	ap = gctl_new_arg(req);
16287514Scjc	if (ap == NULL)
16387514Scjc		return;
16487514Scjc	ap->name = strdup(name);
16587514Scjc	gctl_check_alloc(req, ap->name);
16687514Scjc	if (ap->name == NULL)
16787514Scjc		return;
16887514Scjc	ap->nlen = strlen(ap->name) + 1;
16987514Scjc	ap->value = value;
17087514Scjc	ap->flag = flag;
17187514Scjc	if (len >= 0)
17261981Sbrian		ap->len = len;
17361981Sbrian	else if (len < 0) {
17465843Sbrian		ap->flag |= GCTL_PARAM_ASCII;
17565843Sbrian		ap->len = strlen(value) + 1;
17665843Sbrian	}
17765843Sbrian}
17865843Sbrian
17965843Sbrianvoid
18065843Sbriangctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value)
18165843Sbrian{
18265843Sbrian
18365843Sbrian	gctl_param_add(req, name, len, __DECONST(void *, value), GCTL_PARAM_RD);
18461981Sbrian}
18561981Sbrian
18661981Sbrianvoid
18761981Sbriangctl_rw_param(struct gctl_req *req, const char *name, int len, void *value)
18861981Sbrian{
18961981Sbrian
19061981Sbrian	gctl_param_add(req, name, len, value, GCTL_PARAM_RW);
19161981Sbrian}
19261981Sbrian
19361981Sbrianconst char *
19461981Sbriangctl_issue(struct gctl_req *req)
19561981Sbrian{
19661981Sbrian	int fd, error;
19761981Sbrian
19861981Sbrian	if (req == NULL)
19961981Sbrian		return ("NULL request pointer");
20061981Sbrian	if (req->error != NULL)
20161981Sbrian		return (req->error);
20262206Sbrian
20362155Sbrian	req->version = GCTL_VERSION;
20462155Sbrian	req->lerror = BUFSIZ;		/* XXX: arbitrary number */
20561981Sbrian	req->error = calloc(1, req->lerror);
20661981Sbrian	if (req->error == NULL) {
20761981Sbrian		gctl_check_alloc(req, req->error);
20861981Sbrian		return (req->error);
20961981Sbrian	}
21061981Sbrian	req->lerror--;
21165843Sbrian	fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY);
21265843Sbrian	if (fd < 0)
21365843Sbrian		return(strerror(errno));
21465843Sbrian	error = ioctl(fd, GEOM_CTL, req);
21565843Sbrian	close(fd);
21665843Sbrian	if (req->error[0] != '\0')
21765843Sbrian		return (req->error);
21865843Sbrian	if (error != 0)
21965843Sbrian		return(strerror(errno));
22065843Sbrian	return (NULL);
22161981Sbrian}
22261981Sbrian
22361981Sbrianvoid
22461981Sbriangctl_free(struct gctl_req *req)
22561981Sbrian{
22661981Sbrian	unsigned int i;
22761981Sbrian
22861981Sbrian	if (req == NULL)
22961981Sbrian		return;
23061981Sbrian	for (i = 0; i < req->narg; i++) {
23161981Sbrian		if (req->arg[i].name != NULL)
23261981Sbrian			free(req->arg[i].name);
23361981Sbrian	}
23461981Sbrian	free(req->arg);
23561981Sbrian	if (req->error != NULL && req->error != nomemmsg)
23661981Sbrian		free(req->error);
23761981Sbrian	free(req);
23861981Sbrian}
23961981Sbrian