1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * Test & debug program for the SMB client 18 * 19 * This implements a simple command reader which accepts 20 * commands to simulate system calls into the file system. 21 */ 22 23 #include <sys/types.h> 24 #include <sys/file.h> 25 #include <sys/stat.h> 26 #include <sys/mount.h> 27 #include <sys/dirent.h> 28 #include <sys/strlog.h> /* SL_NOTE */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 38 #include <sys/fs/smbfs_mount.h> 39 #include <netsmb/smb_lib.h> 40 #include <libfknsmb/common/libfknsmb.h> 41 #include <libfksmbfs/common/libfksmbfs.h> 42 43 #if _FILE_OFFSET_BITS != 64 44 #error "This calls (fake) VFS code which requires 64-bit off_t" 45 #endif 46 47 extern int list_shares(struct smb_ctx *); 48 49 #define MAXARG 10 50 51 struct cmd_tbl_ent { 52 void (*ce_func)(int, char **); 53 const char *ce_name; 54 const char *ce_argdesc; 55 }; 56 static struct cmd_tbl_ent cmd_tbl[]; 57 58 static struct smb_ctx *ctx = NULL; 59 static char *server = NULL; 60 61 static vfs_t *vfsp = NULL; 62 63 static void show_dents(vnode_t *, offset_t *, char *, int); 64 static void run_cli(void); 65 66 #define TBUFSZ 8192 67 static char tbuf[TBUFSZ]; 68 69 static void 70 fksmbcl_usage(void) 71 { 72 printf("usage: fksmbcl //user@server (like smbutil)\n"); 73 exit(1); 74 } 75 76 int 77 main(int argc, char *argv[]) 78 { 79 int error, opt; 80 81 /* 82 * Initializations 83 */ 84 nsmb_drv_load(); 85 nsmb_drv_init(); 86 fksmbfs_init(); 87 88 while ((opt = getopt(argc, argv, "dv")) != -1) { 89 switch (opt) { 90 case 'd': 91 smb_debug++; 92 break; 93 case 'v': 94 smb_verbose++; 95 break; 96 case '?': 97 fksmbcl_usage(); 98 break; 99 } 100 } 101 if (optind >= argc) 102 fksmbcl_usage(); 103 server = argv[optind]; 104 105 /* 106 * Setup the libsmbfs context 107 */ 108 error = smb_ctx_alloc(&ctx); 109 if (error) { 110 fprintf(stderr, "%s: smb_ctx_alloc failed (%d)\n", 111 argv[0], error); 112 return (1); 113 } 114 115 error = smb_ctx_scan_argv(ctx, argc, argv, 116 SMBL_SERVER, SMBL_SERVER, USE_WILDCARD); 117 if (error) { 118 fprintf(stderr, "logon: smb_ctx_scan_argv, error %d\n", error); 119 return (1); 120 } 121 error = smb_ctx_readrc(ctx); 122 if (error) { 123 fprintf(stderr, "logon: smb_ctx_readrc, error %d\n", error); 124 return (1); 125 } 126 127 /* Do smb_ctx_setshare later, and smb_ctx_resolve. */ 128 129 /* 130 * Next would be smb_ctx_get_ssn() but don't do that until 131 * the "logon" command so one can set breakpoints etc. 132 */ 133 134 /* 135 * Run the CLI 136 */ 137 run_cli(); 138 139 /* 140 * Cleanup 141 */ 142 fksmbfs_fini(); 143 nsmb_drv_fini(); 144 145 return (0); 146 } 147 148 static void 149 run_cli() 150 { 151 static char cmdbuf[100]; 152 int argc, i; 153 char *argv[MAXARG]; 154 char *cmd; 155 char *savep = NULL; 156 char *sep = " \t\n"; 157 char *prompt = NULL; 158 struct cmd_tbl_ent *ce; 159 160 if (isatty(0)) { 161 fputs("# Start with:\n" 162 "> logon [user [dom [pw]]]\n" 163 "> shares\n" 164 "> mount {share}\n\n", 165 stdout); 166 prompt = "> "; 167 } 168 169 for (;;) { 170 if (prompt) { 171 fputs(prompt, stdout); 172 fflush(stdout); 173 } 174 175 cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin); 176 if (cmd == NULL) 177 break; 178 if (cmd[0] == '#') 179 continue; 180 181 if (prompt == NULL) { 182 /* Put commands in the output too. */ 183 fprintf(stdout, "+ %s", cmdbuf); 184 } 185 186 argv[0] = strtok_r(cmd, sep, &savep); 187 if (argv[0] == NULL) 188 continue; 189 for (argc = 1; argc < MAXARG; argc++) { 190 argv[argc] = strtok_r(NULL, sep, &savep); 191 if (argv[argc] == NULL) 192 break; 193 } 194 for (i = argc; i < MAXARG; i++) 195 argv[i++] = NULL; 196 197 for (ce = cmd_tbl; ce->ce_name != NULL; ce++) 198 if (strcmp(ce->ce_name, argv[0]) == 0) 199 break; 200 if (ce->ce_name != NULL) { 201 ce->ce_func(argc, argv); 202 } else { 203 fprintf(stderr, "%s unknown command. Try help\n", 204 argv[0]); 205 } 206 } 207 } 208 209 /* 210 * Command handlers 211 */ 212 213 static void 214 do_exit(int argc, char **argv) 215 { 216 exit(0); 217 } 218 219 static void 220 do_help(int argc, char **argv) 221 { 222 struct cmd_tbl_ent *ce; 223 224 printf("Commands:\n"); 225 for (ce = cmd_tbl; ce->ce_func != NULL; ce++) 226 printf("%s %s\n", ce->ce_name, ce->ce_argdesc); 227 } 228 229 static void 230 do_logon(int argc, char **argv) 231 { 232 int error; 233 234 if (argc > 1) { 235 if (argv[1][0] == '-') { 236 smb_ctx_setuser(ctx, "", B_TRUE); 237 ctx->ct_flags |= SMBCF_NOPWD; 238 } else { 239 smb_ctx_setuser(ctx, argv[1], B_TRUE); 240 } 241 } 242 if (argc > 2) 243 smb_ctx_setdomain(ctx, argv[2], B_TRUE); 244 if (argc > 3) 245 smb_ctx_setpassword(ctx, argv[3], NULL); 246 247 /* 248 * Resolve the server address, setup derived defaults. 249 */ 250 error = smb_ctx_resolve(ctx); 251 if (error) { 252 fprintf(stderr, "logon: smb_ctx_resolve, error %d\n", error); 253 return; 254 } 255 256 /* 257 * Have server, share, etc. now. 258 * Get the logon session. 259 */ 260 again: 261 error = smb_ctx_get_ssn(ctx); 262 if (error == EAUTH) { 263 int err2; 264 err2 = smb_get_authentication(ctx); 265 if (err2 == 0) 266 goto again; 267 } 268 if (error) { 269 fprintf(stderr, "//%s: login failed, error %d\n", 270 ctx->ct_fullserver, error); 271 } 272 } 273 274 /* 275 * Drop session created by the "logon" command. 276 */ 277 static void 278 do_logoff(int argc, char **argv) 279 { 280 281 (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_RELE, NULL); 282 if (argc > 1) { 283 smb_ctx_done(ctx); 284 (void) smb_ctx_init(ctx); 285 } 286 } 287 288 /* 289 * List shares 290 */ 291 static void 292 do_shares(int argc, char **argv) 293 { 294 int error; 295 296 smb_ctx_setshare(ctx, "IPC$", USE_IPC); 297 error = smb_ctx_get_tree(ctx); 298 if (error) { 299 fprintf(stderr, "shares, tcon IPC$, error=%d\n", error); 300 return; 301 } 302 303 error = list_shares(ctx); 304 if (error) { 305 fprintf(stderr, "shares, enum, error=%d\n", error); 306 } 307 308 (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL); 309 } 310 311 char mnt_opt_buf[MAX_MNTOPT_STR]; 312 char mnt_resource[MAXPATHLEN]; 313 314 /* 315 * Minimal excerpt from vfs.c:domount() 316 */ 317 void 318 do_mount(int argc, char **argv) 319 { 320 struct smbfs_args mdata; 321 struct mounta ma; 322 char *shrname; 323 int error; 324 325 if (vfsp != NULL) { 326 fprintf(stderr, "Already mounted\n"); 327 return; 328 } 329 330 if (argc < 2) { 331 fprintf(stderr, "%s: missing share name\n", argv[0]); 332 return; 333 } 334 shrname = argv[1]; 335 if (argc > 2) 336 strlcpy(mnt_opt_buf, argv[2], sizeof (mnt_opt_buf)); 337 else 338 memset(mnt_opt_buf, 0, sizeof (mnt_opt_buf)); 339 340 smb_ctx_setshare(ctx, shrname, USE_DISKDEV); 341 error = smb_ctx_get_tree(ctx); 342 if (error) { 343 fprintf(stderr, "//%s/%s: tree connect failed, %d\n", 344 server, shrname, error); 345 return; 346 } 347 348 (void) snprintf(mnt_resource, sizeof (mnt_resource), 349 "//%s/%s", ctx->ct_fullserver, shrname); 350 351 bzero(&mdata, sizeof (mdata)); 352 mdata.version = SMBFS_VERSION; /* smbfs mount version */ 353 mdata.file_mode = S_IRWXU; 354 mdata.dir_mode = S_IRWXU; 355 mdata.devfd = ctx->ct_dev_fd; 356 357 /* Build mount args */ 358 bzero(&ma, sizeof (ma)); 359 ma.spec = mnt_resource; 360 ma.dir = "/"; 361 ma.flags = MS_DATA | MS_OPTIONSTR | MS_NOSPLICE | MS_NOSUID; 362 ma.fstype = "smbfs"; 363 ma.dataptr = (void *) &mdata; 364 ma.datalen = sizeof (mdata); 365 ma.optptr = mnt_opt_buf; 366 ma.optlen = sizeof (mnt_opt_buf); 367 368 error = fake_domount("smbfs", &ma, &vfsp); 369 if (error != 0) { 370 fprintf(stderr, "domount error=%d\n", error); 371 } 372 373 /* Mount takes a ref, so always rele here. */ 374 (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL); 375 } 376 377 void 378 do_unmount(int argc, char **argv) 379 { 380 int error; 381 382 if (vfsp == NULL) { 383 fprintf(stderr, "Not mounted\n"); 384 return; 385 } 386 387 error = fake_dounmount(vfsp, 0); 388 if (error != 0) { 389 fprintf(stderr, "dounmount error=%d\n", error); 390 return; 391 } 392 vfsp = NULL; 393 } 394 395 void 396 do_statfs(int argc, char **argv) 397 { 398 statvfs64_t st; 399 int error; 400 401 if (vfsp == NULL) { 402 fprintf(stderr, "Not mounted\n"); 403 return; 404 } 405 406 error = fsop_statfs(vfsp, &st); 407 if (error != 0) { 408 fprintf(stderr, "df error=%d\n", error); 409 return; 410 } 411 printf("bsize=%ld\n", st.f_bsize); 412 printf("frsize=%ld\n", st.f_frsize); 413 printf("blocks=%" PRIu64 "\n", st.f_blocks); 414 printf(" bfree=%" PRIu64 "\n", st.f_bfree); 415 printf("bavail=%" PRIu64 "\n", st.f_bavail); 416 } 417 418 void 419 do_dir(int argc, char **argv) 420 { 421 char *rdir; 422 vnode_t *vp = NULL; 423 offset_t off; 424 int cnt; 425 int error; 426 427 if (vfsp == NULL) { 428 fprintf(stderr, "mnt required first\n"); 429 return; 430 } 431 if (argc > 1) 432 rdir = argv[1]; 433 else 434 rdir = ""; 435 436 error = vn_open(rdir, 0, FREAD, 0, &vp, 0, 0); 437 if (error != 0) { 438 fprintf(stderr, "do_dir, vn_open error=%d\n", error); 439 return; 440 } 441 442 off = 0; 443 do { 444 cnt = fake_getdents(vp, &off, tbuf, TBUFSZ); 445 if (cnt < 0) { 446 fprintf(stderr, "do_dir, getdents %d\n", -cnt); 447 break; 448 } 449 show_dents(vp, &off, tbuf, cnt); 450 } while (cnt > 0); 451 452 if (vp != NULL) 453 vn_close_rele(vp, 0); 454 } 455 456 void 457 do_dirx(int argc, char **argv) 458 { 459 char *rdir; 460 vnode_t *vp = NULL; 461 offset_t off; 462 int cnt; 463 int error; 464 465 if (vfsp == NULL) { 466 fprintf(stderr, "mnt required first\n"); 467 return; 468 } 469 if (argc > 1) 470 rdir = argv[1]; 471 else 472 rdir = ""; 473 474 error = vn_open(rdir, 0, FREAD|FXATTRDIROPEN, 0, &vp, 0, 0); 475 if (error != 0) { 476 fprintf(stderr, "do_dirx, vn_open error=%d\n", error); 477 return; 478 } 479 480 off = 0; 481 do { 482 cnt = fake_getdents(vp, &off, tbuf, TBUFSZ); 483 if (cnt < 0) { 484 fprintf(stderr, "do_dirx, getdents %d\n", -cnt); 485 break; 486 } 487 show_dents(vp, &off, tbuf, cnt); 488 } while (cnt > 0); 489 490 if (vp != NULL) 491 vn_close_rele(vp, 0); 492 } 493 494 static void 495 show_dents(vnode_t *dvp, offset_t *offp, char *buf, int cnt) 496 { 497 char time_buf[40]; 498 struct stat64 st; 499 vnode_t *vp; 500 char *p; 501 dirent_t *d; 502 offset_t offset = (offset_t)-1L; 503 int error; 504 uint_t mode; 505 char type; 506 507 p = buf; 508 while (p < (buf + cnt)) { 509 d = (dirent_t *)(void *)p; 510 p += d->d_reclen; 511 offset = d->d_off; 512 513 error = fake_lookup(dvp, d->d_name, &vp); 514 if (error != 0) { 515 fprintf(stderr, "%s: lookup error=%d\n", 516 d->d_name, error); 517 continue; 518 } 519 error = fake_stat(vp, &st, 0); 520 vn_rele(vp); 521 if (error != 0) { 522 fprintf(stderr, "%s: stat error=%d\n", 523 d->d_name, error); 524 continue; 525 } 526 527 /* 528 * Print type, mode, size, name 529 * First mode (only dir, file expected here) 530 */ 531 if (S_ISDIR(st.st_mode)) { 532 type = 'd'; 533 } else if (S_ISREG(st.st_mode)) { 534 type = ' '; 535 } else { 536 type = '?'; 537 } 538 mode = st.st_mode & 0777; 539 (void) strftime(time_buf, sizeof (time_buf), 540 "%b %e %T %Y", localtime(&st.st_mtime)); 541 542 printf("%c 0%3o %9" PRIu64 " %s %s\n", 543 type, mode, 544 (uint64_t)st.st_size, 545 time_buf, 546 d->d_name); 547 } 548 *offp = offset; 549 } 550 551 /* 552 * get rname [lname] 553 */ 554 void 555 do_get(int argc, char **argv) 556 { 557 struct stat64 st; 558 char *rname; 559 char *lname; 560 vnode_t *vp = NULL; 561 offset_t off; 562 ssize_t cnt, x; 563 int oflg = O_RDWR | O_CREAT; 564 int lfd = -1; 565 int error; 566 567 if (vfsp == NULL) { 568 fprintf(stderr, "mnt required first\n"); 569 return; 570 } 571 if (argc < 2) { 572 fprintf(stderr, "rname required\n"); 573 return; 574 } 575 rname = argv[1]; 576 if (argc > 2) { 577 lname = argv[2]; 578 /* 579 * When local name is specified, overwrite. 580 * Convenient for scripts etc. 581 */ 582 oflg |= O_TRUNC; 583 } else { 584 lname = rname; 585 /* Local file should not exist. */ 586 oflg |= O_EXCL; 587 } 588 589 lfd = open(lname, oflg, 0644); 590 if (lfd < 0) { 591 perror(lname); 592 return; 593 } 594 595 error = vn_open(rname, 0, FREAD, 0, &vp, 0, 0); 596 if (error != 0) { 597 fprintf(stderr, "do_get, vn_open error=%d\n", error); 598 goto out; 599 } 600 error = fake_stat(vp, &st, 0); 601 if (error != 0) { 602 fprintf(stderr, "do_get, stat error=%d\n", error); 603 goto out; 604 } 605 606 off = 0; 607 do { 608 cnt = fake_pread(vp, tbuf, TBUFSZ, off); 609 if (cnt < 0) { 610 fprintf(stderr, "do_get, read %d\n", -cnt); 611 goto out; 612 } 613 x = write(lfd, tbuf, cnt); 614 if (x < 0) { 615 fprintf(stderr, "do_get, write %d\n", errno); 616 goto out; 617 } 618 off += x; 619 } while (off < st.st_size); 620 621 out: 622 if (vp != NULL) 623 vn_close_rele(vp, 0); 624 if (lfd != -1) 625 close(lfd); 626 } 627 628 /* 629 * put lname [rname] 630 */ 631 void 632 do_put(int argc, char **argv) 633 { 634 struct stat64 rst; 635 struct stat st; 636 char *rname; 637 char *lname; 638 vnode_t *vp = NULL; 639 offset_t off; 640 ssize_t cnt, x; 641 int oflg = FREAD|FWRITE|FCREAT; 642 int lfd = -1; 643 int error; 644 645 if (vfsp == NULL) { 646 fprintf(stderr, "mnt required first\n"); 647 return; 648 } 649 if (argc < 2) { 650 fprintf(stderr, "lname required\n"); 651 return; 652 } 653 lname = argv[1]; 654 if (argc > 2) { 655 rname = argv[2]; 656 /* 657 * When remote name is specified, overwrite. 658 * Convenient for scripts etc. 659 */ 660 oflg |= FTRUNC; 661 } else { 662 rname = lname; 663 /* Remote file should not exist. */ 664 oflg |= FEXCL; 665 } 666 667 lfd = open(lname, O_RDONLY, 0); 668 if (lfd < 0) { 669 perror(lname); 670 return; 671 } 672 error = fstat(lfd, &st); 673 if (error != 0) { 674 fprintf(stderr, "do_put, stat error=%d\n", error); 675 goto out; 676 } 677 678 error = vn_open(rname, 0, oflg, 0, &vp, 0, 0); 679 if (error != 0) { 680 fprintf(stderr, "do_put, vn_open error=%d\n", error); 681 goto out; 682 } 683 684 off = 0; 685 do { 686 cnt = pread(lfd, tbuf, TBUFSZ, off); 687 if (cnt < 0) { 688 fprintf(stderr, "do_put, read %d\n", errno); 689 goto out; 690 } 691 x = fake_pwrite(vp, tbuf, cnt, off); 692 if (x < 0) { 693 fprintf(stderr, "do_put, write %d\n", -x); 694 goto out; 695 } 696 off += cnt; 697 } while (off < st.st_size); 698 699 /* This getattr should go OtW. */ 700 error = fake_stat(vp, &rst, 0); 701 if (error != 0) { 702 fprintf(stderr, "do_put, stat error=%d\n", error); 703 goto out; 704 } 705 if (rst.st_size != st.st_size) { 706 fprintf(stderr, "do_put, wrong size?\n"); 707 } 708 709 out: 710 if (vp != NULL) 711 vn_close_rele(vp, 0); 712 if (lfd != -1) 713 close(lfd); 714 } 715 716 /* 717 * rm rname 718 */ 719 void 720 do_rm(int argc, char **argv) 721 { 722 char *rname; 723 int error; 724 725 if (vfsp == NULL) { 726 fprintf(stderr, "mnt required first\n"); 727 return; 728 } 729 if (argc < 2) { 730 fprintf(stderr, "rname required\n"); 731 return; 732 } 733 rname = argv[1]; 734 735 error = fake_unlink(rname, 0); 736 if (error != 0) { 737 fprintf(stderr, "do_rm, unlink error=%d\n", error); 738 } 739 } 740 741 /* 742 * mv fromname toname 743 */ 744 void 745 do_mv(int argc, char **argv) 746 { 747 int error; 748 749 if (vfsp == NULL) { 750 fprintf(stderr, "mnt required first\n"); 751 return; 752 } 753 if (argc < 3) { 754 fprintf(stderr, "from_name to_name required\n"); 755 return; 756 } 757 758 error = fake_rename(argv[1], argv[2]); 759 if (error != 0) { 760 fprintf(stderr, "do_mv, rename error=%d\n", error); 761 } 762 } 763 764 /* 765 * mkdir rname 766 */ 767 void 768 do_mkdir(int argc, char **argv) 769 { 770 char *rname; 771 vnode_t *vp = NULL; 772 int error; 773 774 if (vfsp == NULL) { 775 fprintf(stderr, "mnt required first\n"); 776 return; 777 } 778 if (argc < 2) { 779 fprintf(stderr, "rname required\n"); 780 return; 781 } 782 rname = argv[1]; 783 784 error = vn_open(rname, 0, FCREAT, 0, &vp, CRMKDIR, 0); 785 if (error != 0) { 786 fprintf(stderr, "do_mkdir, vn_open error=%d\n", error); 787 } 788 789 if (vp != NULL) 790 vn_close_rele(vp, 0); 791 } 792 793 /* 794 * rmdir rname 795 */ 796 void 797 do_rmdir(int argc, char **argv) 798 { 799 char *rname; 800 int error; 801 802 if (vfsp == NULL) { 803 fprintf(stderr, "mnt required first\n"); 804 return; 805 } 806 if (argc < 2) { 807 fprintf(stderr, "rname required\n"); 808 return; 809 } 810 rname = argv[1]; 811 812 error = fake_unlink(rname, AT_REMOVEDIR); 813 if (error != 0) { 814 fprintf(stderr, "do_rmdir, unlink error=%d\n", error); 815 } 816 } 817 818 /* 819 * Simple option setting 820 * 821 * Each arg is handled as one line in .nsmbrc [default] 822 */ 823 void 824 do_opt(int argc, char **argv) 825 { 826 static char template[20] = "/tmp/fksmbclXXXXXX"; 827 static char rcname[30]; 828 char *tdname; 829 char *save_home; 830 FILE *fp; 831 int err, i; 832 833 if (argc < 2) { 834 fprintf(stderr, "opt {key}[=value]\n"); 835 return; 836 } 837 838 tdname = mkdtemp(template); 839 if (tdname == NULL) { 840 perror("mkdtemp"); 841 return; 842 } 843 (void) snprintf(rcname, sizeof (rcname), 844 "%s/.nsmbrc", tdname); 845 846 fp = fopen(rcname, "w"); 847 if (fp == NULL) { 848 perror(rcname); 849 goto out; 850 } 851 fprintf(fp, "[default]\n"); 852 for (i = 1; i < argc; i++) 853 fprintf(fp, "%s\n", argv[i]); 854 fclose(fp); 855 856 save_home = ctx->ct_home; 857 ctx->ct_home = tdname; 858 err = smb_ctx_readrc(ctx); 859 ctx->ct_home = save_home; 860 861 if (err != 0) 862 fprintf(stderr, "readrc, err=%d\n", err); 863 864 out: 865 (void) unlink(rcname); 866 (void) rmdir(tdname); 867 } 868 869 /* 870 * Command table 871 */ 872 static struct cmd_tbl_ent 873 cmd_tbl[] = { 874 { do_help, "help", "" }, 875 { do_exit, "exit", "" }, 876 { do_logon, "logon", "[user [dom [pass]]]" }, 877 { do_logoff, "logoff", "[close-driver]" }, 878 { do_shares, "shares", "" }, 879 { do_mount, "mount", "{share} [optstr]" }, 880 { do_unmount, "umount", "" }, 881 { do_unmount, "unmount", "" }, 882 { do_statfs, "statfs", "" }, 883 { do_dir, "dir", "{rdir} [lfile]" }, 884 { do_dirx, "dirx", "{rdir} [lfile]" }, 885 { do_get, "get", "{rfile} [lfile]" }, 886 { do_put, "put", "{lfile} [rfile]" }, 887 { do_mv, "mv", "{from} {to}" }, 888 { do_rm, "rm", "{rfile}" }, 889 { do_mkdir, "mkdir", "{rfile}" }, 890 { do_rmdir, "rmdir", "{rfile}" }, 891 { do_opt, "opt", "{option}" }, 892 { NULL, NULL, NULL } 893 }; 894 895 /* 896 * Provide a real function (one that prints something) to replace 897 * the stub in libfakekernel. This prints cmn_err() messages. 898 */ 899 void 900 fakekernel_putlog(char *msg, size_t len, int flags) 901 { 902 903 /* 904 * [CE_CONT, CE_NOTE, CE_WARN, CE_PANIC] maps to 905 * [SL_NOTE, SL_NOTE, SL_WARN, SL_FATAL] 906 */ 907 if (smb_debug == 0 && (flags & SL_NOTE)) 908 return; 909 (void) fwrite(msg, 1, len, stdout); 910 (void) fflush(stdout); 911 } 912 913 /* 914 * Enable libumem debugging 915 */ 916 const char * 917 _umem_debug_init(void) 918 { 919 return ("default,verbose"); /* $UMEM_DEBUG setting */ 920 } 921 922 const char * 923 _umem_logging_init(void) 924 { 925 return ("fail,contents"); /* $UMEM_LOGGING setting */ 926 } 927