efirt.9: Add missing header to the SYNOPSIS.
[dragonfly.git] / sbin / hammer2 / subs.c
CommitLineData
2910a90c
MD
1/*
2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "hammer2.h"
37
38/*
39 * Obtain a file descriptor that the caller can execute ioctl()'s on.
40 */
41int
42hammer2_ioctl_handle(const char *sel_path)
43{
44 struct hammer2_ioc_version info;
45 int fd;
46
5ba65e34
MD
47 if (sel_path == NULL)
48 sel_path = ".";
49
2910a90c
MD
50 fd = open(sel_path, O_RDONLY, 0);
51 if (fd < 0) {
52 fprintf(stderr, "hammer2: Unable to open %s: %s\n",
53 sel_path, strerror(errno));
54 return(-1);
55 }
ae183399 56 if (ioctl(fd, HAMMER2IOC_VERSION_GET, &info) < 0) {
2910a90c
MD
57 fprintf(stderr, "hammer2: '%s' is not a hammer2 filesystem\n",
58 sel_path);
59 close(fd);
60 return(-1);
61 }
62 return (fd);
63}
5ba65e34 64
9ab15106
MD
65/*
66 * Execute the specified function as a detached independent process/daemon,
67 * unless we are in debug mode. If we are in debug mode the function is
68 * executed as a pthread in the current process.
69 */
5ba65e34 70void
9ab15106 71hammer2_demon(void *(*func)(void *), void *arg)
5ba65e34
MD
72{
73 pthread_t thread = NULL;
74 pid_t pid;
75 int ttyfd;
76
77 /*
78 * Do not disconnect in debug mode
79 */
80 if (DebugOpt) {
81 pthread_create(&thread, NULL, func, arg);
82 NormalExit = 0;
83 return;
84 }
85
86 /*
87 * Otherwise disconnect us. Double-fork to get rid of the ppid
88 * association and disconnect the TTY.
89 */
90 if ((pid = fork()) < 0) {
91 fprintf(stderr, "hammer2: fork(): %s\n", strerror(errno));
92 exit(1);
93 }
94 if (pid > 0) {
95 while (waitpid(pid, NULL, 0) != pid)
96 ;
97 return; /* parent returns */
98 }
99
100 /*
101 * Get rid of the TTY/session before double-forking to finish off
102 * the ppid.
103 */
104 ttyfd = open("/dev/null", O_RDWR);
105 if (ttyfd >= 0) {
106 if (ttyfd != 0)
107 dup2(ttyfd, 0);
108 if (ttyfd != 1)
109 dup2(ttyfd, 1);
110 if (ttyfd != 2)
111 dup2(ttyfd, 2);
112 if (ttyfd > 2)
113 close(ttyfd);
114 }
115
116 ttyfd = open("/dev/tty", O_RDWR);
117 if (ttyfd >= 0) {
118 ioctl(ttyfd, TIOCNOTTY, 0);
119 close(ttyfd);
120 }
121 setsid();
122
123 /*
124 * Second fork to disconnect ppid (the original parent waits for
125 * us to exit).
126 */
127 if ((pid = fork()) < 0) {
128 _exit(2);
129 }
130 if (pid > 0)
131 _exit(0);
132
133 /*
134 * The double child
135 */
136 setsid();
137 pthread_create(&thread, NULL, func, arg);
138 pthread_exit(NULL);
139 _exit(2); /* NOT REACHED */
140}
9ab15106 141
bd878fc9
MD
142const char *
143hammer2_time64_to_str(uint64_t htime64, char **strp)
144{
145 struct tm *tp;
146 time_t t;
147
148 if (*strp) {
149 free(*strp);
150 *strp = NULL;
151 }
152 *strp = malloc(64);
153 t = htime64 / 1000000;
154 tp = localtime(&t);
155 strftime(*strp, 64, "%d-%b-%Y %H:%M:%S", tp);
156 return (*strp);
157}
158
159const char *
160hammer2_uuid_to_str(uuid_t *uuid, char **strp)
161{
162 uint32_t status;
163 if (*strp) {
164 free(*strp);
165 *strp = NULL;
166 }
167 uuid_to_string(uuid, strp, &status);
168 return (*strp);
169}
170
171const char *
172hammer2_iptype_to_str(uint8_t type)
173{
174 switch(type) {
175 case HAMMER2_OBJTYPE_UNKNOWN:
176 return("UNKNOWN");
177 case HAMMER2_OBJTYPE_DIRECTORY:
178 return("DIR");
179 case HAMMER2_OBJTYPE_REGFILE:
180 return("FILE");
181 case HAMMER2_OBJTYPE_FIFO:
182 return("FIFO");
183 case HAMMER2_OBJTYPE_CDEV:
184 return("CDEV");
185 case HAMMER2_OBJTYPE_BDEV:
186 return("BDEV");
187 case HAMMER2_OBJTYPE_SOFTLINK:
188 return("SOFTLINK");
bd878fc9
MD
189 case HAMMER2_OBJTYPE_SOCKET:
190 return("SOCKET");
191 case HAMMER2_OBJTYPE_WHITEOUT:
192 return("WHITEOUT");
193 default:
194 return("ILLEGAL");
195 }
196}
197
198const char *
199hammer2_pfstype_to_str(uint8_t type)
200{
201 switch(type) {
7750fd72 202 case HAMMER2_PFSTYPE_NONE:
bd878fc9 203 return("NONE");
b93cc2e0
MD
204 case HAMMER2_PFSTYPE_SUPROOT:
205 return("SUPROOT");
206 case HAMMER2_PFSTYPE_DUMMY:
207 return("DUMMY");
bd878fc9
MD
208 case HAMMER2_PFSTYPE_CACHE:
209 return("CACHE");
bd878fc9
MD
210 case HAMMER2_PFSTYPE_SLAVE:
211 return("SLAVE");
212 case HAMMER2_PFSTYPE_SOFT_SLAVE:
213 return("SOFT_SLAVE");
214 case HAMMER2_PFSTYPE_SOFT_MASTER:
215 return("SOFT_MASTER");
216 case HAMMER2_PFSTYPE_MASTER:
217 return("MASTER");
218 default:
219 return("ILLEGAL");
220 }
221}
ad7cf8ea
MD
222
223const char *
224sizetostr(hammer2_off_t size)
225{
226 static char buf[32];
227
228 if (size < 1024 / 2) {
229 snprintf(buf, sizeof(buf), "%6.2f", (double)size);
230 } else if (size < 1024 * 1024 / 2) {
231 snprintf(buf, sizeof(buf), "%6.2fKB",
232 (double)size / 1024);
233 } else if (size < 1024 * 1024 * 1024LL / 2) {
234 snprintf(buf, sizeof(buf), "%6.2fMB",
235 (double)size / (1024 * 1024));
236 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
237 snprintf(buf, sizeof(buf), "%6.2fGB",
238 (double)size / (1024 * 1024 * 1024LL));
239 } else {
240 snprintf(buf, sizeof(buf), "%6.2fTB",
241 (double)size / (1024 * 1024 * 1024LL * 1024LL));
242 }
243 return(buf);
244}
8c280d5d 245
8b903fd1
MD
246const char *
247counttostr(hammer2_off_t size)
248{
249 static char buf[32];
250
251 if (size < 1024 / 2) {
252 snprintf(buf, sizeof(buf), "%jd",
253 (intmax_t)size);
254 } else if (size < 1024 * 1024 / 2) {
255 snprintf(buf, sizeof(buf), "%jd",
256 (intmax_t)size);
257 } else if (size < 1024 * 1024 * 1024LL / 2) {
258 snprintf(buf, sizeof(buf), "%6.2fM",
259 (double)size / (1024 * 1024));
260 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
261 snprintf(buf, sizeof(buf), "%6.2fG",
262 (double)(size / (1024 * 1024 * 1024LL)));
263 } else {
264 snprintf(buf, sizeof(buf), "%6.2fT",
265 (double)(size / (1024 * 1024 * 1024LL * 1024LL)));
266 }
267 return(buf);
268}
269
0c3a8cd0 270#if 0
8c280d5d
MD
271/*
272 * Allocation wrappers give us shims for possible future use
273 */
274void *
275hammer2_alloc(size_t bytes)
276{
277 void *ptr;
278
279 ptr = malloc(bytes);
280 assert(ptr);
281 bzero(ptr, bytes);
282 return (ptr);
283}
284
285void
286hammer2_free(void *ptr)
287{
288 free(ptr);
289}
02454b3e 290
0c3a8cd0 291#endif
775153c2
MD
292
293hammer2_key_t
294dirhash(const unsigned char *name, size_t len)
295{
296 const unsigned char *aname = name;
297 uint32_t crcx;
298 uint64_t key;
299 size_t i;
300 size_t j;
301
302 /*
303 * Filesystem version 6 or better will create directories
304 * using the ALG1 dirhash. This hash breaks the filename
305 * up into domains separated by special characters and
306 * hashes each domain independently.
307 *
308 * We also do a simple sub-sort using the first character
309 * of the filename in the top 5-bits.
310 */
311 key = 0;
312
313 /*
314 * m32
315 */
316 crcx = 0;
317 for (i = j = 0; i < len; ++i) {
318 if (aname[i] == '.' ||
319 aname[i] == '-' ||
320 aname[i] == '_' ||
321 aname[i] == '~') {
322 if (i != j)
323 crcx += hammer2_icrc32(aname + j, i - j);
324 j = i + 1;
325 }
326 }
327 if (i != j)
328 crcx += hammer2_icrc32(aname + j, i - j);
329
330 /*
331 * The directory hash utilizes the top 32 bits of the 64-bit key.
332 * Bit 63 must be set to 1.
333 */
334 crcx |= 0x80000000U;
335 key |= (uint64_t)crcx << 32;
336
337 /*
338 * l16 - crc of entire filename
339 *
340 * This crc reduces degenerate hash collision conditions
341 */
342 crcx = hammer2_icrc32(aname, len);
343 crcx = crcx ^ (crcx << 16);
344 key |= crcx & 0xFFFF0000U;
345
346 /*
347 * Set bit 15. This allows readdir to strip bit 63 so a positive
348 * 64-bit cookie/offset can always be returned, and still guarantee
349 * that the values 0x0000-0x7FFF are available for artificial entries.
350 * ('.' and '..').
351 */
352 key |= 0x8000U;
353
354 return (key);
355}