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_SOCKET: 190 return("SOCKET"); 191 case HAMMER2_OBJTYPE_WHITEOUT: 192 return("WHITEOUT"); 193 default: 194 return("ILLEGAL"); 195 } 196 } 197 198 const char * 199 hammer2_pfstype_to_str(uint8_t type) 200 { 201 switch(type) { 202 case HAMMER2_PFSTYPE_NONE: 203 return("NONE"); 204 case HAMMER2_PFSTYPE_SUPROOT: 205 return("SUPROOT"); 206 case HAMMER2_PFSTYPE_DUMMY: 207 return("DUMMY"); 208 case HAMMER2_PFSTYPE_CACHE: 209 return("CACHE"); 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 } 222 223 const char * 224 sizetostr(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 } 245 246 const char * 247 counttostr(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 270 #if 0 271 /* 272 * Allocation wrappers give us shims for possible future use 273 */ 274 void * 275 hammer2_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 285 void 286 hammer2_free(void *ptr) 287 { 288 free(ptr); 289 } 290 291 #endif 292 293 hammer2_key_t 294 dirhash(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 } 356