Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/geom/misc/subr.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2004-2010 Pawel Jakub Dawidek <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/disk.h>
31
#include <sys/endian.h>
32
#include <sys/uio.h>
33
#include <errno.h>
34
#include <fcntl.h>
35
#include <paths.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <limits.h>
39
#include <inttypes.h>
40
#include <stdarg.h>
41
#include <string.h>
42
#include <strings.h>
43
#include <unistd.h>
44
#include <assert.h>
45
#include <libgeom.h>
46
47
#include "misc/subr.h"
48
49
50
struct std_metadata {
51
char md_magic[16];
52
uint32_t md_version;
53
};
54
55
static void
56
std_metadata_decode(const unsigned char *data, struct std_metadata *md)
57
{
58
59
bcopy(data, md->md_magic, sizeof(md->md_magic));
60
md->md_version = le32dec(data + 16);
61
}
62
63
/*
64
* Greatest Common Divisor.
65
*/
66
static unsigned int
67
gcd(unsigned int a, unsigned int b)
68
{
69
unsigned int c;
70
71
while (b != 0) {
72
c = a;
73
a = b;
74
b = (c % b);
75
}
76
return (a);
77
}
78
79
/*
80
* Least Common Multiple.
81
*/
82
unsigned int
83
g_lcm(unsigned int a, unsigned int b)
84
{
85
86
return ((a * b) / gcd(a, b));
87
}
88
89
uint32_t
90
bitcount32(uint32_t x)
91
{
92
93
x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
94
x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
95
x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4);
96
x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8);
97
x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16);
98
return (x);
99
}
100
101
/*
102
* The size of a sector is context specific (i.e. determined by the
103
* media). But when users enter a value with a SI unit, they really
104
* mean the byte-size or byte-offset and not the size or offset in
105
* sectors. We should map the byte-oriented value into a sector-oriented
106
* value when we already know the sector size in bytes. At this time
107
* we can use g_parse_lba() function. It converts user specified
108
* value into sectors with following conditions:
109
* o Sectors size taken as argument from caller.
110
* o When no SI unit is specified the value is in sectors.
111
* o With an SI unit the value is in bytes.
112
* o The 'b' suffix forces byte interpretation and the 's'
113
* suffix forces sector interpretation.
114
*
115
* Thus:
116
* o 2 and 2s mean 2 sectors, and 2b means 2 bytes.
117
* o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors.
118
*
119
*/
120
int
121
g_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors)
122
{
123
off_t number, mult, unit;
124
char *s;
125
126
assert(lbastr != NULL);
127
assert(sectorsize > 0);
128
assert(sectors != NULL);
129
130
number = (off_t)strtoimax(lbastr, &s, 0);
131
if (s == lbastr || number < 0)
132
return (EINVAL);
133
134
mult = 1;
135
unit = sectorsize;
136
if (*s == '\0')
137
goto done;
138
switch (*s) {
139
case 'e': case 'E':
140
mult *= 1024;
141
/* FALLTHROUGH */
142
case 'p': case 'P':
143
mult *= 1024;
144
/* FALLTHROUGH */
145
case 't': case 'T':
146
mult *= 1024;
147
/* FALLTHROUGH */
148
case 'g': case 'G':
149
mult *= 1024;
150
/* FALLTHROUGH */
151
case 'm': case 'M':
152
mult *= 1024;
153
/* FALLTHROUGH */
154
case 'k': case 'K':
155
mult *= 1024;
156
break;
157
default:
158
goto sfx;
159
}
160
unit = 1; /* bytes */
161
s++;
162
if (*s == '\0')
163
goto done;
164
sfx:
165
switch (*s) {
166
case 's': case 'S':
167
unit = sectorsize; /* sector */
168
break;
169
case 'b': case 'B':
170
unit = 1; /* bytes */
171
break;
172
default:
173
return (EINVAL);
174
}
175
s++;
176
if (*s != '\0')
177
return (EINVAL);
178
done:
179
if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number)
180
return (ERANGE);
181
number *= mult * unit;
182
if (number % sectorsize)
183
return (EINVAL);
184
number /= sectorsize;
185
*sectors = number;
186
return (0);
187
}
188
189
off_t
190
g_get_mediasize(const char *name)
191
{
192
off_t mediasize;
193
int fd;
194
195
fd = g_open(name, 0);
196
if (fd == -1)
197
return (0);
198
mediasize = g_mediasize(fd);
199
if (mediasize == -1)
200
mediasize = 0;
201
(void)g_close(fd);
202
return (mediasize);
203
}
204
205
unsigned int
206
g_get_sectorsize(const char *name)
207
{
208
ssize_t sectorsize;
209
int fd;
210
211
fd = g_open(name, 0);
212
if (fd == -1)
213
return (0);
214
sectorsize = g_sectorsize(fd);
215
if (sectorsize == -1)
216
sectorsize = 0;
217
(void)g_close(fd);
218
return ((unsigned int)sectorsize);
219
}
220
221
int
222
g_metadata_read(const char *name, unsigned char *md, size_t size,
223
const char *magic)
224
{
225
struct std_metadata stdmd;
226
unsigned char *sector;
227
ssize_t sectorsize;
228
off_t mediasize;
229
int error, fd;
230
231
sector = NULL;
232
error = 0;
233
234
fd = g_open(name, 0);
235
if (fd == -1)
236
return (errno);
237
mediasize = g_mediasize(fd);
238
if (mediasize == -1) {
239
error = errno;
240
goto out;
241
}
242
sectorsize = g_sectorsize(fd);
243
if (sectorsize == -1) {
244
error = errno;
245
goto out;
246
}
247
assert(sectorsize >= (ssize_t)size);
248
sector = malloc(sectorsize);
249
if (sector == NULL) {
250
error = ENOMEM;
251
goto out;
252
}
253
if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
254
sectorsize) {
255
error = errno;
256
goto out;
257
}
258
if (magic != NULL) {
259
std_metadata_decode(sector, &stdmd);
260
if (strcmp(stdmd.md_magic, magic) != 0) {
261
error = EINVAL;
262
goto out;
263
}
264
}
265
bcopy(sector, md, size);
266
out:
267
if (sector != NULL)
268
free(sector);
269
g_close(fd);
270
return (error);
271
}
272
273
/*
274
* Actually write the GEOM label to the provider
275
*
276
* @param name GEOM provider's name (ie "ada0")
277
* @param md Pointer to the label data to write
278
* @param size Size of the data pointed to by md
279
*/
280
int
281
g_metadata_store(const char *name, const unsigned char *md, size_t size)
282
{
283
unsigned char *sector;
284
ssize_t sectorsize;
285
off_t mediasize;
286
int error, fd;
287
288
sector = NULL;
289
error = 0;
290
291
fd = g_open(name, 1);
292
if (fd == -1)
293
return (errno);
294
mediasize = g_mediasize(fd);
295
if (mediasize == -1) {
296
error = errno;
297
goto out;
298
}
299
sectorsize = g_sectorsize(fd);
300
if (sectorsize == -1) {
301
error = errno;
302
goto out;
303
}
304
assert(sectorsize >= (ssize_t)size);
305
sector = malloc(sectorsize);
306
if (sector == NULL) {
307
error = ENOMEM;
308
goto out;
309
}
310
bcopy(md, sector, size);
311
bzero(sector + size, sectorsize - size);
312
if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
313
sectorsize) {
314
error = errno;
315
goto out;
316
}
317
(void)g_flush(fd);
318
out:
319
if (sector != NULL)
320
free(sector);
321
(void)g_close(fd);
322
return (error);
323
}
324
325
int
326
g_metadata_clear(const char *name, const char *magic)
327
{
328
struct std_metadata md;
329
unsigned char *sector;
330
ssize_t sectorsize;
331
off_t mediasize;
332
int error, fd;
333
334
sector = NULL;
335
error = 0;
336
337
fd = g_open(name, 1);
338
if (fd == -1)
339
return (errno);
340
mediasize = g_mediasize(fd);
341
if (mediasize == 0) {
342
error = errno;
343
goto out;
344
}
345
sectorsize = g_sectorsize(fd);
346
if (sectorsize <= 0) {
347
error = errno;
348
goto out;
349
}
350
sector = malloc(sectorsize);
351
if (sector == NULL) {
352
error = ENOMEM;
353
goto out;
354
}
355
if (magic != NULL) {
356
if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
357
sectorsize) {
358
error = errno;
359
goto out;
360
}
361
std_metadata_decode(sector, &md);
362
if (strcmp(md.md_magic, magic) != 0) {
363
error = EINVAL;
364
goto out;
365
}
366
}
367
bzero(sector, sectorsize);
368
if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
369
sectorsize) {
370
error = errno;
371
goto out;
372
}
373
(void)g_flush(fd);
374
out:
375
free(sector);
376
g_close(fd);
377
return (error);
378
}
379
380
/*
381
* Set an error message, if one does not already exist.
382
*/
383
void
384
gctl_error(struct gctl_req *req, const char *error, ...)
385
{
386
va_list ap;
387
388
if (req != NULL && req->error != NULL)
389
return;
390
va_start(ap, error);
391
if (req != NULL) {
392
vasprintf(&req->error, error, ap);
393
} else {
394
vfprintf(stderr, error, ap);
395
fprintf(stderr, "\n");
396
}
397
va_end(ap);
398
if (req != NULL && req->nerror == 0)
399
req->nerror = EINVAL;
400
}
401
402
static void *
403
gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
404
{
405
struct gctl_req_arg *argp;
406
char param[256];
407
unsigned int i;
408
void *p;
409
410
vsnprintf(param, sizeof(param), pfmt, ap);
411
for (i = 0; i < req->narg; i++) {
412
argp = &req->arg[i];
413
if (strcmp(param, argp->name))
414
continue;
415
if (!(argp->flag & GCTL_PARAM_RD))
416
continue;
417
p = argp->value;
418
if (len == 0) {
419
/* We are looking for a string. */
420
if (argp->len < 1) {
421
fprintf(stderr, "No length argument (%s).\n",
422
param);
423
abort();
424
}
425
if (((char *)p)[argp->len - 1] != '\0') {
426
fprintf(stderr, "Unterminated argument (%s).\n",
427
param);
428
abort();
429
}
430
} else if ((int)len != argp->len) {
431
fprintf(stderr, "Wrong length %s argument.\n", param);
432
abort();
433
}
434
return (p);
435
}
436
fprintf(stderr, "No such argument (%s).\n", param);
437
abort();
438
}
439
440
int
441
gctl_get_int(struct gctl_req *req, const char *pfmt, ...)
442
{
443
int *p;
444
va_list ap;
445
446
va_start(ap, pfmt);
447
p = gctl_get_param(req, sizeof(int), pfmt, ap);
448
va_end(ap);
449
return (*p);
450
}
451
452
intmax_t
453
gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
454
{
455
intmax_t *p;
456
va_list ap;
457
458
va_start(ap, pfmt);
459
p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
460
va_end(ap);
461
return (*p);
462
}
463
464
const char *
465
gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
466
{
467
const char *p;
468
va_list ap;
469
470
va_start(ap, pfmt);
471
p = gctl_get_param(req, 0, pfmt, ap);
472
va_end(ap);
473
return (p);
474
}
475
476
int
477
gctl_change_param(struct gctl_req *req, const char *name, int len,
478
const void *value)
479
{
480
struct gctl_req_arg *ap;
481
unsigned int i;
482
483
if (req == NULL || req->error != NULL)
484
return (EDOOFUS);
485
for (i = 0; i < req->narg; i++) {
486
ap = &req->arg[i];
487
if (strcmp(ap->name, name) != 0)
488
continue;
489
ap->value = __DECONST(void *, value);
490
if (len >= 0) {
491
ap->flag &= ~GCTL_PARAM_ASCII;
492
ap->len = len;
493
} else if (len < 0) {
494
ap->flag |= GCTL_PARAM_ASCII;
495
ap->len = strlen(value) + 1;
496
}
497
return (0);
498
}
499
return (ENOENT);
500
}
501
502
int
503
gctl_delete_param(struct gctl_req *req, const char *name)
504
{
505
struct gctl_req_arg *ap;
506
unsigned int i;
507
508
if (req == NULL || req->error != NULL)
509
return (EDOOFUS);
510
511
i = 0;
512
while (i < req->narg) {
513
ap = &req->arg[i];
514
if (strcmp(ap->name, name) == 0)
515
break;
516
i++;
517
}
518
if (i == req->narg)
519
return (ENOENT);
520
521
free(ap->name);
522
req->narg--;
523
while (i < req->narg) {
524
req->arg[i] = req->arg[i + 1];
525
i++;
526
}
527
return (0);
528
}
529
530
int
531
gctl_has_param(struct gctl_req *req, const char *name)
532
{
533
struct gctl_req_arg *ap;
534
unsigned int i;
535
536
if (req == NULL || req->error != NULL)
537
return (0);
538
539
for (i = 0; i < req->narg; i++) {
540
ap = &req->arg[i];
541
if (strcmp(ap->name, name) == 0)
542
return (1);
543
}
544
return (0);
545
}
546
547