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], NULL);
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 /* LINTED E_BAD_PTR_CAST_ALIGN */
511 d = (dirent_t *)p;
512 p += d->d_reclen;
513 offset = d->d_off;
514
515 error = fake_lookup(dvp, d->d_name, &vp);
516 if (error != 0) {
517 fprintf(stderr, "%s: lookup error=%d\n",
518 d->d_name, error);
519 continue;
520 }
521 error = fake_stat(vp, &st, 0);
522 vn_rele(vp);
523 if (error != 0) {
524 fprintf(stderr, "%s: stat error=%d\n",
525 d->d_name, error);
526 continue;
527 }
528
529 /*
530 * Print type, mode, size, name
531 * First mode (only dir, file expected here)
532 */
533 if (S_ISDIR(st.st_mode)) {
534 type = 'd';
535 } else if (S_ISREG(st.st_mode)) {
536 type = ' ';
537 } else {
538 type = '?';
539 }
540 mode = st.st_mode & 0777;
541 (void) strftime(time_buf, sizeof (time_buf),
542 "%b %e %T %Y", localtime(&st.st_mtime));
543
544 printf("%c 0%3o %9" PRIu64 " %s %s\n",
545 type, mode,
546 (uint64_t)st.st_size,
547 time_buf,
548 d->d_name);
549 }
550 *offp = offset;
551 }
552
553 /*
554 * get rname [lname]
555 */
556 void
557 do_get(int argc, char **argv)
558 {
559 struct stat64 st;
560 char *rname;
561 char *lname;
562 vnode_t *vp = NULL;
563 offset_t off;
564 ssize_t cnt, x;
565 int oflg = O_RDWR | O_CREAT;
566 int lfd = -1;
567 int error;
568
569 if (vfsp == NULL) {
570 fprintf(stderr, "mnt required first\n");
571 return;
572 }
573 if (argc < 2) {
574 fprintf(stderr, "rname required\n");
575 return;
576 }
577 rname = argv[1];
578 if (argc > 2) {
579 lname = argv[2];
580 /*
581 * When local name is specified, overwrite.
582 * Convenient for scripts etc.
583 */
584 oflg |= O_TRUNC;
585 } else {
586 lname = rname;
587 /* Local file should not exist. */
588 oflg |= O_EXCL;
589 }
590
591 lfd = open(lname, oflg, 0644);
592 if (lfd < 0) {
593 perror(lname);
594 return;
595 }
596
597 error = vn_open(rname, 0, FREAD, 0, &vp, 0, 0);
598 if (error != 0) {
599 fprintf(stderr, "do_get, vn_open error=%d\n", error);
600 goto out;
601 }
602 error = fake_stat(vp, &st, 0);
603 if (error != 0) {
604 fprintf(stderr, "do_get, stat error=%d\n", error);
605 goto out;
606 }
607
608 off = 0;
609 do {
610 cnt = fake_pread(vp, tbuf, TBUFSZ, off);
611 if (cnt < 0) {
612 fprintf(stderr, "do_get, read %d\n", -cnt);
613 goto out;
614 }
615 x = write(lfd, tbuf, cnt);
616 if (x < 0) {
617 fprintf(stderr, "do_get, write %d\n", errno);
618 goto out;
619 }
620 off += x;
621 } while (off < st.st_size);
622
623 out:
624 if (vp != NULL)
625 vn_close_rele(vp, 0);
626 if (lfd != -1)
627 close(lfd);
628 }
629
630 /*
631 * put lname [rname]
632 */
633 void
634 do_put(int argc, char **argv)
635 {
636 struct stat64 rst;
637 struct stat st;
638 char *rname;
639 char *lname;
640 vnode_t *vp = NULL;
641 offset_t off;
642 ssize_t cnt, x;
643 int oflg = FREAD|FWRITE|FCREAT;
644 int lfd = -1;
645 int error;
646
647 if (vfsp == NULL) {
648 fprintf(stderr, "mnt required first\n");
649 return;
650 }
651 if (argc < 2) {
652 fprintf(stderr, "lname required\n");
653 return;
654 }
655 lname = argv[1];
656 if (argc > 2) {
657 rname = argv[2];
658 /*
659 * When remote name is specified, overwrite.
660 * Convenient for scripts etc.
661 */
662 oflg |= FTRUNC;
663 } else {
664 rname = lname;
665 /* Remote file should not exist. */
666 oflg |= FEXCL;
667 }
668
669 lfd = open(lname, O_RDONLY, 0);
670 if (lfd < 0) {
671 perror(lname);
672 return;
673 }
674 error = fstat(lfd, &st);
675 if (error != 0) {
676 fprintf(stderr, "do_put, stat error=%d\n", error);
677 goto out;
678 }
679
680 error = vn_open(rname, 0, oflg, 0, &vp, 0, 0);
681 if (error != 0) {
682 fprintf(stderr, "do_put, vn_open error=%d\n", error);
683 goto out;
684 }
685
686 off = 0;
687 do {
688 cnt = pread(lfd, tbuf, TBUFSZ, off);
689 if (cnt < 0) {
690 fprintf(stderr, "do_put, read %d\n", errno);
691 goto out;
692 }
693 x = fake_pwrite(vp, tbuf, cnt, off);
694 if (x < 0) {
695 fprintf(stderr, "do_put, write %d\n", -x);
696 goto out;
697 }
698 off += cnt;
699 } while (off < st.st_size);
700
701 /* This getattr should go OtW. */
702 error = fake_stat(vp, &rst, 0);
703 if (error != 0) {
704 fprintf(stderr, "do_put, stat error=%d\n", error);
705 goto out;
706 }
707 if (rst.st_size != st.st_size) {
708 fprintf(stderr, "do_put, wrong size?\n");
709 }
710
711 out:
712 if (vp != NULL)
713 vn_close_rele(vp, 0);
714 if (lfd != -1)
715 close(lfd);
716 }
717
718 /*
719 * rm rname
720 */
721 void
722 do_rm(int argc, char **argv)
723 {
724 char *rname;
725 int error;
726
727 if (vfsp == NULL) {
728 fprintf(stderr, "mnt required first\n");
729 return;
730 }
731 if (argc < 2) {
732 fprintf(stderr, "rname required\n");
733 return;
734 }
735 rname = argv[1];
736
737 error = fake_unlink(rname, 0);
738 if (error != 0) {
739 fprintf(stderr, "do_rm, unlink error=%d\n", error);
740 }
741 }
742
743 /*
744 * mv fromname toname
745 */
746 void
747 do_mv(int argc, char **argv)
748 {
749 int error;
750
751 if (vfsp == NULL) {
752 fprintf(stderr, "mnt required first\n");
753 return;
754 }
755 if (argc < 3) {
756 fprintf(stderr, "from_name to_name required\n");
757 return;
758 }
759
760 error = fake_rename(argv[1], argv[2]);
761 if (error != 0) {
762 fprintf(stderr, "do_mv, rename error=%d\n", error);
763 }
764 }
765
766 /*
767 * mkdir rname
768 */
769 void
770 do_mkdir(int argc, char **argv)
771 {
772 char *rname;
773 vnode_t *vp = NULL;
774 int error;
775
776 if (vfsp == NULL) {
777 fprintf(stderr, "mnt required first\n");
778 return;
779 }
780 if (argc < 2) {
781 fprintf(stderr, "rname required\n");
782 return;
783 }
784 rname = argv[1];
785
786 error = vn_open(rname, 0, FCREAT, 0, &vp, CRMKDIR, 0);
787 if (error != 0) {
788 fprintf(stderr, "do_mkdir, vn_open error=%d\n", error);
789 }
790
791 if (vp != NULL)
792 vn_close_rele(vp, 0);
793 }
794
795 /*
796 * rmdir rname
797 */
798 void
799 do_rmdir(int argc, char **argv)
800 {
801 char *rname;
802 int error;
803
804 if (vfsp == NULL) {
805 fprintf(stderr, "mnt required first\n");
806 return;
807 }
808 if (argc < 2) {
809 fprintf(stderr, "rname required\n");
810 return;
811 }
812 rname = argv[1];
813
814 error = fake_unlink(rname, AT_REMOVEDIR);
815 if (error != 0) {
816 fprintf(stderr, "do_rmdir, unlink error=%d\n", error);
817 }
818 }
819
820 /*
821 * Simple option setting
822 *
823 * Each arg is handled as one line in .nsmbrc [default]
824 */
825 void
826 do_opt(int argc, char **argv)
827 {
828 static char template[20] = "/tmp/fksmbclXXXXXX";
829 static char rcname[30];
830 char *tdname;
831 char *save_home;
832 FILE *fp;
833 int err, i;
834
835 if (argc < 2) {
836 fprintf(stderr, "opt {key}[=value]\n");
837 return;
838 }
839
840 tdname = mkdtemp(template);
841 if (tdname == NULL) {
842 perror("mkdtemp");
843 return;
844 }
845 (void) snprintf(rcname, sizeof (rcname),
846 "%s/.nsmbrc", tdname);
847
848 fp = fopen(rcname, "w");
849 if (fp == NULL) {
850 perror(rcname);
851 goto out;
852 }
853 fprintf(fp, "[default]\n");
854 for (i = 1; i < argc; i++)
855 fprintf(fp, "%s\n", argv[i]);
856 fclose(fp);
857
858 save_home = ctx->ct_home;
859 ctx->ct_home = tdname;
860 err = smb_ctx_readrc(ctx);
861 ctx->ct_home = save_home;
862
863 if (err != 0)
864 fprintf(stderr, "readrc, err=%d\n", err);
865
866 out:
867 (void) unlink(rcname);
868 (void) rmdir(tdname);
869 }
870
871 /*
872 * Command table
873 */
874 static struct cmd_tbl_ent
875 cmd_tbl[] = {
876 { do_help, "help", "" },
877 { do_exit, "exit", "" },
878 { do_logon, "logon", "[user [dom [pass]]]" },
879 { do_logoff, "logoff", "[close-driver]" },
880 { do_shares, "shares", "" },
881 { do_mount, "mount", "{share} [optstr]" },
882 { do_unmount, "umount", "" },
883 { do_unmount, "unmount", "" },
884 { do_statfs, "statfs", "" },
885 { do_dir, "dir", "{rdir} [lfile]" },
886 { do_dirx, "dirx", "{rdir} [lfile]" },
887 { do_get, "get", "{rfile} [lfile]" },
888 { do_put, "put", "{lfile} [rfile]" },
889 { do_mv, "mv", "{from} {to}" },
890 { do_rm, "rm", "{rfile}" },
891 { do_mkdir, "mkdir", "{rfile}" },
892 { do_rmdir, "rmdir", "{rfile}" },
893 { do_opt, "opt", "{option}" },
894 { NULL, NULL, NULL }
895 };
896
897 /*
898 * Provide a real function (one that prints something) to replace
899 * the stub in libfakekernel. This prints cmn_err() messages.
900 */
901 void
902 fakekernel_putlog(char *msg, size_t len, int flags)
903 {
904
905 /*
906 * [CE_CONT, CE_NOTE, CE_WARN, CE_PANIC] maps to
907 * [SL_NOTE, SL_NOTE, SL_WARN, SL_FATAL]
908 */
909 if (smb_debug == 0 && (flags & SL_NOTE))
910 return;
911 (void) fwrite(msg, 1, len, stdout);
912 (void) fflush(stdout);
913 }
914
915 /*
916 * Print nsmb debug messages via driver smb_debugmsg()
917 */
918 void
919 smb_debugmsg(const char *func, char *msg)
920 {
921 if (smb_debug < 2)
922 return;
923 printf("[kmod] %s: %s\n", func, msg);
924 }
925
926 /*
927 * Enable libumem debugging
928 */
929 const char *
930 _umem_debug_init(void)
931 {
932 return ("default,verbose"); /* $UMEM_DEBUG setting */
933 }
934
935 const char *
936 _umem_logging_init(void)
937 {
938 return ("fail,contents"); /* $UMEM_LOGGING setting */
939 }