Run a revision on the OAM api.
Use prefix gctl_ systematically. Add flag with access perms for each argument. Add ro/rw versions of argument building functions. General cleanup.
This commit is contained in:
parent
5e52756d9d
commit
63728c47e8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=112709
@ -35,29 +35,30 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <paths.h>
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define GEOM_CTL_TABLE 1
|
||||
#define GCTL_TABLE 1
|
||||
#include <libgeom.h>
|
||||
|
||||
#include <geom/geom_ext.h>
|
||||
|
||||
void
|
||||
geom_ctl_dump(struct geom_ctl_req *req, FILE *f)
|
||||
gctl_dump(struct gctl_req *req, FILE *f)
|
||||
{
|
||||
u_int i;
|
||||
int j;
|
||||
struct geom_ctl_req_arg *ap;
|
||||
struct gctl_req_arg *ap;
|
||||
|
||||
if (req == NULL) {
|
||||
fprintf(f, "Dump of geom_ctl request at NULL\n");
|
||||
fprintf(f, "Dump of gctl request at NULL\n");
|
||||
return;
|
||||
}
|
||||
fprintf(f, "Dump of geom_ctl %s request at %p:\n", req->reqt->name, req);
|
||||
fprintf(f, "Dump of gctl %s request at %p:\n", req->reqt->name, req);
|
||||
if (req->error != NULL)
|
||||
fprintf(f, " error:\t\"%s\"\n", req->error);
|
||||
else
|
||||
@ -68,24 +69,30 @@ geom_ctl_dump(struct geom_ctl_req *req, FILE *f)
|
||||
fprintf(f, " param:\t\"%s\"", ap->name);
|
||||
else
|
||||
fprintf(f, " meta:\t@%jd", (intmax_t)ap->offset);
|
||||
fprintf(f, " [%s%s",
|
||||
ap->flag & GCTL_PARAM_RD ? "R" : "",
|
||||
ap->flag & GCTL_PARAM_WR ? "W" : "");
|
||||
fflush(f);
|
||||
if (ap->len < 0)
|
||||
fprintf(f, " = [%d] \"%s\"", -ap->len, (char *)ap->value);
|
||||
if (ap->flag & GCTL_PARAM_ASCII)
|
||||
fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value);
|
||||
else if (ap->len > 0) {
|
||||
fprintf(f, " = [%d]", ap->len);
|
||||
fprintf(f, "%d] = ", ap->len);
|
||||
fflush(f);
|
||||
for (j = 0; j < ap->len; j++) {
|
||||
fprintf(f, " %02x", ((u_char *)ap->value)[j]);
|
||||
}
|
||||
} else {
|
||||
fprintf(f, " = [0] %p", ap->value);
|
||||
fprintf(f, "0] = %p", ap->value);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set an error message, if one does not already exist.
|
||||
*/
|
||||
static void
|
||||
geom_ctl_set_error(struct geom_ctl_req *req, const char *error, ...)
|
||||
gctl_set_error(struct gctl_req *req, const char *error, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@ -93,107 +100,145 @@ geom_ctl_set_error(struct geom_ctl_req *req, const char *error, ...)
|
||||
return;
|
||||
va_start(ap, error);
|
||||
vasprintf(&req->error, error, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that a malloc operation succeeded, and set a consistent error
|
||||
* message if not.
|
||||
*/
|
||||
static void
|
||||
geom_ctl_check_alloc(struct geom_ctl_req *req, void *ptr)
|
||||
gctl_check_alloc(struct gctl_req *req, void *ptr)
|
||||
{
|
||||
if (ptr != NULL)
|
||||
return;
|
||||
geom_ctl_set_error(req, "Could not allocate memory");
|
||||
gctl_set_error(req, "Could not allocate memory");
|
||||
if (req->error == NULL)
|
||||
req->error = "Could not allocate memory";
|
||||
}
|
||||
|
||||
struct geom_ctl_req *
|
||||
geom_ctl_get_handle(enum geom_ctl_request req)
|
||||
/*
|
||||
* Allocate a new request handle of the specified type.
|
||||
* XXX: Why bother checking the type ?
|
||||
*/
|
||||
struct gctl_req *
|
||||
gctl_get_handle(enum gctl_request req)
|
||||
{
|
||||
struct geom_ctl_req_table *gtp;
|
||||
struct geom_ctl_req *rp;
|
||||
struct gctl_req_table *gtp;
|
||||
struct gctl_req *rp;
|
||||
|
||||
rp = calloc(1, sizeof *rp);
|
||||
if (rp == NULL)
|
||||
return (NULL);
|
||||
for (gtp = gcrt; gtp->request != req; gtp++)
|
||||
if (gtp->request == GEOM_INVALID_REQUEST)
|
||||
if (gtp->request == GCTL_INVALID_REQUEST)
|
||||
break;
|
||||
|
||||
rp->request = req;
|
||||
rp->reqt = gtp;
|
||||
if (rp->reqt->request == GEOM_INVALID_REQUEST)
|
||||
geom_ctl_set_error(rp, "Invalid request");
|
||||
if (rp->reqt->request == GCTL_INVALID_REQUEST)
|
||||
gctl_set_error(rp, "Invalid request");
|
||||
return (rp);
|
||||
}
|
||||
|
||||
void
|
||||
geom_ctl_set_param(struct geom_ctl_req *req, const char *name, int len, void* value)
|
||||
/*
|
||||
* Allocate space for another argument.
|
||||
*/
|
||||
static struct gctl_req_arg *
|
||||
gctl_new_arg(struct gctl_req *req)
|
||||
{
|
||||
struct geom_ctl_req_arg *ap;
|
||||
struct gctl_req_arg *ap;
|
||||
|
||||
req->narg++;
|
||||
req->arg = realloc(req->arg, sizeof *ap * req->narg);
|
||||
gctl_check_alloc(req, req->arg);
|
||||
if (req->arg == NULL) {
|
||||
req->narg = 0;
|
||||
return (NULL);
|
||||
}
|
||||
ap = req->arg + (req->narg - 1);
|
||||
memset(ap, 0, sizeof *ap);
|
||||
return (ap);
|
||||
}
|
||||
|
||||
void
|
||||
gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value)
|
||||
{
|
||||
struct gctl_req_arg *ap;
|
||||
|
||||
if (req == NULL || req->error != NULL)
|
||||
return;
|
||||
if (req->reqt->params == 0)
|
||||
geom_ctl_set_error(req, "Request takes no parameters");
|
||||
req->narg++;
|
||||
req->arg = realloc(req->arg, sizeof *ap * req->narg);
|
||||
geom_ctl_check_alloc(req, req->arg);
|
||||
if (req->arg != NULL) {
|
||||
ap = req->arg + (req->narg - 1);
|
||||
memset(ap, 0, sizeof *ap);
|
||||
ap->name = strdup(name);
|
||||
geom_ctl_check_alloc(req, ap->name);
|
||||
ap->nlen = strlen(ap->name);
|
||||
ap = gctl_new_arg(req);
|
||||
if (ap == NULL)
|
||||
return;
|
||||
ap->name = strdup(name);
|
||||
gctl_check_alloc(req, ap->name);
|
||||
ap->nlen = strlen(ap->name) + 1;
|
||||
ap->value = __DECONST(void *, value);
|
||||
ap->flag = GCTL_PARAM_RD;
|
||||
if (len >= 0)
|
||||
ap->len = len;
|
||||
if (len > 0) {
|
||||
ap->value = value;
|
||||
} else if (len < 0) {
|
||||
ap->len = -strlen(value);
|
||||
ap->value = strdup(value);
|
||||
} else {
|
||||
ap->value = value;
|
||||
}
|
||||
if (len != 0)
|
||||
geom_ctl_check_alloc(req, ap->value);
|
||||
} else {
|
||||
req->narg = 0;
|
||||
else if (len < 0) {
|
||||
ap->flag |= GCTL_PARAM_ASCII;
|
||||
ap->len = strlen(value) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
geom_ctl_set_meta(struct geom_ctl_req *req, off_t offset, u_int len, void* value)
|
||||
gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value)
|
||||
{
|
||||
struct geom_ctl_req_arg *ap;
|
||||
u_int i;
|
||||
struct gctl_req_arg *ap;
|
||||
|
||||
if (req == NULL || req->error != NULL)
|
||||
return;
|
||||
if (req->reqt->meta == 0)
|
||||
geom_ctl_set_error(req, "Request takes no meta data");
|
||||
for (i = 0; i < req->narg; i++) {
|
||||
ap = &req->arg[i];
|
||||
if (ap->name != NULL)
|
||||
continue;
|
||||
if (ap->offset >= offset + len)
|
||||
continue;
|
||||
if (ap->offset + ap->len <= offset)
|
||||
continue;
|
||||
geom_ctl_set_error(req, "Overlapping meta data");
|
||||
ap = gctl_new_arg(req);
|
||||
if (ap == NULL)
|
||||
return;
|
||||
}
|
||||
req->narg++;
|
||||
req->arg = realloc(req->arg, sizeof *ap * req->narg);
|
||||
geom_ctl_check_alloc(req, req->arg);
|
||||
if (req->arg != NULL) {
|
||||
ap = req->arg + (req->narg - 1);
|
||||
memset(ap, 0, sizeof *ap);
|
||||
ap->value = value;
|
||||
ap->offset = offset;
|
||||
ap->name = strdup(name);
|
||||
gctl_check_alloc(req, ap->name);
|
||||
ap->nlen = strlen(ap->name) + 1;
|
||||
ap->value = value;
|
||||
ap->flag = GCTL_PARAM_RW;
|
||||
if (len >= 0)
|
||||
ap->len = len;
|
||||
} else {
|
||||
req->narg = 0;
|
||||
}
|
||||
else if (len < 0)
|
||||
ap->len = strlen(value) + 1;
|
||||
}
|
||||
|
||||
void
|
||||
gctl_ro_meta(struct gctl_req *req, off_t offset, u_int len, const void* value)
|
||||
{
|
||||
struct gctl_req_arg *ap;
|
||||
|
||||
if (req == NULL || req->error != NULL)
|
||||
return;
|
||||
ap = gctl_new_arg(req);
|
||||
if (ap == NULL)
|
||||
return;
|
||||
ap->value = __DECONST(void *, value);
|
||||
ap->flag = GCTL_PARAM_RD;
|
||||
ap->offset = offset;
|
||||
ap->len = len;
|
||||
}
|
||||
|
||||
void
|
||||
gctl_rw_meta(struct gctl_req *req, off_t offset, u_int len, void* value)
|
||||
{
|
||||
struct gctl_req_arg *ap;
|
||||
|
||||
if (req == NULL || req->error != NULL)
|
||||
return;
|
||||
ap = gctl_new_arg(req);
|
||||
if (ap == NULL)
|
||||
return;
|
||||
ap->value = value;
|
||||
ap->flag = GCTL_PARAM_RW;
|
||||
ap->offset = offset;
|
||||
ap->len = len;
|
||||
}
|
||||
|
||||
const char *
|
||||
geom_ctl_issue(struct geom_ctl_req *req)
|
||||
gctl_issue(struct gctl_req *req)
|
||||
{
|
||||
int fd, error;
|
||||
|
||||
@ -202,16 +247,21 @@ geom_ctl_issue(struct geom_ctl_req *req)
|
||||
if (req->error != NULL)
|
||||
return (req->error);
|
||||
|
||||
req->version = GEOM_CTL_VERSION;
|
||||
req->version = GCTL_VERSION;
|
||||
req->lerror = BUFSIZ; /* XXX: arbitrary number */
|
||||
req->error = malloc(req->lerror);
|
||||
if (req->error == NULL) {
|
||||
gctl_check_alloc(req, req->error);
|
||||
return (req->error);
|
||||
}
|
||||
memset(req->error, 0, req->lerror);
|
||||
req->lerror--;
|
||||
fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return(strerror(errno));
|
||||
error = ioctl(fd, GEOM_CTL, req);
|
||||
if (error && errno == EINVAL && req->error[0] != '\0')
|
||||
close(fd);
|
||||
if (req->error[0] != '\0')
|
||||
return (req->error);
|
||||
if (error != 0)
|
||||
return(strerror(errno));
|
||||
@ -219,19 +269,18 @@ geom_ctl_issue(struct geom_ctl_req *req)
|
||||
}
|
||||
|
||||
void
|
||||
geom_ctl_free(struct geom_ctl_req *req)
|
||||
gctl_free(struct gctl_req *req)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (req == NULL)
|
||||
return;
|
||||
for (i = 0; i < req->narg; i++) {
|
||||
if (req->arg[i].name != NULL)
|
||||
free(req->arg[i].name);
|
||||
if (req->arg[i].len < 0)
|
||||
free(req->arg[i].value);
|
||||
}
|
||||
free(req->arg);
|
||||
if (req->error != NULL)
|
||||
free(req->error);
|
||||
free(req->arg);
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
@ -129,23 +129,17 @@ void geom_deletetree(struct gmesh *gmp);
|
||||
|
||||
/* geom_ctl.c */
|
||||
|
||||
struct geom_ctl_req;
|
||||
struct gctl_req;
|
||||
|
||||
#ifdef _STDIO_H_ /* limit #include pollution */
|
||||
void geom_ctl_dump(struct geom_ctl_req *req, FILE *f);
|
||||
void gctl_dump(struct gctl_req *req, FILE *f);
|
||||
#endif
|
||||
void geom_ctl_free(struct geom_ctl_req *req);
|
||||
struct geom_ctl_req *geom_ctl_get_handle(enum geom_ctl_request req);
|
||||
const char *geom_ctl_issue(struct geom_ctl_req *req);
|
||||
void geom_ctl_set_class_by_id(struct geom_ctl_req *req, void *id);
|
||||
void geom_ctl_set_class_by_name(struct geom_ctl_req *req, const char *name);
|
||||
void geom_ctl_set_consumer_by_id(struct geom_ctl_req *req, void *id);
|
||||
void geom_ctl_set_consumer_by_name(struct geom_ctl_req *req, const char *name);
|
||||
void geom_ctl_set_geom_by_id(struct geom_ctl_req *req, void *id);
|
||||
void geom_ctl_set_geom_by_name(struct geom_ctl_req *req, const char *name);
|
||||
void geom_ctl_set_meta(struct geom_ctl_req *req, off_t offset, u_int len, void* val);
|
||||
void geom_ctl_set_param(struct geom_ctl_req *req, const char *name, int len, void* val);
|
||||
void geom_ctl_set_provider_by_id(struct geom_ctl_req *req, void *id);
|
||||
void geom_ctl_set_provider_by_name(struct geom_ctl_req *req, const char *name);
|
||||
void gctl_free(struct gctl_req *req);
|
||||
struct gctl_req *gctl_get_handle(enum gctl_request req);
|
||||
const char *gctl_issue(struct gctl_req *req);
|
||||
void gctl_ro_meta(struct gctl_req *req, off_t offset, u_int len, const void* val);
|
||||
void gctl_rw_meta(struct gctl_req *req, off_t offset, u_int len, void* val);
|
||||
void gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* val);
|
||||
void gctl_rw_param(struct gctl_req *req, const char *name, int len, void* val);
|
||||
|
||||
#endif /* _LIBGEOM_H_ */
|
||||
|
@ -62,9 +62,12 @@ struct g_stat;
|
||||
struct thread;
|
||||
struct bio;
|
||||
struct sbuf;
|
||||
struct gctl_req;
|
||||
struct g_configargs;
|
||||
|
||||
typedef int g_config_t (struct g_configargs *ca);
|
||||
typedef int g_ctl_create_geom_t (struct gctl_req *, struct g_class *cp, struct g_provider *pp);
|
||||
typedef int g_ctl_destroy_geom_t (struct gctl_req *, struct g_class *cp, struct g_geom *gp);
|
||||
typedef struct g_geom * g_taste_t (struct g_class *, struct g_provider *,
|
||||
int flags);
|
||||
#define G_TF_NORMAL 0
|
||||
@ -90,6 +93,8 @@ struct g_class {
|
||||
const char *name;
|
||||
g_taste_t *taste;
|
||||
g_config_t *config;
|
||||
g_ctl_create_geom_t *create_geom;
|
||||
g_ctl_destroy_geom_t *destroy_geom;
|
||||
/*
|
||||
* The remaning elements are private and classes should use
|
||||
* the G_CLASS_INITIALIZER macro to initialize them.
|
||||
@ -426,6 +431,10 @@ struct gcfg_magicrw {
|
||||
*/
|
||||
|
||||
|
||||
/* geom_ctl.c */
|
||||
void *gctl_get_param(struct gctl_req *req, const char *param, int *len);
|
||||
int gctl_error(struct gctl_req *req, const char *errtxt);
|
||||
|
||||
/* geom_enc.c */
|
||||
uint16_t g_dec_be2(const u_char *p);
|
||||
uint32_t g_dec_be4(const u_char *p);
|
||||
|
@ -55,7 +55,7 @@
|
||||
|
||||
#include <geom/geom.h>
|
||||
#include <geom/geom_int.h>
|
||||
#define GEOM_CTL_TABLE 1
|
||||
#define GCTL_TABLE 1
|
||||
#include <geom/geom_ctl.h>
|
||||
#include <geom/geom_ext.h>
|
||||
|
||||
@ -74,6 +74,10 @@ g_ctl_init(void)
|
||||
|
||||
make_dev(&g_ctl_cdevsw, 0,
|
||||
UID_ROOT, GID_OPERATOR, 0640, PATH_GEOM_CTL);
|
||||
KASSERT(GCTL_PARAM_RD == VM_PROT_READ,
|
||||
("GCTL_PARAM_RD != VM_PROT_READ"));
|
||||
KASSERT(GCTL_PARAM_WR == VM_PROT_WRITE,
|
||||
("GCTL_PARAM_WR != VM_PROT_WRITE"));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -125,8 +129,8 @@ g_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct th
|
||||
* XXX: should not be static.
|
||||
* XXX: should take printf like args.
|
||||
*/
|
||||
static int
|
||||
g_ctl_seterror(struct geom_ctl_req *req, const char *errtxt)
|
||||
int
|
||||
gctl_error(struct gctl_req *req, const char *errtxt)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -142,7 +146,7 @@ g_ctl_seterror(struct geom_ctl_req *req, const char *errtxt)
|
||||
* XXX: this should really be a standard function in the kernel.
|
||||
*/
|
||||
static void *
|
||||
geom_alloc_copyin(void *uaddr, size_t len, int *errp)
|
||||
geom_alloc_copyin(struct gctl_req *req, void *uaddr, size_t len, int *errp)
|
||||
{
|
||||
int error;
|
||||
void *ptr;
|
||||
@ -154,6 +158,7 @@ geom_alloc_copyin(void *uaddr, size_t len, int *errp)
|
||||
error = copyin(uaddr, ptr, len);
|
||||
if (!error)
|
||||
return (ptr);
|
||||
gctl_error(req, "no access to argument");
|
||||
*errp = error;
|
||||
if (ptr != NULL)
|
||||
g_free(ptr);
|
||||
@ -169,45 +174,46 @@ geom_alloc_copyin(void *uaddr, size_t len, int *errp)
|
||||
*/
|
||||
|
||||
static int
|
||||
geom_ctl_copyin(struct geom_ctl_req *req)
|
||||
gctl_copyin(struct gctl_req *req)
|
||||
{
|
||||
int error, i, j;
|
||||
struct geom_ctl_req_arg *ap;
|
||||
struct gctl_req_arg *ap;
|
||||
char *p;
|
||||
|
||||
error = 0;
|
||||
if (!useracc(req->error, req->lerror, VM_PROT_WRITE))
|
||||
return (g_ctl_seterror(req, "No access to error field"));
|
||||
ap = geom_alloc_copyin(req->arg, req->narg * sizeof(*ap), &error);
|
||||
if (ap == NULL)
|
||||
ap = geom_alloc_copyin(req, req->arg, req->narg * sizeof(*ap), &error);
|
||||
if (ap == NULL) {
|
||||
gctl_error(req, "copyin() of arguments failed");
|
||||
return (error);
|
||||
}
|
||||
|
||||
for (i = 0; !error && i < req->narg; i++) {
|
||||
if (ap[i].len < 0 &&
|
||||
!useracc(ap[i].value, 1 + -ap[i].len, VM_PROT_READ))
|
||||
error = g_ctl_seterror(req, "No access to param data");
|
||||
else if (ap[i].len > 0 &&
|
||||
!useracc(ap[i].value, ap[i].len,
|
||||
VM_PROT_READ | VM_PROT_WRITE))
|
||||
error = g_ctl_seterror(req, "No access to param data");
|
||||
if (ap[i].name == NULL)
|
||||
continue;
|
||||
if (ap[i].len > 0 &&
|
||||
!useracc(ap[i].value, ap[i].len,
|
||||
ap[i].flag & GCTL_PARAM_RW))
|
||||
error = gctl_error(req, "no access to param data");
|
||||
if (ap[i].name == NULL) {
|
||||
if (req->reqt->meta)
|
||||
continue;
|
||||
error = gctl_error(req,
|
||||
"request does not take metadata arguments");
|
||||
break;
|
||||
}
|
||||
p = NULL;
|
||||
if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN)
|
||||
error = EINVAL;
|
||||
if (error)
|
||||
if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) {
|
||||
error = gctl_error(req, "wrong param name length");
|
||||
break;
|
||||
p = geom_alloc_copyin(ap[i].name, ap[i].nlen + 1, &error);
|
||||
if (error)
|
||||
}
|
||||
p = geom_alloc_copyin(req, ap[i].name, ap[i].nlen, &error);
|
||||
if (p == NULL)
|
||||
break;
|
||||
if (p[ap[i].nlen] != '\0')
|
||||
error = EINVAL;
|
||||
if (!error) {
|
||||
ap[i].name = p;
|
||||
ap[i].nlen = 0;
|
||||
} else {
|
||||
if (p[ap[i].nlen - 1] != '\0') {
|
||||
error = gctl_error(req, "unterminated param name");
|
||||
g_free(p);
|
||||
break;
|
||||
}
|
||||
ap[i].name = p;
|
||||
ap[i].nlen = 0;
|
||||
}
|
||||
if (!error) {
|
||||
req->arg = ap;
|
||||
@ -221,17 +227,17 @@ geom_ctl_copyin(struct geom_ctl_req *req)
|
||||
}
|
||||
|
||||
static void
|
||||
geom_ctl_dump(struct geom_ctl_req *req)
|
||||
gctl_dump(struct gctl_req *req)
|
||||
{
|
||||
u_int i;
|
||||
int j, error;
|
||||
struct geom_ctl_req_arg *ap;
|
||||
struct gctl_req_arg *ap;
|
||||
void *p;
|
||||
|
||||
|
||||
printf("Dump of geom_ctl %s request at %p:\n", req->reqt->name, req);
|
||||
printf("Dump of gctl %s request at %p:\n", req->reqt->name, req);
|
||||
if (req->lerror > 0) {
|
||||
p = geom_alloc_copyin(req->error, req->lerror, &error);
|
||||
p = geom_alloc_copyin(req, req->error, req->lerror, &error);
|
||||
if (p != NULL) {
|
||||
((char *)p)[req->lerror - 1] = '\0';
|
||||
printf(" error:\t\"%s\"\n", (char *)p);
|
||||
@ -244,15 +250,19 @@ geom_ctl_dump(struct geom_ctl_req *req)
|
||||
printf(" param:\t\"%s\"", ap->name);
|
||||
else
|
||||
printf(" meta:\t@%jd", (intmax_t)ap->offset);
|
||||
printf(" [%d] = ", ap->len);
|
||||
if (ap->len < 0) {
|
||||
p = geom_alloc_copyin(ap->value, 1 + -ap->len, &error);
|
||||
((char *)p)[-ap->len] = '\0';
|
||||
if (p != NULL)
|
||||
printf(" [%s%s%d] = ",
|
||||
ap->flag & GCTL_PARAM_RD ? "R" : "",
|
||||
ap->flag & GCTL_PARAM_WR ? "W" : "",
|
||||
ap->len);
|
||||
if (ap->flag & GCTL_PARAM_ASCII) {
|
||||
p = geom_alloc_copyin(req, ap->value, ap->len, &error);
|
||||
if (p != NULL) {
|
||||
((char *)p)[ap->len - 1] = '\0';
|
||||
printf("\"%s\"", (char *)p);
|
||||
}
|
||||
g_free(p);
|
||||
} else if (ap->len > 0) {
|
||||
p = geom_alloc_copyin(ap->value, ap->len, &error);
|
||||
p = geom_alloc_copyin(req, ap->value, ap->len, &error);
|
||||
for (j = 0; j < ap->len; j++)
|
||||
printf(" %02x", ((u_char *)p)[j]);
|
||||
g_free(p);
|
||||
@ -263,6 +273,171 @@ geom_ctl_dump(struct geom_ctl_req *req)
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
gctl_get_param(struct gctl_req *req, const char *param, int *len)
|
||||
{
|
||||
int i, error, j;
|
||||
void *p;
|
||||
struct gctl_req_arg *ap;
|
||||
|
||||
for (i = 0; i < req->narg; i++) {
|
||||
ap = &req->arg[i];
|
||||
if (strcmp(param, ap->name))
|
||||
continue;
|
||||
if (!(ap->flag & GCTL_PARAM_RD))
|
||||
continue;
|
||||
if (ap->len > 0)
|
||||
j = ap->len;
|
||||
else
|
||||
j = 0;
|
||||
if (j != 0)
|
||||
p = geom_alloc_copyin(req, ap->value, j, &error);
|
||||
/* XXX: should not fail, tested prviously */
|
||||
else
|
||||
p = ap->value;
|
||||
if (len != NULL)
|
||||
*len = j;
|
||||
return (p);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static struct g_class*
|
||||
gctl_get_class(struct gctl_req *req)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
struct g_class *cp;
|
||||
|
||||
p = gctl_get_param(req, "class", &len);
|
||||
if (p == NULL)
|
||||
return (NULL);
|
||||
if (p[len - 1] != '\0') {
|
||||
gctl_error(req, "Unterminated class name");
|
||||
g_free(p);
|
||||
return (NULL);
|
||||
}
|
||||
LIST_FOREACH(cp, &g_classes, class) {
|
||||
if (!strcmp(p, cp->name)) {
|
||||
g_free(p);
|
||||
return (cp);
|
||||
}
|
||||
}
|
||||
gctl_error(req, "Class not found");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static struct g_geom*
|
||||
gctl_get_geom(struct gctl_req *req, struct g_class *mpr)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
struct g_class *mp;
|
||||
struct g_geom *gp;
|
||||
|
||||
p = gctl_get_param(req, "geom", &len);
|
||||
if (p == NULL)
|
||||
return (NULL);
|
||||
if (p[len - 1] != '\0') {
|
||||
gctl_error(req, "Unterminated provider name");
|
||||
g_free(p);
|
||||
return (NULL);
|
||||
}
|
||||
LIST_FOREACH(mp, &g_classes, class) {
|
||||
if (mpr != NULL && mpr != mp)
|
||||
continue;
|
||||
LIST_FOREACH(gp, &mp->geom, geom) {
|
||||
if (!strcmp(p, gp->name)) {
|
||||
g_free(p);
|
||||
return (gp);
|
||||
}
|
||||
}
|
||||
}
|
||||
gctl_error(req, "Geom not found");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static struct g_provider*
|
||||
gctl_get_provider(struct gctl_req *req)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
struct g_class *cp;
|
||||
struct g_geom *gp;
|
||||
struct g_provider *pp;
|
||||
|
||||
p = gctl_get_param(req, "provider", &len);
|
||||
if (p == NULL)
|
||||
return (NULL);
|
||||
if (p[len - 1] != '\0') {
|
||||
gctl_error(req, "Unterminated provider name");
|
||||
g_free(p);
|
||||
return (NULL);
|
||||
}
|
||||
LIST_FOREACH(cp, &g_classes, class) {
|
||||
LIST_FOREACH(gp, &cp->geom, geom) {
|
||||
LIST_FOREACH(pp, &gp->provider, provider) {
|
||||
if (!strcmp(p, pp->name)) {
|
||||
g_free(p);
|
||||
return (pp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gctl_error(req, "Provider not found");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gctl_create_geom(struct gctl_req *req)
|
||||
{
|
||||
struct g_class *mp;
|
||||
struct g_provider *pp;
|
||||
|
||||
g_topology_assert();
|
||||
mp = gctl_get_class(req);
|
||||
if (mp == NULL)
|
||||
return;
|
||||
printf("Found class: %p\n", mp);
|
||||
if (mp->create_geom == NULL) {
|
||||
gctl_error(req, "Class has no create_geom method");
|
||||
return;
|
||||
}
|
||||
pp = gctl_get_provider(req);
|
||||
printf("Found provider: %p\n", pp);
|
||||
mp->create_geom(req, mp, pp);
|
||||
g_topology_assert();
|
||||
}
|
||||
|
||||
static void
|
||||
gctl_destroy_geom(struct gctl_req *req)
|
||||
{
|
||||
struct g_class *mp;
|
||||
struct g_geom *gp;
|
||||
|
||||
g_topology_assert();
|
||||
mp = gctl_get_class(req);
|
||||
if (mp == NULL)
|
||||
return;
|
||||
printf("Found class: %p\n", mp);
|
||||
if (mp->destroy_geom == NULL) {
|
||||
gctl_error(req, "Class has no destroy_geom method");
|
||||
return;
|
||||
}
|
||||
gp = gctl_get_geom(req, mp);
|
||||
if (gp == NULL) {
|
||||
gctl_error(req, "Geom not specified");
|
||||
return;
|
||||
}
|
||||
if (gp->class != mp) {
|
||||
gctl_error(req, "Geom not of specificed class");
|
||||
return;
|
||||
}
|
||||
printf("Found geom: %p\n", gp);
|
||||
mp->destroy_geom(req, mp, gp);
|
||||
g_topology_assert();
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle ioctl from libgeom::geom_ctl.c
|
||||
*/
|
||||
@ -271,28 +446,53 @@ g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *t
|
||||
{
|
||||
int error;
|
||||
int i;
|
||||
struct geom_ctl_req *req;
|
||||
struct gctl_req *req;
|
||||
|
||||
req = (void *)data;
|
||||
/* It is an error if we cannot return an error text */
|
||||
if (req->lerror < 1)
|
||||
return (EINVAL);
|
||||
if (req->version != GEOM_CTL_VERSION)
|
||||
return (g_ctl_seterror(req,
|
||||
"Kernel and libgeom version skew."));
|
||||
for (i = 0; gcrt[i].request != GEOM_INVALID_REQUEST; i++)
|
||||
if (gcrt[i].request == req->request) {
|
||||
req->reqt = &gcrt[i];
|
||||
if (!useracc(req->error, req->lerror, VM_PROT_WRITE))
|
||||
return (EINVAL);
|
||||
|
||||
/* Check the version */
|
||||
if (req->version != GCTL_VERSION)
|
||||
return (gctl_error(req,
|
||||
"kernel and libgeom version mismatch."));
|
||||
|
||||
/* Check the request type */
|
||||
for (i = 0; gcrt[i].request != GCTL_INVALID_REQUEST; i++)
|
||||
if (gcrt[i].request == req->request)
|
||||
break;
|
||||
}
|
||||
if (gcrt[i].request == GEOM_INVALID_REQUEST)
|
||||
return (g_ctl_seterror(req, "Invalid request"));
|
||||
error = geom_ctl_copyin(req);
|
||||
if (gcrt[i].request == GCTL_INVALID_REQUEST)
|
||||
return (gctl_error(req, "invalid request"));
|
||||
req->reqt = &gcrt[i];
|
||||
|
||||
/* Get things on board */
|
||||
error = gctl_copyin(req);
|
||||
if (error)
|
||||
return (error);
|
||||
req->reqt = &gcrt[i];
|
||||
|
||||
gctl_dump(req);
|
||||
#if 0
|
||||
g_stall_events();
|
||||
geom_ctl_dump(req);
|
||||
#endif
|
||||
g_topology_lock();
|
||||
switch (req->request) {
|
||||
case GCTL_CREATE_GEOM:
|
||||
gctl_create_geom(req);
|
||||
break;
|
||||
case GCTL_DESTROY_GEOM:
|
||||
gctl_destroy_geom(req);
|
||||
break;
|
||||
default:
|
||||
gctl_error(req, "XXX: TBD");
|
||||
break;
|
||||
}
|
||||
g_topology_unlock();
|
||||
#if 0
|
||||
g_release_events();
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -310,7 +510,9 @@ g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
|
||||
PICKUP_GIANT();
|
||||
break;
|
||||
case GEOM_CTL:
|
||||
DROP_GIANT();
|
||||
error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td);
|
||||
PICKUP_GIANT();
|
||||
break;
|
||||
default:
|
||||
error = ENOTTY;
|
||||
|
@ -35,27 +35,27 @@
|
||||
/*
|
||||
* Version number. Used to check consistency between kernel and libgeom.
|
||||
*/
|
||||
#define GEOM_CTL_VERSION 1
|
||||
#define GCTL_VERSION 1
|
||||
|
||||
/*
|
||||
* Primitives.
|
||||
*/
|
||||
enum geom_ctl_request {
|
||||
GEOM_INVALID_REQUEST = 0,
|
||||
GEOM_CREATE_GEOM,
|
||||
GEOM_NEW_GEOM,
|
||||
GEOM_ATTACH,
|
||||
GEOM_DETACH,
|
||||
GEOM_CREATE_PROVIDER,
|
||||
GEOM_DESTROY_PROVIDER,
|
||||
GEOM_INSERT_GEOM,
|
||||
GEOM_ELIMINATE_GEOM,
|
||||
GEOM_WRITE_META,
|
||||
GEOM_READ_META
|
||||
enum gctl_request {
|
||||
GCTL_INVALID_REQUEST = 0,
|
||||
GCTL_CREATE_GEOM,
|
||||
GCTL_DESTROY_GEOM,
|
||||
GCTL_ATTACH,
|
||||
GCTL_DETACH,
|
||||
GCTL_CREATE_PROVIDER,
|
||||
GCTL_DESTROY_PROVIDER,
|
||||
GCTL_INSERT_GEOM,
|
||||
GCTL_ELIMINATE_GEOM,
|
||||
GCTL_WRITE_META,
|
||||
GCTL_READ_META
|
||||
};
|
||||
|
||||
#ifdef GEOM_CTL_TABLE
|
||||
struct geom_ctl_req_table {
|
||||
#ifdef GCTL_TABLE
|
||||
struct gctl_req_table {
|
||||
int class;
|
||||
int geom;
|
||||
int provider;
|
||||
@ -63,24 +63,24 @@ struct geom_ctl_req_table {
|
||||
int params;
|
||||
int meta;
|
||||
char *name;
|
||||
enum geom_ctl_request request;
|
||||
enum gctl_request request;
|
||||
} gcrt[] = {
|
||||
/* Cl Ge Pr Co Pa Me Name Request */
|
||||
{ 1, 1, 1, 0, 1, 0, "create geom", GEOM_CREATE_GEOM },
|
||||
{ 1, 1, 0, 0, 1, 0, "new geom", GEOM_NEW_GEOM },
|
||||
{ 0, 1, 1, 0, 1, 0, "attach", GEOM_ATTACH },
|
||||
{ 0, 1, 1, 0, 1, 0, "detach", GEOM_DETACH },
|
||||
{ 0, 1, 0, 0, 1, 0, "create provider", GEOM_CREATE_PROVIDER },
|
||||
{ 0, 1, 1, 0, 1, 0, "destroy provider", GEOM_DESTROY_PROVIDER },
|
||||
{ 1, 1, 1, 0, 1, 0, "insert geom", GEOM_INSERT_GEOM },
|
||||
{ 0, 1, 0, 0, 1, 0, "eliminate geom", GEOM_ELIMINATE_GEOM },
|
||||
{ 0, 1, 0, 0, 1, 1, "write meta", GEOM_WRITE_META },
|
||||
{ 0, 1, 0, 0, 1, 1, "read meta", GEOM_READ_META },
|
||||
{ 1, 0, 1, 0, 1, 0, "create geom", GCTL_CREATE_GEOM },
|
||||
{ 0, 1, 0, 0, 1, 0, "destroy geom", GCTL_DESTROY_GEOM },
|
||||
{ 0, 1, 1, 0, 1, 0, "attach", GCTL_ATTACH },
|
||||
{ 0, 1, 1, 0, 1, 0, "detach", GCTL_DETACH },
|
||||
{ 0, 1, 0, 0, 1, 0, "create provider", GCTL_CREATE_PROVIDER },
|
||||
{ 0, 1, 1, 0, 1, 0, "destroy provider", GCTL_DESTROY_PROVIDER },
|
||||
{ 1, 1, 1, 0, 1, 0, "insert geom", GCTL_INSERT_GEOM },
|
||||
{ 0, 1, 0, 0, 1, 0, "eliminate geom", GCTL_ELIMINATE_GEOM },
|
||||
{ 0, 1, 0, 0, 1, 1, "write meta", GCTL_WRITE_META },
|
||||
{ 0, 1, 0, 0, 1, 1, "read meta", GCTL_READ_META },
|
||||
|
||||
/* Terminator entry */
|
||||
{ 1, 1, 1, 1, 1, 1, "*INVALID*", GEOM_INVALID_REQUEST }
|
||||
{ 1, 1, 1, 1, 1, 1, "*INVALID*", GCTL_INVALID_REQUEST }
|
||||
};
|
||||
|
||||
#endif /* GEOM_CTL_TABLE */
|
||||
#endif /* GCTL_TABLE */
|
||||
|
||||
#endif /* _GEOM_GEOM_CTL_H_ */
|
||||
|
@ -40,26 +40,32 @@
|
||||
#include <sys/ioccom.h>
|
||||
#include <geom/geom_ctl.h>
|
||||
|
||||
struct geom_ctl_req_arg {
|
||||
struct gctl_req_arg {
|
||||
u_int nlen;
|
||||
char *name;
|
||||
off_t offset;
|
||||
int flag;
|
||||
int len;
|
||||
void *value;
|
||||
};
|
||||
|
||||
struct geom_ctl_req {
|
||||
#define GCTL_PARAM_RD 1 /* Must match VM_PROT_READ */
|
||||
#define GCTL_PARAM_WR 2 /* Must match VM_PROT_WRITE */
|
||||
#define GCTL_PARAM_RW (GCTL_PARAM_RD | GCTL_PARAM_WR)
|
||||
#define GCTL_PARAM_ASCII 4
|
||||
|
||||
struct gctl_req {
|
||||
u_int version;
|
||||
u_int serial;
|
||||
enum geom_ctl_request request;
|
||||
enum gctl_request request;
|
||||
u_int narg;
|
||||
struct geom_ctl_req_arg *arg;
|
||||
struct gctl_req_arg *arg;
|
||||
u_int lerror;
|
||||
char *error;
|
||||
struct geom_ctl_req_table *reqt;
|
||||
struct gctl_req_table *reqt;
|
||||
};
|
||||
|
||||
#define GEOM_CTL _IOW('G', GEOM_CTL_VERSION, struct geom_ctl_req)
|
||||
#define GEOM_CTL _IOW('G', GCTL_VERSION, struct gctl_req)
|
||||
|
||||
#define PATH_GEOM_CTL "geom.ctl"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user