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