aboutsummaryrefslogtreecommitdiffstats
path: root/sbin/geom/misc/subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/geom/misc/subr.c')
-rw-r--r--sbin/geom/misc/subr.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/sbin/geom/misc/subr.c b/sbin/geom/misc/subr.c
new file mode 100644
index 000000000000..9d72e3483442
--- /dev/null
+++ b/sbin/geom/misc/subr.c
@@ -0,0 +1,247 @@
+/*-
+ * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/disk.h>
+#include <sys/endian.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <assert.h>
+#include <libgeom.h>
+
+#include "misc/subr.h"
+
+
+struct std_metadata {
+ char md_magic[16];
+ uint32_t md_version;
+};
+
+static void
+std_metadata_decode(const u_char *data, struct std_metadata *md)
+{
+
+ bcopy(data, md->md_magic, sizeof(md->md_magic));
+ md->md_version = le32dec(data + 16);
+}
+
+static void
+pathgen(const char *name, char *path, size_t size)
+{
+
+ if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
+ snprintf(path, size, "%s%s", _PATH_DEV, name);
+ else
+ strlcpy(path, name, size);
+}
+
+int
+g_metadata_store(const char *name, u_char *md, size_t size)
+{
+ char path[MAXPATHLEN];
+ unsigned sectorsize;
+ off_t mediasize;
+ u_char *sector;
+ int error, fd;
+
+ pathgen(name, path, sizeof(path));
+ sector = NULL;
+ error = 0;
+
+ fd = open(path, O_WRONLY);
+ if (fd == -1)
+ return (errno);
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
+ error = errno;
+ goto out;
+ }
+ if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
+ error = errno;
+ goto out;
+ }
+ assert(sectorsize >= size);
+ sector = malloc(sectorsize);
+ if (sector == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ bcopy(md, sector, size);
+ if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
+ (ssize_t)sectorsize) {
+ error = errno;
+ goto out;
+ }
+out:
+ if (sector != NULL)
+ free(sector);
+ close(fd);
+ return (error);
+}
+
+int
+g_metadata_clear(const char *name, const char *magic)
+{
+ struct std_metadata md;
+ char path[MAXPATHLEN];
+ unsigned sectorsize;
+ off_t mediasize;
+ u_char *sector;
+ int error, fd;
+
+ pathgen(name, path, sizeof(path));
+ sector = NULL;
+ error = 0;
+
+ fd = open(path, O_RDWR);
+ if (fd == -1)
+ return (errno);
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
+ error = errno;
+ goto out;
+ }
+ if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
+ error = errno;
+ goto out;
+ }
+ sector = malloc(sectorsize);
+ if (sector == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ if (magic != NULL) {
+ if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
+ (ssize_t)sectorsize) {
+ error = errno;
+ goto out;
+ }
+ std_metadata_decode(sector, &md);
+ if (strcmp(md.md_magic, magic) != 0) {
+ error = EINVAL;
+ goto out;
+ }
+ }
+ bzero(sector, sectorsize);
+ if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
+ (ssize_t)sectorsize) {
+ error = errno;
+ goto out;
+ }
+out:
+ if (sector != NULL)
+ free(sector);
+ close(fd);
+ return (error);
+}
+
+/*
+ * Set an error message, if one does not already exist.
+ */
+void
+gctl_error(struct gctl_req *req, const char *error, ...)
+{
+ va_list ap;
+
+ if (req->error != NULL)
+ return;
+ va_start(ap, error);
+ vasprintf(&req->error, error, ap);
+ va_end(ap);
+}
+
+void *
+gctl_get_param(struct gctl_req *req, const char *param, int *len)
+{
+ unsigned i;
+ 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;
+ p = ap->value;
+ if (len != NULL)
+ *len = ap->len;
+ return (p);
+ }
+ return (NULL);
+}
+
+char const *
+gctl_get_asciiparam(struct gctl_req *req, const char *param)
+{
+ unsigned i;
+ char const *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;
+ p = ap->value;
+ if (ap->len < 1) {
+ gctl_error(req, "No length argument (%s)", param);
+ return (NULL);
+ }
+ if (p[ap->len - 1] != '\0') {
+ gctl_error(req, "Unterminated argument (%s)", param);
+ return (NULL);
+ }
+ return (p);
+ }
+ return (NULL);
+}
+
+void *
+gctl_get_paraml(struct gctl_req *req, const char *param, int len)
+{
+ int i;
+ void *p;
+
+ p = gctl_get_param(req, param, &i);
+ if (p == NULL)
+ gctl_error(req, "Missing %s argument", param);
+ else if (i != len) {
+ p = NULL;
+ gctl_error(req, "Wrong length %s argument", param);
+ }
+ return (p);
+}