Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/cmd/zgenhostid.c
48259 views
1
// SPDX-License-Identifier: CDDL-1.0
2
/*
3
* CDDL HEADER START
4
*
5
* The contents of this file are subject to the terms of the
6
* Common Development and Distribution License (the "License").
7
* You may not use this file except in compliance with the License.
8
*
9
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10
* or https://opensource.org/licenses/CDDL-1.0.
11
* See the License for the specific language governing permissions
12
* and limitations under the License.
13
*
14
* When distributing Covered Code, include this CDDL HEADER in each
15
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16
* If applicable, add the following below this CDDL HEADER, with the
17
* fields enclosed by brackets "[]" replaced with your own identifying
18
* information: Portions Copyright [yyyy] [name of copyright owner]
19
*
20
* CDDL HEADER END
21
*/
22
23
/*
24
* Copyright (c) 2020, Georgy Yakovlev. All rights reserved.
25
*/
26
27
#include <errno.h>
28
#include <fcntl.h>
29
#include <getopt.h>
30
#include <inttypes.h>
31
#include <limits.h>
32
#include <stdint.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <sys/stat.h>
37
#include <time.h>
38
#include <unistd.h>
39
40
static __attribute__((noreturn)) void
41
usage(void)
42
{
43
(void) fprintf(stderr,
44
"usage: zgenhostid [-fh] [-o path] [value]\n\n"
45
" -f\t\t force hostid file write\n"
46
" -h\t\t print this usage and exit\n"
47
" -o <filename>\t write hostid to this file\n\n"
48
"If hostid file is not present, store a hostid in it.\n"
49
"The optional value should be an 8-digit hex number between"
50
" 1 and 2^32-1.\n"
51
"If the value is 0 or no value is provided, a random one"
52
" will be generated.\n"
53
"The value must be unique among your systems.\n");
54
exit(EXIT_FAILURE);
55
}
56
57
int
58
main(int argc, char **argv)
59
{
60
/* default file path, can be optionally set by user */
61
const char *path = "/etc/hostid";
62
/* holds converted user input or lrand48() generated value */
63
unsigned long input_i = 0;
64
65
int opt;
66
int force_fwrite = 0;
67
while ((opt = getopt_long(argc, argv, "fo:h?", 0, 0)) != -1) {
68
switch (opt) {
69
case 'f':
70
force_fwrite = 1;
71
break;
72
case 'o':
73
path = optarg;
74
break;
75
case 'h':
76
case '?':
77
usage();
78
}
79
}
80
81
char *in_s = argv[optind];
82
if (in_s != NULL) {
83
/* increment pointer by 2 if string is 0x prefixed */
84
if (strncasecmp("0x", in_s, 2) == 0) {
85
in_s += 2;
86
}
87
88
/* need to be exactly 8 characters */
89
const char *hex = "0123456789abcdefABCDEF";
90
if (strlen(in_s) != 8 || strspn(in_s, hex) != 8) {
91
fprintf(stderr, "%s\n", strerror(ERANGE));
92
usage();
93
}
94
95
input_i = strtoul(in_s, NULL, 16);
96
if (errno != 0) {
97
perror("strtoul");
98
exit(EXIT_FAILURE);
99
}
100
101
if (input_i > UINT32_MAX) {
102
fprintf(stderr, "%s\n", strerror(ERANGE));
103
usage();
104
}
105
}
106
107
struct stat fstat;
108
if (force_fwrite == 0 && stat(path, &fstat) == 0 &&
109
S_ISREG(fstat.st_mode)) {
110
fprintf(stderr, "%s: %s\n", path, strerror(EEXIST));
111
exit(EXIT_FAILURE);
112
}
113
114
/*
115
* generate if not provided by user
116
* also handle unlikely zero return from lrand48()
117
*/
118
while (input_i == 0) {
119
srand48(getpid() ^ time(NULL));
120
input_i = lrand48();
121
}
122
123
FILE *fp = fopen(path, "wb");
124
if (!fp) {
125
perror("fopen");
126
exit(EXIT_FAILURE);
127
}
128
129
/*
130
* we need just 4 bytes in native endianness
131
* not using sethostid() because it may be missing or just a stub
132
*/
133
uint32_t hostid = input_i;
134
int written = fwrite(&hostid, 1, 4, fp);
135
if (written != 4) {
136
perror("fwrite");
137
exit(EXIT_FAILURE);
138
}
139
140
fclose(fp);
141
exit(EXIT_SUCCESS);
142
}
143
144