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 */ 41 int 42 hammer2_ioctl_handle(const char *sel_path) 43 { 44 struct hammer2_ioc_version info; 45 int fd; 46 47 if (sel_path == NULL) 48 sel_path = "."; 49 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 } 56 if (ioctl(fd, HAMMER2IOC_VERSION_GET, &info) < 0) { 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 } 64 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 */ 70 void 71 hammer2_demon(void *(*func)(void *), void *arg) 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 } 141 142 const char * 143 hammer2_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 159 const char * 160 hammer2_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 171 const char * 172 hammer2_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"); 189 case HAMMER2_OBJTYPE_HARDLINK: 190 return("HARDLINK"); 191 case HAMMER2_OBJTYPE_SOCKET: 192 return("SOCKET"); 193 case HAMMER2_OBJTYPE_WHITEOUT: 194 return("WHITEOUT"); 195 default: 196 return("ILLEGAL"); 197 } 198 } 199 200 const char * 201 hammer2_pfstype_to_str(uint8_t type) 202 { 203 switch(type) { 204 case HAMMER2_PFSTYPE_NONE: 205 return("NONE"); 206 case HAMMER2_PFSTYPE_SUPROOT: 207 return("SUPROOT"); 208 case HAMMER2_PFSTYPE_DUMMY: 209 return("DUMMY"); 210 case HAMMER2_PFSTYPE_CACHE: 211 return("CACHE"); 212 case HAMMER2_PFSTYPE_SLAVE: 213 return("SLAVE"); 214 case HAMMER2_PFSTYPE_SOFT_SLAVE: 215 return("SOFT_SLAVE"); 216 case HAMMER2_PFSTYPE_SOFT_MASTER: 217 return("SOFT_MASTER"); 218 case HAMMER2_PFSTYPE_MASTER: 219 return("MASTER"); 220 default: 221 return("ILLEGAL"); 222 } 223 } 224 225 const char * 226 sizetostr(hammer2_off_t size) 227 { 228 static char buf[32]; 229 230 if (size < 1024 / 2) { 231 snprintf(buf, sizeof(buf), "%6.2f", (double)size); 232 } else if (size < 1024 * 1024 / 2) { 233 snprintf(buf, sizeof(buf), "%6.2fKB", 234 (double)size / 1024); 235 } else if (size < 1024 * 1024 * 1024LL / 2) { 236 snprintf(buf, sizeof(buf), "%6.2fMB", 237 (double)size / (1024 * 1024)); 238 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) { 239 snprintf(buf, sizeof(buf), "%6.2fGB", 240 (double)size / (1024 * 1024 * 1024LL)); 241 } else { 242 snprintf(buf, sizeof(buf), "%6.2fTB", 243 (double)size / (1024 * 1024 * 1024LL * 1024LL)); 244 } 245 return(buf); 246 } 247 248 const char * 249 counttostr(hammer2_off_t size) 250 { 251 static char buf[32]; 252 253 if (size < 1024 / 2) { 254 snprintf(buf, sizeof(buf), "%jd", 255 (intmax_t)size); 256 } else if (size < 1024 * 1024 / 2) { 257 snprintf(buf, sizeof(buf), "%jd", 258 (intmax_t)size); 259 } else if (size < 1024 * 1024 * 1024LL / 2) { 260 snprintf(buf, sizeof(buf), "%6.2fM", 261 (double)size / (1024 * 1024)); 262 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) { 263 snprintf(buf, sizeof(buf), "%6.2fG", 264 (double)(size / (1024 * 1024 * 1024LL))); 265 } else { 266 snprintf(buf, sizeof(buf), "%6.2fT", 267 (double)(size / (1024 * 1024 * 1024LL * 1024LL))); 268 } 269 return(buf); 270 } 271 272 #if 0 273 /* 274 * Allocation wrappers give us shims for possible future use 275 */ 276 void * 277 hammer2_alloc(size_t bytes) 278 { 279 void *ptr; 280 281 ptr = malloc(bytes); 282 assert(ptr); 283 bzero(ptr, bytes); 284 return (ptr); 285 } 286 287 void 288 hammer2_free(void *ptr) 289 { 290 free(ptr); 291 } 292 293 #endif 294 295 hammer2_key_t 296 dirhash(const unsigned char *name, size_t len) 297 { 298 const unsigned char *aname = name; 299 uint32_t crcx; 300 uint64_t key; 301 size_t i; 302 size_t j; 303 304 /* 305 * Filesystem version 6 or better will create directories 306 * using the ALG1 dirhash. This hash breaks the filename 307 * up into domains separated by special characters and 308 * hashes each domain independently. 309 * 310 * We also do a simple sub-sort using the first character 311 * of the filename in the top 5-bits. 312 */ 313 key = 0; 314 315 /* 316 * m32 317 */ 318 crcx = 0; 319 for (i = j = 0; i < len; ++i) { 320 if (aname[i] == '.' || 321 aname[i] == '-' || 322 aname[i] == '_' || 323 aname[i] == '~') { 324 if (i != j) 325 crcx += hammer2_icrc32(aname + j, i - j); 326 j = i + 1; 327 } 328 } 329 if (i != j) 330 crcx += hammer2_icrc32(aname + j, i - j); 331 332 /* 333 * The directory hash utilizes the top 32 bits of the 64-bit key. 334 * Bit 63 must be set to 1. 335 */ 336 crcx |= 0x80000000U; 337 key |= (uint64_t)crcx << 32; 338 339 /* 340 * l16 - crc of entire filename 341 * 342 * This crc reduces degenerate hash collision conditions 343 */ 344 crcx = hammer2_icrc32(aname, len); 345 crcx = crcx ^ (crcx << 16); 346 key |= crcx & 0xFFFF0000U; 347 348 /* 349 * Set bit 15. This allows readdir to strip bit 63 so a positive 350 * 64-bit cookie/offset can always be returned, and still guarantee 351 * that the values 0x0000-0x7FFF are available for artificial entries. 352 * ('.' and '..'). 353 */ 354 key |= 0x8000U; 355 356 return (key); 357 } 358