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_ADMIN: 207 return("ADMIN"); 208 case HAMMER2_PFSTYPE_CACHE: 209 return("CACHE"); 210 case HAMMER2_PFSTYPE_COPY: 211 return("COPY"); 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 #if 0 249 /* 250 * Allocation wrappers give us shims for possible future use 251 */ 252 void * 253 hammer2_alloc(size_t bytes) 254 { 255 void *ptr; 256 257 ptr = malloc(bytes); 258 assert(ptr); 259 bzero(ptr, bytes); 260 return (ptr); 261 } 262 263 void 264 hammer2_free(void *ptr) 265 { 266 free(ptr); 267 } 268 269 #endif 270 271 hammer2_key_t 272 dirhash(const unsigned char *name, size_t len) 273 { 274 const unsigned char *aname = name; 275 uint32_t crcx; 276 uint64_t key; 277 size_t i; 278 size_t j; 279 280 /* 281 * Filesystem version 6 or better will create directories 282 * using the ALG1 dirhash. This hash breaks the filename 283 * up into domains separated by special characters and 284 * hashes each domain independently. 285 * 286 * We also do a simple sub-sort using the first character 287 * of the filename in the top 5-bits. 288 */ 289 key = 0; 290 291 /* 292 * m32 293 */ 294 crcx = 0; 295 for (i = j = 0; i < len; ++i) { 296 if (aname[i] == '.' || 297 aname[i] == '-' || 298 aname[i] == '_' || 299 aname[i] == '~') { 300 if (i != j) 301 crcx += hammer2_icrc32(aname + j, i - j); 302 j = i + 1; 303 } 304 } 305 if (i != j) 306 crcx += hammer2_icrc32(aname + j, i - j); 307 308 /* 309 * The directory hash utilizes the top 32 bits of the 64-bit key. 310 * Bit 63 must be set to 1. 311 */ 312 crcx |= 0x80000000U; 313 key |= (uint64_t)crcx << 32; 314 315 /* 316 * l16 - crc of entire filename 317 * 318 * This crc reduces degenerate hash collision conditions 319 */ 320 crcx = hammer2_icrc32(aname, len); 321 crcx = crcx ^ (crcx << 16); 322 key |= crcx & 0xFFFF0000U; 323 324 /* 325 * Set bit 15. This allows readdir to strip bit 63 so a positive 326 * 64-bit cookie/offset can always be returned, and still guarantee 327 * that the values 0x0000-0x7FFF are available for artificial entries. 328 * ('.' and '..'). 329 */ 330 key |= 0x8000U; 331 332 return (key); 333 } 334