1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <assert.h> 27 #include <fcntl.h> 28 #include <poll.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <zlib.h> 33 #include <sys/spa.h> 34 #include <sys/stat.h> 35 #include <sys/processor.h> 36 #include <sys/zfs_context.h> 37 #include <sys/zmod.h> 38 #include <sys/utsname.h> 39 #include <sys/systeminfo.h> 40 41 /* 42 * Emulation of kernel services in userland. 43 */ 44 45 uint64_t physmem; 46 vnode_t *rootdir = (vnode_t *)0xabcd1234; 47 char hw_serial[HW_HOSTID_LEN]; 48 49 struct utsname utsname = { 50 "userland", "libzpool", "1", "1", "na" 51 }; 52 53 /* this only exists to have its address taken */ 54 struct proc p0; 55 56 /* 57 * ========================================================================= 58 * threads 59 * ========================================================================= 60 */ 61 /*ARGSUSED*/ 62 kthread_t * 63 zk_thread_create(void (*func)(), void *arg) 64 { 65 thread_t tid; 66 67 VERIFY(thr_create(0, 0, (void *(*)(void *))func, arg, THR_DETACHED, 68 &tid) == 0); 69 70 return ((void *)(uintptr_t)tid); 71 } 72 73 /* 74 * ========================================================================= 75 * kstats 76 * ========================================================================= 77 */ 78 /*ARGSUSED*/ 79 kstat_t * 80 kstat_create(char *module, int instance, char *name, char *class, 81 uchar_t type, ulong_t ndata, uchar_t ks_flag) 82 { 83 return (NULL); 84 } 85 86 /*ARGSUSED*/ 87 void 88 kstat_install(kstat_t *ksp) 89 {} 90 91 /*ARGSUSED*/ 92 void 93 kstat_delete(kstat_t *ksp) 94 {} 95 96 /* 97 * ========================================================================= 98 * mutexes 99 * ========================================================================= 100 */ 101 void 102 zmutex_init(kmutex_t *mp) 103 { 104 mp->m_owner = NULL; 105 mp->initialized = B_TRUE; 106 (void) _mutex_init(&mp->m_lock, USYNC_THREAD, NULL); 107 } 108 109 void 110 zmutex_destroy(kmutex_t *mp) 111 { 112 ASSERT(mp->initialized == B_TRUE); 113 ASSERT(mp->m_owner == NULL); 114 (void) _mutex_destroy(&(mp)->m_lock); 115 mp->m_owner = (void *)-1UL; 116 mp->initialized = B_FALSE; 117 } 118 119 void 120 mutex_enter(kmutex_t *mp) 121 { 122 ASSERT(mp->initialized == B_TRUE); 123 ASSERT(mp->m_owner != (void *)-1UL); 124 ASSERT(mp->m_owner != curthread); 125 VERIFY(mutex_lock(&mp->m_lock) == 0); 126 ASSERT(mp->m_owner == NULL); 127 mp->m_owner = curthread; 128 } 129 130 int 131 mutex_tryenter(kmutex_t *mp) 132 { 133 ASSERT(mp->initialized == B_TRUE); 134 ASSERT(mp->m_owner != (void *)-1UL); 135 if (0 == mutex_trylock(&mp->m_lock)) { 136 ASSERT(mp->m_owner == NULL); 137 mp->m_owner = curthread; 138 return (1); 139 } else { 140 return (0); 141 } 142 } 143 144 void 145 mutex_exit(kmutex_t *mp) 146 { 147 ASSERT(mp->initialized == B_TRUE); 148 ASSERT(mutex_owner(mp) == curthread); 149 mp->m_owner = NULL; 150 VERIFY(mutex_unlock(&mp->m_lock) == 0); 151 } 152 153 void * 154 mutex_owner(kmutex_t *mp) 155 { 156 ASSERT(mp->initialized == B_TRUE); 157 return (mp->m_owner); 158 } 159 160 /* 161 * ========================================================================= 162 * rwlocks 163 * ========================================================================= 164 */ 165 /*ARGSUSED*/ 166 void 167 rw_init(krwlock_t *rwlp, char *name, int type, void *arg) 168 { 169 rwlock_init(&rwlp->rw_lock, USYNC_THREAD, NULL); 170 rwlp->rw_owner = NULL; 171 rwlp->initialized = B_TRUE; 172 } 173 174 void 175 rw_destroy(krwlock_t *rwlp) 176 { 177 rwlock_destroy(&rwlp->rw_lock); 178 rwlp->rw_owner = (void *)-1UL; 179 rwlp->initialized = B_FALSE; 180 } 181 182 void 183 rw_enter(krwlock_t *rwlp, krw_t rw) 184 { 185 ASSERT(!RW_LOCK_HELD(rwlp)); 186 ASSERT(rwlp->initialized == B_TRUE); 187 ASSERT(rwlp->rw_owner != (void *)-1UL); 188 ASSERT(rwlp->rw_owner != curthread); 189 190 if (rw == RW_READER) 191 VERIFY(rw_rdlock(&rwlp->rw_lock) == 0); 192 else 193 VERIFY(rw_wrlock(&rwlp->rw_lock) == 0); 194 195 rwlp->rw_owner = curthread; 196 } 197 198 void 199 rw_exit(krwlock_t *rwlp) 200 { 201 ASSERT(rwlp->initialized == B_TRUE); 202 ASSERT(rwlp->rw_owner != (void *)-1UL); 203 204 rwlp->rw_owner = NULL; 205 VERIFY(rw_unlock(&rwlp->rw_lock) == 0); 206 } 207 208 int 209 rw_tryenter(krwlock_t *rwlp, krw_t rw) 210 { 211 int rv; 212 213 ASSERT(rwlp->initialized == B_TRUE); 214 ASSERT(rwlp->rw_owner != (void *)-1UL); 215 216 if (rw == RW_READER) 217 rv = rw_tryrdlock(&rwlp->rw_lock); 218 else 219 rv = rw_trywrlock(&rwlp->rw_lock); 220 221 if (rv == 0) { 222 rwlp->rw_owner = curthread; 223 return (1); 224 } 225 226 return (0); 227 } 228 229 /*ARGSUSED*/ 230 int 231 rw_tryupgrade(krwlock_t *rwlp) 232 { 233 ASSERT(rwlp->initialized == B_TRUE); 234 ASSERT(rwlp->rw_owner != (void *)-1UL); 235 236 return (0); 237 } 238 239 /* 240 * ========================================================================= 241 * condition variables 242 * ========================================================================= 243 */ 244 /*ARGSUSED*/ 245 void 246 cv_init(kcondvar_t *cv, char *name, int type, void *arg) 247 { 248 VERIFY(cond_init(cv, type, NULL) == 0); 249 } 250 251 void 252 cv_destroy(kcondvar_t *cv) 253 { 254 VERIFY(cond_destroy(cv) == 0); 255 } 256 257 void 258 cv_wait(kcondvar_t *cv, kmutex_t *mp) 259 { 260 ASSERT(mutex_owner(mp) == curthread); 261 mp->m_owner = NULL; 262 int ret = cond_wait(cv, &mp->m_lock); 263 VERIFY(ret == 0 || ret == EINTR); 264 mp->m_owner = curthread; 265 } 266 267 clock_t 268 cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime) 269 { 270 int error; 271 timestruc_t ts; 272 clock_t delta; 273 274 top: 275 delta = abstime - ddi_get_lbolt(); 276 if (delta <= 0) 277 return (-1); 278 279 ts.tv_sec = delta / hz; 280 ts.tv_nsec = (delta % hz) * (NANOSEC / hz); 281 282 ASSERT(mutex_owner(mp) == curthread); 283 mp->m_owner = NULL; 284 error = cond_reltimedwait(cv, &mp->m_lock, &ts); 285 mp->m_owner = curthread; 286 287 if (error == ETIME) 288 return (-1); 289 290 if (error == EINTR) 291 goto top; 292 293 ASSERT(error == 0); 294 295 return (1); 296 } 297 298 void 299 cv_signal(kcondvar_t *cv) 300 { 301 VERIFY(cond_signal(cv) == 0); 302 } 303 304 void 305 cv_broadcast(kcondvar_t *cv) 306 { 307 VERIFY(cond_broadcast(cv) == 0); 308 } 309 310 /* 311 * ========================================================================= 312 * vnode operations 313 * ========================================================================= 314 */ 315 /* 316 * Note: for the xxxat() versions of these functions, we assume that the 317 * starting vp is always rootdir (which is true for spa_directory.c, the only 318 * ZFS consumer of these interfaces). We assert this is true, and then emulate 319 * them by adding '/' in front of the path. 320 */ 321 322 /*ARGSUSED*/ 323 int 324 vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3) 325 { 326 int fd; 327 vnode_t *vp; 328 int old_umask; 329 char realpath[MAXPATHLEN]; 330 struct stat64 st; 331 332 /* 333 * If we're accessing a real disk from userland, we need to use 334 * the character interface to avoid caching. This is particularly 335 * important if we're trying to look at a real in-kernel storage 336 * pool from userland, e.g. via zdb, because otherwise we won't 337 * see the changes occurring under the segmap cache. 338 * On the other hand, the stupid character device returns zero 339 * for its size. So -- gag -- we open the block device to get 340 * its size, and remember it for subsequent VOP_GETATTR(). 341 */ 342 if (strncmp(path, "/dev/", 5) == 0) { 343 char *dsk; 344 fd = open64(path, O_RDONLY); 345 if (fd == -1) 346 return (errno); 347 if (fstat64(fd, &st) == -1) { 348 close(fd); 349 return (errno); 350 } 351 close(fd); 352 (void) sprintf(realpath, "%s", path); 353 dsk = strstr(path, "/dsk/"); 354 if (dsk != NULL) 355 (void) sprintf(realpath + (dsk - path) + 1, "r%s", 356 dsk + 1); 357 } else { 358 (void) sprintf(realpath, "%s", path); 359 if (!(flags & FCREAT) && stat64(realpath, &st) == -1) 360 return (errno); 361 } 362 363 if (flags & FCREAT) 364 old_umask = umask(0); 365 366 /* 367 * The construct 'flags - FREAD' conveniently maps combinations of 368 * FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR. 369 */ 370 fd = open64(realpath, flags - FREAD, mode); 371 372 if (flags & FCREAT) 373 (void) umask(old_umask); 374 375 if (fd == -1) 376 return (errno); 377 378 if (fstat64(fd, &st) == -1) { 379 close(fd); 380 return (errno); 381 } 382 383 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 384 385 *vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL); 386 387 vp->v_fd = fd; 388 vp->v_size = st.st_size; 389 vp->v_path = spa_strdup(path); 390 391 return (0); 392 } 393 394 /*ARGSUSED*/ 395 int 396 vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, 397 int x3, vnode_t *startvp, int fd) 398 { 399 char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL); 400 int ret; 401 402 ASSERT(startvp == rootdir); 403 (void) sprintf(realpath, "/%s", path); 404 405 /* fd ignored for now, need if want to simulate nbmand support */ 406 ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3); 407 408 umem_free(realpath, strlen(path) + 2); 409 410 return (ret); 411 } 412 413 /*ARGSUSED*/ 414 int 415 vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset, 416 int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp) 417 { 418 ssize_t iolen, split; 419 420 if (uio == UIO_READ) { 421 iolen = pread64(vp->v_fd, addr, len, offset); 422 } else { 423 /* 424 * To simulate partial disk writes, we split writes into two 425 * system calls so that the process can be killed in between. 426 */ 427 split = (len > 0 ? rand() % len : 0); 428 iolen = pwrite64(vp->v_fd, addr, split, offset); 429 iolen += pwrite64(vp->v_fd, (char *)addr + split, 430 len - split, offset + split); 431 } 432 433 if (iolen == -1) 434 return (errno); 435 if (residp) 436 *residp = len - iolen; 437 else if (iolen != len) 438 return (EIO); 439 return (0); 440 } 441 442 void 443 vn_close(vnode_t *vp) 444 { 445 close(vp->v_fd); 446 spa_strfree(vp->v_path); 447 umem_free(vp, sizeof (vnode_t)); 448 } 449 450 /* 451 * At a minimum we need to update the size since vdev_reopen() 452 * will no longer call vn_openat(). 453 */ 454 int 455 fop_getattr(vnode_t *vp, vattr_t *vap) 456 { 457 struct stat64 st; 458 459 if (fstat64(vp->v_fd, &st) == -1) { 460 close(vp->v_fd); 461 return (errno); 462 } 463 464 vap->va_size = st.st_size; 465 return (0); 466 } 467 468 #ifdef ZFS_DEBUG 469 470 /* 471 * ========================================================================= 472 * Figure out which debugging statements to print 473 * ========================================================================= 474 */ 475 476 static char *dprintf_string; 477 static int dprintf_print_all; 478 479 int 480 dprintf_find_string(const char *string) 481 { 482 char *tmp_str = dprintf_string; 483 int len = strlen(string); 484 485 /* 486 * Find out if this is a string we want to print. 487 * String format: file1.c,function_name1,file2.c,file3.c 488 */ 489 490 while (tmp_str != NULL) { 491 if (strncmp(tmp_str, string, len) == 0 && 492 (tmp_str[len] == ',' || tmp_str[len] == '\0')) 493 return (1); 494 tmp_str = strchr(tmp_str, ','); 495 if (tmp_str != NULL) 496 tmp_str++; /* Get rid of , */ 497 } 498 return (0); 499 } 500 501 void 502 dprintf_setup(int *argc, char **argv) 503 { 504 int i, j; 505 506 /* 507 * Debugging can be specified two ways: by setting the 508 * environment variable ZFS_DEBUG, or by including a 509 * "debug=..." argument on the command line. The command 510 * line setting overrides the environment variable. 511 */ 512 513 for (i = 1; i < *argc; i++) { 514 int len = strlen("debug="); 515 /* First look for a command line argument */ 516 if (strncmp("debug=", argv[i], len) == 0) { 517 dprintf_string = argv[i] + len; 518 /* Remove from args */ 519 for (j = i; j < *argc; j++) 520 argv[j] = argv[j+1]; 521 argv[j] = NULL; 522 (*argc)--; 523 } 524 } 525 526 if (dprintf_string == NULL) { 527 /* Look for ZFS_DEBUG environment variable */ 528 dprintf_string = getenv("ZFS_DEBUG"); 529 } 530 531 /* 532 * Are we just turning on all debugging? 533 */ 534 if (dprintf_find_string("on")) 535 dprintf_print_all = 1; 536 } 537 538 /* 539 * ========================================================================= 540 * debug printfs 541 * ========================================================================= 542 */ 543 void 544 __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 545 { 546 const char *newfile; 547 va_list adx; 548 549 /* 550 * Get rid of annoying "../common/" prefix to filename. 551 */ 552 newfile = strrchr(file, '/'); 553 if (newfile != NULL) { 554 newfile = newfile + 1; /* Get rid of leading / */ 555 } else { 556 newfile = file; 557 } 558 559 if (dprintf_print_all || 560 dprintf_find_string(newfile) || 561 dprintf_find_string(func)) { 562 /* Print out just the function name if requested */ 563 flockfile(stdout); 564 if (dprintf_find_string("pid")) 565 (void) printf("%d ", getpid()); 566 if (dprintf_find_string("tid")) 567 (void) printf("%u ", thr_self()); 568 if (dprintf_find_string("cpu")) 569 (void) printf("%u ", getcpuid()); 570 if (dprintf_find_string("time")) 571 (void) printf("%llu ", gethrtime()); 572 if (dprintf_find_string("long")) 573 (void) printf("%s, line %d: ", newfile, line); 574 (void) printf("%s: ", func); 575 va_start(adx, fmt); 576 (void) vprintf(fmt, adx); 577 va_end(adx); 578 funlockfile(stdout); 579 } 580 } 581 582 #endif /* ZFS_DEBUG */ 583 584 /* 585 * ========================================================================= 586 * cmn_err() and panic() 587 * ========================================================================= 588 */ 589 static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" }; 590 static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" }; 591 592 void 593 vpanic(const char *fmt, va_list adx) 594 { 595 (void) fprintf(stderr, "error: "); 596 (void) vfprintf(stderr, fmt, adx); 597 (void) fprintf(stderr, "\n"); 598 599 abort(); /* think of it as a "user-level crash dump" */ 600 } 601 602 void 603 panic(const char *fmt, ...) 604 { 605 va_list adx; 606 607 va_start(adx, fmt); 608 vpanic(fmt, adx); 609 va_end(adx); 610 } 611 612 void 613 vcmn_err(int ce, const char *fmt, va_list adx) 614 { 615 if (ce == CE_PANIC) 616 vpanic(fmt, adx); 617 if (ce != CE_NOTE) { /* suppress noise in userland stress testing */ 618 (void) fprintf(stderr, "%s", ce_prefix[ce]); 619 (void) vfprintf(stderr, fmt, adx); 620 (void) fprintf(stderr, "%s", ce_suffix[ce]); 621 } 622 } 623 624 /*PRINTFLIKE2*/ 625 void 626 cmn_err(int ce, const char *fmt, ...) 627 { 628 va_list adx; 629 630 va_start(adx, fmt); 631 vcmn_err(ce, fmt, adx); 632 va_end(adx); 633 } 634 635 /* 636 * ========================================================================= 637 * kobj interfaces 638 * ========================================================================= 639 */ 640 struct _buf * 641 kobj_open_file(char *name) 642 { 643 struct _buf *file; 644 vnode_t *vp; 645 646 /* set vp as the _fd field of the file */ 647 if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir, 648 -1) != 0) 649 return ((void *)-1UL); 650 651 file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL); 652 file->_fd = (intptr_t)vp; 653 return (file); 654 } 655 656 int 657 kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off) 658 { 659 ssize_t resid; 660 661 vn_rdwr(UIO_READ, (vnode_t *)file->_fd, buf, size, (offset_t)off, 662 UIO_SYSSPACE, 0, 0, 0, &resid); 663 664 return (size - resid); 665 } 666 667 void 668 kobj_close_file(struct _buf *file) 669 { 670 vn_close((vnode_t *)file->_fd); 671 umem_free(file, sizeof (struct _buf)); 672 } 673 674 int 675 kobj_get_filesize(struct _buf *file, uint64_t *size) 676 { 677 struct stat64 st; 678 vnode_t *vp = (vnode_t *)file->_fd; 679 680 if (fstat64(vp->v_fd, &st) == -1) { 681 vn_close(vp); 682 return (errno); 683 } 684 *size = st.st_size; 685 return (0); 686 } 687 688 /* 689 * ========================================================================= 690 * misc routines 691 * ========================================================================= 692 */ 693 694 void 695 delay(clock_t ticks) 696 { 697 poll(0, 0, ticks * (1000 / hz)); 698 } 699 700 /* 701 * Find highest one bit set. 702 * Returns bit number + 1 of highest bit that is set, otherwise returns 0. 703 * High order bit is 31 (or 63 in _LP64 kernel). 704 */ 705 int 706 highbit(ulong_t i) 707 { 708 register int h = 1; 709 710 if (i == 0) 711 return (0); 712 #ifdef _LP64 713 if (i & 0xffffffff00000000ul) { 714 h += 32; i >>= 32; 715 } 716 #endif 717 if (i & 0xffff0000) { 718 h += 16; i >>= 16; 719 } 720 if (i & 0xff00) { 721 h += 8; i >>= 8; 722 } 723 if (i & 0xf0) { 724 h += 4; i >>= 4; 725 } 726 if (i & 0xc) { 727 h += 2; i >>= 2; 728 } 729 if (i & 0x2) { 730 h += 1; 731 } 732 return (h); 733 } 734 735 static int random_fd = -1, urandom_fd = -1; 736 737 static int 738 random_get_bytes_common(uint8_t *ptr, size_t len, int fd) 739 { 740 size_t resid = len; 741 ssize_t bytes; 742 743 ASSERT(fd != -1); 744 745 while (resid != 0) { 746 bytes = read(fd, ptr, resid); 747 ASSERT3S(bytes, >=, 0); 748 ptr += bytes; 749 resid -= bytes; 750 } 751 752 return (0); 753 } 754 755 int 756 random_get_bytes(uint8_t *ptr, size_t len) 757 { 758 return (random_get_bytes_common(ptr, len, random_fd)); 759 } 760 761 int 762 random_get_pseudo_bytes(uint8_t *ptr, size_t len) 763 { 764 return (random_get_bytes_common(ptr, len, urandom_fd)); 765 } 766 767 int 768 ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result) 769 { 770 char *end; 771 772 *result = strtoul(hw_serial, &end, base); 773 if (*result == 0) 774 return (errno); 775 return (0); 776 } 777 778 /* 779 * ========================================================================= 780 * kernel emulation setup & teardown 781 * ========================================================================= 782 */ 783 static int 784 umem_out_of_memory(void) 785 { 786 char errmsg[] = "out of memory -- generating core dump\n"; 787 788 write(fileno(stderr), errmsg, sizeof (errmsg)); 789 abort(); 790 return (0); 791 } 792 793 void 794 kernel_init(int mode) 795 { 796 umem_nofail_callback(umem_out_of_memory); 797 798 physmem = sysconf(_SC_PHYS_PAGES); 799 800 dprintf("physmem = %llu pages (%.2f GB)\n", physmem, 801 (double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30)); 802 803 (void) snprintf(hw_serial, sizeof (hw_serial), "%ld", 804 (mode & FWRITE) ? gethostid() : 0); 805 806 VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1); 807 VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1); 808 809 system_taskq_init(); 810 811 spa_init(mode); 812 } 813 814 void 815 kernel_fini(void) 816 { 817 spa_fini(); 818 819 system_taskq_fini(); 820 821 close(random_fd); 822 close(urandom_fd); 823 824 random_fd = -1; 825 urandom_fd = -1; 826 } 827 828 int 829 z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen) 830 { 831 int ret; 832 uLongf len = *dstlen; 833 834 if ((ret = uncompress(dst, &len, src, srclen)) == Z_OK) 835 *dstlen = (size_t)len; 836 837 return (ret); 838 } 839 840 int 841 z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen, 842 int level) 843 { 844 int ret; 845 uLongf len = *dstlen; 846 847 if ((ret = compress2(dst, &len, src, srclen, level)) == Z_OK) 848 *dstlen = (size_t)len; 849 850 return (ret); 851 } 852 853 uid_t 854 crgetuid(cred_t *cr) 855 { 856 return (0); 857 } 858 859 gid_t 860 crgetgid(cred_t *cr) 861 { 862 return (0); 863 } 864 865 int 866 crgetngroups(cred_t *cr) 867 { 868 return (0); 869 } 870 871 gid_t * 872 crgetgroups(cred_t *cr) 873 { 874 return (NULL); 875 } 876 877 int 878 zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 879 { 880 return (0); 881 } 882 883 int 884 zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 885 { 886 return (0); 887 } 888 889 int 890 zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 891 { 892 return (0); 893 } 894 895 ksiddomain_t * 896 ksid_lookupdomain(const char *dom) 897 { 898 ksiddomain_t *kd; 899 900 kd = umem_zalloc(sizeof (ksiddomain_t), UMEM_NOFAIL); 901 kd->kd_name = spa_strdup(dom); 902 return (kd); 903 } 904 905 void 906 ksiddomain_rele(ksiddomain_t *ksid) 907 { 908 spa_strfree(ksid->kd_name); 909 umem_free(ksid, sizeof (ksiddomain_t)); 910 } 911 912 /* 913 * Do not change the length of the returned string; it must be freed 914 * with strfree(). 915 */ 916 char * 917 kmem_asprintf(const char *fmt, ...) 918 { 919 int size; 920 va_list adx; 921 char *buf; 922 923 va_start(adx, fmt); 924 size = vsnprintf(NULL, 0, fmt, adx) + 1; 925 va_end(adx); 926 927 buf = kmem_alloc(size, KM_SLEEP); 928 929 va_start(adx, fmt); 930 size = vsnprintf(buf, size, fmt, adx); 931 va_end(adx); 932 933 return (buf); 934 } 935