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