1129470Spjd/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4213074Spjd * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5129470Spjd * All rights reserved.
6129470Spjd *
7129470Spjd * Redistribution and use in source and binary forms, with or without
8129470Spjd * modification, are permitted provided that the following conditions
9129470Spjd * are met:
10129470Spjd * 1. Redistributions of source code must retain the above copyright
11129470Spjd *    notice, this list of conditions and the following disclaimer.
12129470Spjd * 2. Redistributions in binary form must reproduce the above copyright
13129470Spjd *    notice, this list of conditions and the following disclaimer in the
14129470Spjd *    documentation and/or other materials provided with the distribution.
15155175Spjd *
16129470Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17129470Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18129470Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19129470Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20129470Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21129470Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22129470Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23129470Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24129470Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25129470Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26129470Spjd * SUCH DAMAGE.
27129470Spjd */
28129470Spjd
29129470Spjd#include <sys/cdefs.h>
30129470Spjd__FBSDID("$FreeBSD: stable/11/sbin/geom/misc/subr.c 330726 2018-03-10 02:15:45Z asomers $");
31129470Spjd
32129470Spjd#include <sys/param.h>
33129470Spjd#include <sys/disk.h>
34129470Spjd#include <sys/endian.h>
35129470Spjd#include <sys/uio.h>
36129470Spjd#include <errno.h>
37129470Spjd#include <fcntl.h>
38129470Spjd#include <paths.h>
39129470Spjd#include <stdio.h>
40129470Spjd#include <stdlib.h>
41209388Sae#include <limits.h>
42209388Sae#include <inttypes.h>
43129470Spjd#include <stdarg.h>
44129470Spjd#include <string.h>
45129470Spjd#include <strings.h>
46129470Spjd#include <unistd.h>
47129470Spjd#include <assert.h>
48129470Spjd#include <libgeom.h>
49129470Spjd
50129470Spjd#include "misc/subr.h"
51129470Spjd
52129470Spjd
53129470Spjdstruct std_metadata {
54129470Spjd	char		md_magic[16];
55129470Spjd	uint32_t	md_version;
56129470Spjd};
57129470Spjd
58129470Spjdstatic void
59213074Spjdstd_metadata_decode(const unsigned char *data, struct std_metadata *md)
60129470Spjd{
61129470Spjd
62129470Spjd        bcopy(data, md->md_magic, sizeof(md->md_magic));
63129470Spjd        md->md_version = le32dec(data + 16);
64129470Spjd}
65129470Spjd
66130591Spjd/*
67130591Spjd * Greatest Common Divisor.
68130591Spjd */
69213074Spjdstatic unsigned int
70213074Spjdgcd(unsigned int a, unsigned int b)
71130591Spjd{
72213074Spjd	unsigned int c;
73130591Spjd
74130591Spjd	while (b != 0) {
75130591Spjd		c = a;
76130591Spjd		a = b;
77130591Spjd		b = (c % b);
78130591Spjd	}
79130591Spjd	return (a);
80130591Spjd}
81130591Spjd
82130591Spjd/*
83130591Spjd * Least Common Multiple.
84130591Spjd */
85213074Spjdunsigned int
86213074Spjdg_lcm(unsigned int a, unsigned int b)
87130591Spjd{
88130591Spjd
89130591Spjd	return ((a * b) / gcd(a, b));
90130591Spjd}
91130591Spjd
92149302Spjduint32_t
93149302Spjdbitcount32(uint32_t x)
94149302Spjd{
95149302Spjd
96149302Spjd	x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
97149302Spjd	x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
98149302Spjd	x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4);
99149302Spjd	x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8);
100149302Spjd	x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16);
101149302Spjd	return (x);
102149302Spjd}
103149302Spjd
104209388Sae/*
105209388Sae * The size of a sector is context specific (i.e. determined by the
106209388Sae * media). But when users enter a value with a SI unit, they really
107209388Sae * mean the byte-size or byte-offset and not the size or offset in
108209388Sae * sectors. We should map the byte-oriented value into a sector-oriented
109209388Sae * value when we already know the sector size in bytes. At this time
110209388Sae * we can use g_parse_lba() function. It converts user specified
111209388Sae * value into sectors with following conditions:
112209388Sae * o  Sectors size taken as argument from caller.
113209388Sae * o  When no SI unit is specified the value is in sectors.
114209388Sae * o  With an SI unit the value is in bytes.
115209388Sae * o  The 'b' suffix forces byte interpretation and the 's'
116209388Sae *    suffix forces sector interpretation.
117209388Sae *
118209388Sae * Thus:
119209388Sae * o  2 and 2s mean 2 sectors, and 2b means 2 bytes.
120209388Sae * o  4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors.
121209388Sae *
122209388Sae */
123209388Saeint
124213074Spjdg_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors)
125209388Sae{
126209388Sae	off_t number, mult, unit;
127209388Sae	char *s;
128209388Sae
129209388Sae	assert(lbastr != NULL);
130209388Sae	assert(sectorsize > 0);
131209388Sae	assert(sectors != NULL);
132209388Sae
133209388Sae	number = (off_t)strtoimax(lbastr, &s, 0);
134209392Sae	if (s == lbastr || number < 0)
135209388Sae		return (EINVAL);
136209388Sae
137209388Sae	mult = 1;
138209388Sae	unit = sectorsize;
139209388Sae	if (*s == '\0')
140209388Sae		goto done;
141209388Sae	switch (*s) {
142209388Sae	case 'e': case 'E':
143209388Sae		mult *= 1024;
144209388Sae		/* FALLTHROUGH */
145209388Sae	case 'p': case 'P':
146209388Sae		mult *= 1024;
147209388Sae		/* FALLTHROUGH */
148209388Sae	case 't': case 'T':
149209388Sae		mult *= 1024;
150209388Sae		/* FALLTHROUGH */
151209388Sae	case 'g': case 'G':
152209388Sae		mult *= 1024;
153209388Sae		/* FALLTHROUGH */
154209388Sae	case 'm': case 'M':
155209388Sae		mult *= 1024;
156209388Sae		/* FALLTHROUGH */
157209388Sae	case 'k': case 'K':
158209388Sae		mult *= 1024;
159209388Sae		break;
160209388Sae	default:
161209388Sae		goto sfx;
162209388Sae	}
163209388Sae	unit = 1;	/* bytes */
164209388Sae	s++;
165209388Sae	if (*s == '\0')
166209388Sae		goto done;
167209388Saesfx:
168209388Sae	switch (*s) {
169209388Sae	case 's': case 'S':
170209388Sae		unit = sectorsize;	/* sector */
171209388Sae		break;
172209388Sae	case 'b': case 'B':
173209388Sae		unit = 1;		/* bytes */
174209388Sae		break;
175209388Sae	default:
176209388Sae		return (EINVAL);
177209388Sae	}
178209388Sae	s++;
179209388Sae	if (*s != '\0')
180209388Sae		return (EINVAL);
181209388Saedone:
182209392Sae	if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number)
183209388Sae		return (ERANGE);
184209388Sae	number *= mult * unit;
185209388Sae	if (number % sectorsize)
186209388Sae		return (EINVAL);
187209388Sae	number /= sectorsize;
188209388Sae	*sectors = number;
189209388Sae	return (0);
190209388Sae}
191209388Sae
192130591Spjdoff_t
193130591Spjdg_get_mediasize(const char *name)
194130591Spjd{
195130591Spjd	off_t mediasize;
196130591Spjd	int fd;
197130591Spjd
198213074Spjd	fd = g_open(name, 0);
199130591Spjd	if (fd == -1)
200130591Spjd		return (0);
201213074Spjd	mediasize = g_mediasize(fd);
202213074Spjd	if (mediasize == -1)
203213074Spjd		mediasize = 0;
204213074Spjd	(void)g_close(fd);
205130591Spjd	return (mediasize);
206130591Spjd}
207130591Spjd
208213074Spjdunsigned int
209130591Spjdg_get_sectorsize(const char *name)
210130591Spjd{
211213074Spjd	ssize_t sectorsize;
212130591Spjd	int fd;
213130591Spjd
214213074Spjd	fd = g_open(name, 0);
215130591Spjd	if (fd == -1)
216130591Spjd		return (0);
217213074Spjd	sectorsize = g_sectorsize(fd);
218213074Spjd	if (sectorsize == -1)
219213074Spjd		sectorsize = 0;
220213074Spjd	(void)g_close(fd);
221213074Spjd	return ((unsigned int)sectorsize);
222130591Spjd}
223130591Spjd
224129470Spjdint
225213074Spjdg_metadata_read(const char *name, unsigned char *md, size_t size,
226213074Spjd    const char *magic)
227131603Spjd{
228131603Spjd	struct std_metadata stdmd;
229213074Spjd	unsigned char *sector;
230213074Spjd	ssize_t sectorsize;
231131603Spjd	off_t mediasize;
232131603Spjd	int error, fd;
233131603Spjd
234131603Spjd	sector = NULL;
235131603Spjd	error = 0;
236131603Spjd
237213074Spjd	fd = g_open(name, 0);
238131603Spjd	if (fd == -1)
239131603Spjd		return (errno);
240213074Spjd	mediasize = g_mediasize(fd);
241213074Spjd	if (mediasize == -1) {
242131603Spjd		error = errno;
243131603Spjd		goto out;
244131603Spjd	}
245213074Spjd	sectorsize = g_sectorsize(fd);
246213074Spjd	if (sectorsize == -1) {
247131603Spjd		error = errno;
248131603Spjd		goto out;
249131603Spjd	}
250213074Spjd	assert(sectorsize >= (ssize_t)size);
251131603Spjd	sector = malloc(sectorsize);
252131603Spjd	if (sector == NULL) {
253131603Spjd		error = ENOMEM;
254131603Spjd		goto out;
255131603Spjd	}
256131603Spjd	if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
257213074Spjd	    sectorsize) {
258131603Spjd		error = errno;
259131603Spjd		goto out;
260131603Spjd	}
261131603Spjd	if (magic != NULL) {
262131603Spjd		std_metadata_decode(sector, &stdmd);
263131603Spjd		if (strcmp(stdmd.md_magic, magic) != 0) {
264131603Spjd			error = EINVAL;
265131603Spjd			goto out;
266131603Spjd		}
267131603Spjd	}
268131603Spjd	bcopy(sector, md, size);
269131603Spjdout:
270131603Spjd	if (sector != NULL)
271131603Spjd		free(sector);
272213074Spjd	g_close(fd);
273131603Spjd	return (error);
274131603Spjd}
275131603Spjd
276330726Sasomers/*
277330726Sasomers * Actually write the GEOM label to the provider
278330726Sasomers *
279330726Sasomers * @param name	GEOM provider's name (ie "ada0")
280330726Sasomers * @param md	Pointer to the label data to write
281330726Sasomers * @param size	Size of the data pointed to by md
282330726Sasomers */
283131603Spjdint
284213074Spjdg_metadata_store(const char *name, const unsigned char *md, size_t size)
285129470Spjd{
286213074Spjd	unsigned char *sector;
287213074Spjd	ssize_t sectorsize;
288129470Spjd	off_t mediasize;
289129470Spjd	int error, fd;
290129470Spjd
291129470Spjd	sector = NULL;
292129470Spjd	error = 0;
293129470Spjd
294213074Spjd	fd = g_open(name, 1);
295129470Spjd	if (fd == -1)
296129470Spjd		return (errno);
297213074Spjd	mediasize = g_mediasize(fd);
298213074Spjd	if (mediasize == -1) {
299129470Spjd		error = errno;
300129470Spjd		goto out;
301129470Spjd	}
302213074Spjd	sectorsize = g_sectorsize(fd);
303213074Spjd	if (sectorsize == -1) {
304129470Spjd		error = errno;
305129470Spjd		goto out;
306129470Spjd	}
307213074Spjd	assert(sectorsize >= (ssize_t)size);
308129470Spjd	sector = malloc(sectorsize);
309129470Spjd	if (sector == NULL) {
310129470Spjd		error = ENOMEM;
311129470Spjd		goto out;
312129470Spjd	}
313129470Spjd	bcopy(md, sector, size);
314330726Sasomers	bzero(sector + size, sectorsize - size);
315129470Spjd	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
316213074Spjd	    sectorsize) {
317129470Spjd		error = errno;
318129470Spjd		goto out;
319129470Spjd	}
320213074Spjd	(void)g_flush(fd);
321129470Spjdout:
322129470Spjd	if (sector != NULL)
323129470Spjd		free(sector);
324213074Spjd	(void)g_close(fd);
325129470Spjd	return (error);
326129470Spjd}
327129470Spjd
328129470Spjdint
329129470Spjdg_metadata_clear(const char *name, const char *magic)
330129470Spjd{
331129470Spjd	struct std_metadata md;
332213074Spjd	unsigned char *sector;
333213074Spjd	ssize_t sectorsize;
334129470Spjd	off_t mediasize;
335129470Spjd	int error, fd;
336129470Spjd
337129470Spjd	sector = NULL;
338129470Spjd	error = 0;
339129470Spjd
340213074Spjd	fd = g_open(name, 1);
341129470Spjd	if (fd == -1)
342129470Spjd		return (errno);
343213074Spjd	mediasize = g_mediasize(fd);
344130591Spjd	if (mediasize == 0) {
345129470Spjd		error = errno;
346129470Spjd		goto out;
347129470Spjd	}
348213074Spjd	sectorsize = g_sectorsize(fd);
349317440Sasomers	if (sectorsize <= 0) {
350129470Spjd		error = errno;
351129470Spjd		goto out;
352129470Spjd	}
353129470Spjd	sector = malloc(sectorsize);
354129470Spjd	if (sector == NULL) {
355129470Spjd		error = ENOMEM;
356129470Spjd		goto out;
357129470Spjd	}
358129470Spjd	if (magic != NULL) {
359129470Spjd		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
360213074Spjd		    sectorsize) {
361129470Spjd			error = errno;
362129470Spjd			goto out;
363129470Spjd		}
364129470Spjd		std_metadata_decode(sector, &md);
365129470Spjd		if (strcmp(md.md_magic, magic) != 0) {
366129470Spjd			error = EINVAL;
367129470Spjd			goto out;
368129470Spjd		}
369129470Spjd	}
370129470Spjd	bzero(sector, sectorsize);
371129470Spjd	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
372213074Spjd	    sectorsize) {
373129470Spjd		error = errno;
374129470Spjd		goto out;
375129470Spjd	}
376213074Spjd	(void)g_flush(fd);
377129470Spjdout:
378317440Sasomers	free(sector);
379213074Spjd	g_close(fd);
380129470Spjd	return (error);
381129470Spjd}
382129470Spjd
383129470Spjd/*
384129470Spjd * Set an error message, if one does not already exist.
385129470Spjd */
386129470Spjdvoid
387129470Spjdgctl_error(struct gctl_req *req, const char *error, ...)
388129470Spjd{
389129470Spjd	va_list ap;
390129470Spjd
391226718Spjd	if (req != NULL && req->error != NULL)
392129470Spjd		return;
393129470Spjd	va_start(ap, error);
394226718Spjd	if (req != NULL) {
395226718Spjd		vasprintf(&req->error, error, ap);
396226718Spjd	} else {
397226718Spjd		vfprintf(stderr, error, ap);
398226718Spjd		fprintf(stderr, "\n");
399226718Spjd	}
400129470Spjd	va_end(ap);
401129470Spjd}
402129470Spjd
403153190Spjdstatic void *
404153190Spjdgctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
405129470Spjd{
406153190Spjd	struct gctl_req_arg *argp;
407153190Spjd	char param[256];
408213074Spjd	unsigned int i;
409153190Spjd	void *p;
410129470Spjd
411153190Spjd	vsnprintf(param, sizeof(param), pfmt, ap);
412129470Spjd	for (i = 0; i < req->narg; i++) {
413153190Spjd		argp = &req->arg[i];
414153190Spjd		if (strcmp(param, argp->name))
415129470Spjd			continue;
416153190Spjd		if (!(argp->flag & GCTL_PARAM_RD))
417129470Spjd			continue;
418153190Spjd		p = argp->value;
419153190Spjd		if (len == 0) {
420153190Spjd			/* We are looking for a string. */
421153190Spjd			if (argp->len < 1) {
422153190Spjd				fprintf(stderr, "No length argument (%s).\n",
423153190Spjd				    param);
424153190Spjd				abort();
425153190Spjd			}
426153190Spjd			if (((char *)p)[argp->len - 1] != '\0') {
427153190Spjd				fprintf(stderr, "Unterminated argument (%s).\n",
428153190Spjd				    param);
429153190Spjd				abort();
430153190Spjd			}
431153190Spjd		} else if ((int)len != argp->len) {
432153190Spjd			fprintf(stderr, "Wrong length %s argument.\n", param);
433153190Spjd			abort();
434153190Spjd		}
435129470Spjd		return (p);
436129470Spjd	}
437153190Spjd	fprintf(stderr, "No such argument (%s).\n", param);
438153190Spjd	abort();
439129470Spjd}
440129470Spjd
441153190Spjdint
442153190Spjdgctl_get_int(struct gctl_req *req, const char *pfmt, ...)
443129470Spjd{
444153190Spjd	int *p;
445153190Spjd	va_list ap;
446129470Spjd
447153190Spjd	va_start(ap, pfmt);
448153190Spjd	p = gctl_get_param(req, sizeof(int), pfmt, ap);
449153190Spjd	va_end(ap);
450153190Spjd	return (*p);
451129470Spjd}
452129470Spjd
453153190Spjdintmax_t
454153190Spjdgctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
455129470Spjd{
456153190Spjd	intmax_t *p;
457153190Spjd	va_list ap;
458129470Spjd
459153190Spjd	va_start(ap, pfmt);
460153190Spjd	p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
461153190Spjd	va_end(ap);
462153190Spjd	return (*p);
463153190Spjd}
464153190Spjd
465153190Spjdconst char *
466153190Spjdgctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
467153190Spjd{
468153190Spjd	const char *p;
469153190Spjd	va_list ap;
470153190Spjd
471153190Spjd	va_start(ap, pfmt);
472153190Spjd	p = gctl_get_param(req, 0, pfmt, ap);
473153190Spjd	va_end(ap);
474129470Spjd	return (p);
475129470Spjd}
476166215Spjd
477166215Spjdint
478166215Spjdgctl_change_param(struct gctl_req *req, const char *name, int len,
479166215Spjd    const void *value)
480166215Spjd{
481166215Spjd	struct gctl_req_arg *ap;
482213074Spjd	unsigned int i;
483166215Spjd
484166215Spjd	if (req == NULL || req->error != NULL)
485166215Spjd		return (EDOOFUS);
486166215Spjd	for (i = 0; i < req->narg; i++) {
487166215Spjd		ap = &req->arg[i];
488166215Spjd		if (strcmp(ap->name, name) != 0)
489166215Spjd			continue;
490166215Spjd		ap->value = __DECONST(void *, value);
491166215Spjd		if (len >= 0) {
492166215Spjd			ap->flag &= ~GCTL_PARAM_ASCII;
493166215Spjd			ap->len = len;
494166215Spjd		} else if (len < 0) {
495166215Spjd			ap->flag |= GCTL_PARAM_ASCII;
496166215Spjd			ap->len = strlen(value) + 1;
497166215Spjd		}
498166215Spjd		return (0);
499166215Spjd	}
500166215Spjd	return (ENOENT);
501166215Spjd}
502179628Smarcel
503179628Smarcelint
504179628Smarcelgctl_delete_param(struct gctl_req *req, const char *name)
505179628Smarcel{
506179628Smarcel	struct gctl_req_arg *ap;
507179628Smarcel	unsigned int i;
508179628Smarcel
509179628Smarcel	if (req == NULL || req->error != NULL)
510179628Smarcel		return (EDOOFUS);
511179628Smarcel
512179628Smarcel	i = 0;
513179628Smarcel	while (i < req->narg) {
514179628Smarcel		ap = &req->arg[i];
515179628Smarcel		if (strcmp(ap->name, name) == 0)
516179628Smarcel			break;
517179628Smarcel		i++;
518179628Smarcel	}
519179628Smarcel	if (i == req->narg)
520179628Smarcel		return (ENOENT);
521179628Smarcel
522208886Sae	free(ap->name);
523179628Smarcel	req->narg--;
524179628Smarcel	while (i < req->narg) {
525179628Smarcel		req->arg[i] = req->arg[i + 1];
526179628Smarcel		i++;
527179628Smarcel	}
528179628Smarcel	return (0);
529179628Smarcel}
530179628Smarcel
531179628Smarcelint
532179628Smarcelgctl_has_param(struct gctl_req *req, const char *name)
533179628Smarcel{
534179628Smarcel	struct gctl_req_arg *ap;
535179628Smarcel	unsigned int i;
536179628Smarcel
537179628Smarcel	if (req == NULL || req->error != NULL)
538179628Smarcel		return (0);
539179628Smarcel
540179628Smarcel	for (i = 0; i < req->narg; i++) {
541179628Smarcel		ap = &req->arg[i];
542179628Smarcel		if (strcmp(ap->name, name) == 0)
543179628Smarcel			return (1);
544179628Smarcel	}
545179628Smarcel	return (0);
546179628Smarcel}
547