18329232eSGordon Ross /*
28329232eSGordon Ross  * This file and its contents are supplied under the terms of the
38329232eSGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
48329232eSGordon Ross  * You may only use this file in accordance with the terms of version
58329232eSGordon Ross  * 1.0 of the CDDL.
68329232eSGordon Ross  *
78329232eSGordon Ross  * A full copy of the text of the CDDL should have accompanied this
88329232eSGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
98329232eSGordon Ross  * http://www.illumos.org/license/CDDL.
108329232eSGordon Ross  */
118329232eSGordon Ross 
128329232eSGordon Ross /*
13adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
148329232eSGordon Ross  */
158329232eSGordon Ross 
168329232eSGordon Ross /*
178329232eSGordon Ross  * Test & debug program for the SMB client
188329232eSGordon Ross  *
198329232eSGordon Ross  * This implements a simple command reader which accepts
208329232eSGordon Ross  * commands to simulate system calls into the file system.
218329232eSGordon Ross  */
228329232eSGordon Ross 
238329232eSGordon Ross #include <sys/types.h>
248329232eSGordon Ross #include <sys/file.h>
258329232eSGordon Ross #include <sys/stat.h>
268329232eSGordon Ross #include <sys/mount.h>
278329232eSGordon Ross #include <sys/dirent.h>
288329232eSGordon Ross #include <sys/strlog.h>		/* SL_NOTE */
298329232eSGordon Ross 
308329232eSGordon Ross #include <stdio.h>
318329232eSGordon Ross #include <stdlib.h>
328329232eSGordon Ross #include <string.h>
338329232eSGordon Ross #include <strings.h>
348329232eSGordon Ross #include <errno.h>
358329232eSGordon Ross #include <fcntl.h>
36adee6784SGordon Ross #include <inttypes.h>
378329232eSGordon Ross #include <unistd.h>
388329232eSGordon Ross 
398329232eSGordon Ross #include <sys/fs/smbfs_mount.h>
408329232eSGordon Ross #include <netsmb/smb_lib.h>
418329232eSGordon Ross #include <libfknsmb/common/libfknsmb.h>
428329232eSGordon Ross #include <libfksmbfs/common/libfksmbfs.h>
438329232eSGordon Ross 
448329232eSGordon Ross #if _FILE_OFFSET_BITS != 64
458329232eSGordon Ross #error "This calls (fake) VFS code which requires 64-bit off_t"
468329232eSGordon Ross #endif
478329232eSGordon Ross 
488329232eSGordon Ross extern int list_shares(struct smb_ctx *);
498329232eSGordon Ross 
508329232eSGordon Ross #define	MAXARG	10
518329232eSGordon Ross 
528329232eSGordon Ross struct cmd_tbl_ent {
538329232eSGordon Ross 	void (*ce_func)(int, char **);
548329232eSGordon Ross 	const char *ce_name;
558329232eSGordon Ross 	const char *ce_argdesc;
568329232eSGordon Ross };
578329232eSGordon Ross static struct cmd_tbl_ent cmd_tbl[];
588329232eSGordon Ross 
598329232eSGordon Ross static struct smb_ctx *ctx = NULL;
608329232eSGordon Ross static char *server = NULL;
618329232eSGordon Ross 
628329232eSGordon Ross static vfs_t *vfsp = NULL;
638329232eSGordon Ross 
648329232eSGordon Ross static void show_dents(vnode_t *, offset_t *, char *, int);
658329232eSGordon Ross static void run_cli(void);
668329232eSGordon Ross 
678329232eSGordon Ross #define	TBUFSZ 8192
688329232eSGordon Ross static char tbuf[TBUFSZ];
698329232eSGordon Ross 
708329232eSGordon Ross static void
fksmbcl_usage(void)718329232eSGordon Ross fksmbcl_usage(void)
728329232eSGordon Ross {
738329232eSGordon Ross 	printf("usage: fksmbcl //user@server (like smbutil)\n");
748329232eSGordon Ross 	exit(1);
758329232eSGordon Ross }
768329232eSGordon Ross 
778329232eSGordon Ross int
main(int argc,char * argv[])788329232eSGordon Ross main(int argc, char *argv[])
798329232eSGordon Ross {
808329232eSGordon Ross 	int error, opt;
818329232eSGordon Ross 
828329232eSGordon Ross 	/*
838329232eSGordon Ross 	 * Initializations
848329232eSGordon Ross 	 */
858329232eSGordon Ross 	nsmb_drv_load();
868329232eSGordon Ross 	nsmb_drv_init();
878329232eSGordon Ross 	fksmbfs_init();
888329232eSGordon Ross 
898329232eSGordon Ross 	while ((opt = getopt(argc, argv, "dv")) != -1) {
908329232eSGordon Ross 		switch (opt) {
918329232eSGordon Ross 		case 'd':
928329232eSGordon Ross 			smb_debug++;
938329232eSGordon Ross 			break;
948329232eSGordon Ross 		case 'v':
958329232eSGordon Ross 			smb_verbose++;
968329232eSGordon Ross 			break;
978329232eSGordon Ross 		case '?':
988329232eSGordon Ross 			fksmbcl_usage();
998329232eSGordon Ross 			break;
1008329232eSGordon Ross 		}
1018329232eSGordon Ross 	}
1028329232eSGordon Ross 	if (optind >= argc)
1038329232eSGordon Ross 		fksmbcl_usage();
1048329232eSGordon Ross 	server = argv[optind];
1058329232eSGordon Ross 
1068329232eSGordon Ross 	/*
1078329232eSGordon Ross 	 * Setup the libsmbfs context
1088329232eSGordon Ross 	 */
1098329232eSGordon Ross 	error = smb_ctx_alloc(&ctx);
1108329232eSGordon Ross 	if (error) {
1118329232eSGordon Ross 		fprintf(stderr, "%s: smb_ctx_alloc failed (%d)\n",
1128329232eSGordon Ross 		    argv[0], error);
1138329232eSGordon Ross 		return (1);
1148329232eSGordon Ross 	}
1158329232eSGordon Ross 
1168329232eSGordon Ross 	error = smb_ctx_scan_argv(ctx, argc, argv,
1178329232eSGordon Ross 	    SMBL_SERVER, SMBL_SERVER, USE_WILDCARD);
1188329232eSGordon Ross 	if (error) {
1198329232eSGordon Ross 		fprintf(stderr, "logon: smb_ctx_scan_argv, error %d\n", error);
1208329232eSGordon Ross 		return (1);
1218329232eSGordon Ross 	}
1228329232eSGordon Ross 	error = smb_ctx_readrc(ctx);
1238329232eSGordon Ross 	if (error) {
1248329232eSGordon Ross 		fprintf(stderr, "logon: smb_ctx_readrc, error %d\n", error);
1258329232eSGordon Ross 		return (1);
1268329232eSGordon Ross 	}
1278329232eSGordon Ross 
1288329232eSGordon Ross 	/* Do smb_ctx_setshare later, and smb_ctx_resolve. */
1298329232eSGordon Ross 
1308329232eSGordon Ross 	/*
1318329232eSGordon Ross 	 * Next would be smb_ctx_get_ssn() but don't do that until
1328329232eSGordon Ross 	 * the "logon" command so one can set breakpoints etc.
1338329232eSGordon Ross 	 */
1348329232eSGordon Ross 
1358329232eSGordon Ross 	/*
1368329232eSGordon Ross 	 * Run the CLI
1378329232eSGordon Ross 	 */
1388329232eSGordon Ross 	run_cli();
1398329232eSGordon Ross 
1408329232eSGordon Ross 	/*
1418329232eSGordon Ross 	 * Cleanup
1428329232eSGordon Ross 	 */
1438329232eSGordon Ross 	fksmbfs_fini();
1448329232eSGordon Ross 	nsmb_drv_fini();
1458329232eSGordon Ross 
1468329232eSGordon Ross 	return (0);
1478329232eSGordon Ross }
1488329232eSGordon Ross 
1498329232eSGordon Ross static void
run_cli()1508329232eSGordon Ross run_cli()
1518329232eSGordon Ross {
1528329232eSGordon Ross 	static char cmdbuf[100];
1538329232eSGordon Ross 	int argc, i;
1548329232eSGordon Ross 	char *argv[MAXARG];
1558329232eSGordon Ross 	char *cmd;
1568329232eSGordon Ross 	char *savep = NULL;
1578329232eSGordon Ross 	char *sep = " \t\n";
1588329232eSGordon Ross 	char *prompt = NULL;
1598329232eSGordon Ross 	struct cmd_tbl_ent *ce;
1608329232eSGordon Ross 
1618329232eSGordon Ross 	if (isatty(0)) {
1628329232eSGordon Ross 		fputs("# Start with:\n"
1638329232eSGordon Ross 		    "> logon [user [dom [pw]]]\n"
1648329232eSGordon Ross 		    "> shares\n"
1658329232eSGordon Ross 		    "> mount {share}\n\n",
1668329232eSGordon Ross 		    stdout);
1678329232eSGordon Ross 		prompt = "> ";
1688329232eSGordon Ross 	}
1698329232eSGordon Ross 
1708329232eSGordon Ross 	for (;;) {
1718329232eSGordon Ross 		if (prompt) {
1728329232eSGordon Ross 			fputs(prompt, stdout);
1738329232eSGordon Ross 			fflush(stdout);
1748329232eSGordon Ross 		}
1758329232eSGordon Ross 
1768329232eSGordon Ross 		cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin);
1778329232eSGordon Ross 		if (cmd == NULL)
1788329232eSGordon Ross 			break;
1798329232eSGordon Ross 		if (cmd[0] == '#')
1808329232eSGordon Ross 			continue;
1818329232eSGordon Ross 
1828329232eSGordon Ross 		if (prompt == NULL) {
1838329232eSGordon Ross 			/* Put commands in the output too. */
1848329232eSGordon Ross 			fprintf(stdout, "+ %s", cmdbuf);
1858329232eSGordon Ross 		}
1868329232eSGordon Ross 
1878329232eSGordon Ross 		argv[0] = strtok_r(cmd, sep, &savep);
1888329232eSGordon Ross 		if (argv[0] == NULL)
1898329232eSGordon Ross 			continue;
1908329232eSGordon Ross 		for (argc = 1; argc < MAXARG; argc++) {
1918329232eSGordon Ross 			argv[argc] = strtok_r(NULL, sep, &savep);
1928329232eSGordon Ross 			if (argv[argc] == NULL)
1938329232eSGordon Ross 				break;
1948329232eSGordon Ross 		}
1958329232eSGordon Ross 		for (i = argc; i < MAXARG; i++)
1968329232eSGordon Ross 			argv[i++] = NULL;
1978329232eSGordon Ross 
1988329232eSGordon Ross 		for (ce = cmd_tbl; ce->ce_name != NULL; ce++)
1998329232eSGordon Ross 			if (strcmp(ce->ce_name, argv[0]) == 0)
2008329232eSGordon Ross 				break;
2018329232eSGordon Ross 		if (ce->ce_name != NULL) {
2028329232eSGordon Ross 			ce->ce_func(argc, argv);
2038329232eSGordon Ross 		} else {
2048329232eSGordon Ross 			fprintf(stderr, "%s unknown command. Try help\n",
2058329232eSGordon Ross 			    argv[0]);
2068329232eSGordon Ross 		}
2078329232eSGordon Ross 	}
2088329232eSGordon Ross }
2098329232eSGordon Ross 
2108329232eSGordon Ross /*
2118329232eSGordon Ross  * Command handlers
2128329232eSGordon Ross  */
2138329232eSGordon Ross 
2148329232eSGordon Ross static void
do_exit(int argc,char ** argv)2158329232eSGordon Ross do_exit(int argc, char **argv)
2168329232eSGordon Ross {
2178329232eSGordon Ross 	exit(0);
2188329232eSGordon Ross }
2198329232eSGordon Ross 
2208329232eSGordon Ross static void
do_help(int argc,char ** argv)2218329232eSGordon Ross do_help(int argc, char **argv)
2228329232eSGordon Ross {
2238329232eSGordon Ross 	struct cmd_tbl_ent *ce;
2248329232eSGordon Ross 
2258329232eSGordon Ross 	printf("Commands:\n");
2268329232eSGordon Ross 	for (ce = cmd_tbl; ce->ce_func != NULL; ce++)
2278329232eSGordon Ross 		printf("%s %s\n", ce->ce_name, ce->ce_argdesc);
2288329232eSGordon Ross }
2298329232eSGordon Ross 
2308329232eSGordon Ross static void
do_logon(int argc,char ** argv)2318329232eSGordon Ross do_logon(int argc, char **argv)
2328329232eSGordon Ross {
2338329232eSGordon Ross 	int error;
2348329232eSGordon Ross 
2358329232eSGordon Ross 	if (argc > 1) {
2368329232eSGordon Ross 		if (argv[1][0] == '-') {
2378329232eSGordon Ross 			smb_ctx_setuser(ctx, "", B_TRUE);
2388329232eSGordon Ross 			ctx->ct_flags |= SMBCF_NOPWD;
2398329232eSGordon Ross 		} else {
2408329232eSGordon Ross 			smb_ctx_setuser(ctx, argv[1], B_TRUE);
2418329232eSGordon Ross 		}
2428329232eSGordon Ross 	}
2438329232eSGordon Ross 	if (argc > 2)
2448329232eSGordon Ross 		smb_ctx_setdomain(ctx, argv[2], B_TRUE);
2458329232eSGordon Ross 	if (argc > 3)
246*8509e9caSToomas Soome 		smb_ctx_setpassword(ctx, argv[3], 0);
2478329232eSGordon Ross 
2488329232eSGordon Ross 	/*
2498329232eSGordon Ross 	 * Resolve the server address, setup derived defaults.
2508329232eSGordon Ross 	 */
2518329232eSGordon Ross 	error = smb_ctx_resolve(ctx);
2528329232eSGordon Ross 	if (error) {
2538329232eSGordon Ross 		fprintf(stderr, "logon: smb_ctx_resolve, error %d\n", error);
2548329232eSGordon Ross 		return;
2558329232eSGordon Ross 	}
2568329232eSGordon Ross 
2578329232eSGordon Ross 	/*
2588329232eSGordon Ross 	 * Have server, share, etc. now.
2598329232eSGordon Ross 	 * Get the logon session.
2608329232eSGordon Ross 	 */
2618329232eSGordon Ross again:
2628329232eSGordon Ross 	error = smb_ctx_get_ssn(ctx);
2638329232eSGordon Ross 	if (error == EAUTH) {
2648329232eSGordon Ross 		int err2;
2658329232eSGordon Ross 		err2 = smb_get_authentication(ctx);
2668329232eSGordon Ross 		if (err2 == 0)
2678329232eSGordon Ross 			goto again;
2688329232eSGordon Ross 	}
2698329232eSGordon Ross 	if (error) {
2708329232eSGordon Ross 		fprintf(stderr, "//%s: login failed, error %d\n",
2718329232eSGordon Ross 		    ctx->ct_fullserver, error);
2728329232eSGordon Ross 	}
2738329232eSGordon Ross }
2748329232eSGordon Ross 
2758329232eSGordon Ross /*
2768329232eSGordon Ross  * Drop session created by the "logon" command.
2778329232eSGordon Ross  */
2788329232eSGordon Ross static void
do_logoff(int argc,char ** argv)2798329232eSGordon Ross do_logoff(int argc, char **argv)
2808329232eSGordon Ross {
2818329232eSGordon Ross 
2828329232eSGordon Ross 	(void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_RELE, NULL);
2838329232eSGordon Ross 	if (argc > 1) {
2848329232eSGordon Ross 		smb_ctx_done(ctx);
2858329232eSGordon Ross 		(void) smb_ctx_init(ctx);
2868329232eSGordon Ross 	}
2878329232eSGordon Ross }
2888329232eSGordon Ross 
2898329232eSGordon Ross /*
2908329232eSGordon Ross  * List shares
2918329232eSGordon Ross  */
2928329232eSGordon Ross static void
do_shares(int argc,char ** argv)2938329232eSGordon Ross do_shares(int argc, char **argv)
2948329232eSGordon Ross {
2958329232eSGordon Ross 	int error;
2968329232eSGordon Ross 
2978329232eSGordon Ross 	smb_ctx_setshare(ctx, "IPC$", USE_IPC);
2988329232eSGordon Ross 	error = smb_ctx_get_tree(ctx);
2998329232eSGordon Ross 	if (error) {
3008329232eSGordon Ross 		fprintf(stderr, "shares, tcon IPC$, error=%d\n", error);
3018329232eSGordon Ross 		return;
3028329232eSGordon Ross 	}
3038329232eSGordon Ross 
3048329232eSGordon Ross 	error = list_shares(ctx);
3058329232eSGordon Ross 	if (error) {
3068329232eSGordon Ross 		fprintf(stderr, "shares, enum, error=%d\n", error);
3078329232eSGordon Ross 	}
3088329232eSGordon Ross 
3098329232eSGordon Ross 	(void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL);
3108329232eSGordon Ross }
3118329232eSGordon Ross 
3128329232eSGordon Ross char mnt_opt_buf[MAX_MNTOPT_STR];
3138329232eSGordon Ross char mnt_resource[MAXPATHLEN];
3148329232eSGordon Ross 
3158329232eSGordon Ross /*
3168329232eSGordon Ross  * Minimal excerpt from vfs.c:domount()
3178329232eSGordon Ross  */
3188329232eSGordon Ross void
do_mount(int argc,char ** argv)3198329232eSGordon Ross do_mount(int argc, char **argv)
3208329232eSGordon Ross {
3218329232eSGordon Ross 	struct smbfs_args mdata;
3228329232eSGordon Ross 	struct mounta ma;
3238329232eSGordon Ross 	char *shrname;
3248329232eSGordon Ross 	int error;
3258329232eSGordon Ross 
3268329232eSGordon Ross 	if (vfsp != NULL) {
3278329232eSGordon Ross 		fprintf(stderr, "Already mounted\n");
3288329232eSGordon Ross 		return;
3298329232eSGordon Ross 	}
3308329232eSGordon Ross 
3318329232eSGordon Ross 	if (argc < 2) {
3328329232eSGordon Ross 		fprintf(stderr, "%s: missing share name\n", argv[0]);
3338329232eSGordon Ross 		return;
3348329232eSGordon Ross 	}
3358329232eSGordon Ross 	shrname = argv[1];
3368329232eSGordon Ross 	if (argc > 2)
3378329232eSGordon Ross 		strlcpy(mnt_opt_buf, argv[2], sizeof (mnt_opt_buf));
3388329232eSGordon Ross 	else
3398329232eSGordon Ross 		memset(mnt_opt_buf, 0, sizeof (mnt_opt_buf));
3408329232eSGordon Ross 
3418329232eSGordon Ross 	smb_ctx_setshare(ctx, shrname, USE_DISKDEV);
3428329232eSGordon Ross 	error = smb_ctx_get_tree(ctx);
3438329232eSGordon Ross 	if (error) {
3448329232eSGordon Ross 		fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
3458329232eSGordon Ross 		    server, shrname, error);
3468329232eSGordon Ross 		return;
3478329232eSGordon Ross 	}
3488329232eSGordon Ross 
3498329232eSGordon Ross 	(void) snprintf(mnt_resource, sizeof (mnt_resource),
3508329232eSGordon Ross 	    "//%s/%s", ctx->ct_fullserver, shrname);
3518329232eSGordon Ross 
3528329232eSGordon Ross 	bzero(&mdata, sizeof (mdata));
3538329232eSGordon Ross 	mdata.version = SMBFS_VERSION;		/* smbfs mount version */
3548329232eSGordon Ross 	mdata.file_mode = S_IRWXU;
3558329232eSGordon Ross 	mdata.dir_mode = S_IRWXU;
3568329232eSGordon Ross 	mdata.devfd = ctx->ct_dev_fd;
3578329232eSGordon Ross 
3588329232eSGordon Ross 	/* Build mount args */
3598329232eSGordon Ross 	bzero(&ma, sizeof (ma));
3608329232eSGordon Ross 	ma.spec = mnt_resource;
3618329232eSGordon Ross 	ma.dir = "/";
3628329232eSGordon Ross 	ma.flags =  MS_DATA | MS_OPTIONSTR | MS_NOSPLICE | MS_NOSUID;
3638329232eSGordon Ross 	ma.fstype = "smbfs";
3648329232eSGordon Ross 	ma.dataptr = (void *) &mdata;
3658329232eSGordon Ross 	ma.datalen = sizeof (mdata);
3668329232eSGordon Ross 	ma.optptr = mnt_opt_buf;
3678329232eSGordon Ross 	ma.optlen = sizeof (mnt_opt_buf);
3688329232eSGordon Ross 
3698329232eSGordon Ross 	error = fake_domount("smbfs", &ma, &vfsp);
3708329232eSGordon Ross 	if (error != 0) {
3718329232eSGordon Ross 		fprintf(stderr, "domount error=%d\n", error);
3728329232eSGordon Ross 	}
3738329232eSGordon Ross 
3748329232eSGordon Ross 	/* Mount takes a ref, so always rele here. */
3758329232eSGordon Ross 	(void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL);
3768329232eSGordon Ross }
3778329232eSGordon Ross 
3788329232eSGordon Ross void
do_unmount(int argc,char ** argv)3798329232eSGordon Ross do_unmount(int argc, char **argv)
3808329232eSGordon Ross {
3818329232eSGordon Ross 	int error;
3828329232eSGordon Ross 
3838329232eSGordon Ross 	if (vfsp == NULL) {
3848329232eSGordon Ross 		fprintf(stderr, "Not mounted\n");
3858329232eSGordon Ross 		return;
3868329232eSGordon Ross 	}
3878329232eSGordon Ross 
3888329232eSGordon Ross 	error = fake_dounmount(vfsp, 0);
3898329232eSGordon Ross 	if (error != 0) {
3908329232eSGordon Ross 		fprintf(stderr, "dounmount error=%d\n", error);
3918329232eSGordon Ross 		return;
3928329232eSGordon Ross 	}
3938329232eSGordon Ross 	vfsp = NULL;
3948329232eSGordon Ross }
3958329232eSGordon Ross 
3968329232eSGordon Ross void
do_statfs(int argc,char ** argv)3978329232eSGordon Ross do_statfs(int argc, char **argv)
3988329232eSGordon Ross {
3998329232eSGordon Ross 	statvfs64_t st;
4008329232eSGordon Ross 	int error;
4018329232eSGordon Ross 
4028329232eSGordon Ross 	if (vfsp == NULL) {
4038329232eSGordon Ross 		fprintf(stderr, "Not mounted\n");
4048329232eSGordon Ross 		return;
4058329232eSGordon Ross 	}
4068329232eSGordon Ross 
4078329232eSGordon Ross 	error = fsop_statfs(vfsp, &st);
4088329232eSGordon Ross 	if (error != 0) {
4098329232eSGordon Ross 		fprintf(stderr, "df error=%d\n", error);
4108329232eSGordon Ross 		return;
4118329232eSGordon Ross 	}
4128329232eSGordon Ross 	printf("bsize=%ld\n", st.f_bsize);
4138329232eSGordon Ross 	printf("frsize=%ld\n", st.f_frsize);
4148329232eSGordon Ross 	printf("blocks=%" PRIu64 "\n", st.f_blocks);
4158329232eSGordon Ross 	printf(" bfree=%" PRIu64 "\n", st.f_bfree);
4168329232eSGordon Ross 	printf("bavail=%" PRIu64 "\n", st.f_bavail);
4178329232eSGordon Ross }
4188329232eSGordon Ross 
4198329232eSGordon Ross void
do_dir(int argc,char ** argv)4208329232eSGordon Ross do_dir(int argc, char **argv)
4218329232eSGordon Ross {
4228329232eSGordon Ross 	char *rdir;
4238329232eSGordon Ross 	vnode_t *vp = NULL;
4248329232eSGordon Ross 	offset_t off;
4258329232eSGordon Ross 	int cnt;
4268329232eSGordon Ross 	int error;
4278329232eSGordon Ross 
4288329232eSGordon Ross 	if (vfsp == NULL) {
4298329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
4308329232eSGordon Ross 		return;
4318329232eSGordon Ross 	}
4328329232eSGordon Ross 	if (argc > 1)
4338329232eSGordon Ross 		rdir = argv[1];
4348329232eSGordon Ross 	else
4358329232eSGordon Ross 		rdir = "";
4368329232eSGordon Ross 
4378329232eSGordon Ross 	error = vn_open(rdir, 0, FREAD, 0, &vp, 0, 0);
4388329232eSGordon Ross 	if (error != 0) {
4398329232eSGordon Ross 		fprintf(stderr, "do_dir, vn_open error=%d\n", error);
4408329232eSGordon Ross 		return;
4418329232eSGordon Ross 	}
4428329232eSGordon Ross 
4438329232eSGordon Ross 	off = 0;
4448329232eSGordon Ross 	do {
4458329232eSGordon Ross 		cnt = fake_getdents(vp, &off, tbuf, TBUFSZ);
4468329232eSGordon Ross 		if (cnt < 0) {
4478329232eSGordon Ross 			fprintf(stderr, "do_dir, getdents %d\n", -cnt);
4488329232eSGordon Ross 			break;
4498329232eSGordon Ross 		}
4508329232eSGordon Ross 		show_dents(vp, &off, tbuf, cnt);
4518329232eSGordon Ross 	} while (cnt > 0);
4528329232eSGordon Ross 
4538329232eSGordon Ross 	if (vp != NULL)
4548329232eSGordon Ross 		vn_close_rele(vp, 0);
4558329232eSGordon Ross }
4568329232eSGordon Ross 
4578329232eSGordon Ross void
do_dirx(int argc,char ** argv)4588329232eSGordon Ross do_dirx(int argc, char **argv)
4598329232eSGordon Ross {
4608329232eSGordon Ross 	char *rdir;
4618329232eSGordon Ross 	vnode_t *vp = NULL;
4628329232eSGordon Ross 	offset_t off;
4638329232eSGordon Ross 	int cnt;
4648329232eSGordon Ross 	int error;
4658329232eSGordon Ross 
4668329232eSGordon Ross 	if (vfsp == NULL) {
4678329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
4688329232eSGordon Ross 		return;
4698329232eSGordon Ross 	}
4708329232eSGordon Ross 	if (argc > 1)
4718329232eSGordon Ross 		rdir = argv[1];
4728329232eSGordon Ross 	else
4738329232eSGordon Ross 		rdir = "";
4748329232eSGordon Ross 
4758329232eSGordon Ross 	error = vn_open(rdir, 0, FREAD|FXATTRDIROPEN, 0, &vp, 0, 0);
4768329232eSGordon Ross 	if (error != 0) {
4778329232eSGordon Ross 		fprintf(stderr, "do_dirx, vn_open error=%d\n", error);
4788329232eSGordon Ross 		return;
4798329232eSGordon Ross 	}
4808329232eSGordon Ross 
4818329232eSGordon Ross 	off = 0;
4828329232eSGordon Ross 	do {
4838329232eSGordon Ross 		cnt = fake_getdents(vp, &off, tbuf, TBUFSZ);
4848329232eSGordon Ross 		if (cnt < 0) {
4858329232eSGordon Ross 			fprintf(stderr, "do_dirx, getdents %d\n", -cnt);
4868329232eSGordon Ross 			break;
4878329232eSGordon Ross 		}
4888329232eSGordon Ross 		show_dents(vp, &off, tbuf, cnt);
4898329232eSGordon Ross 	} while (cnt > 0);
4908329232eSGordon Ross 
4918329232eSGordon Ross 	if (vp != NULL)
4928329232eSGordon Ross 		vn_close_rele(vp, 0);
4938329232eSGordon Ross }
4948329232eSGordon Ross 
4958329232eSGordon Ross static void
show_dents(vnode_t * dvp,offset_t * offp,char * buf,int cnt)4968329232eSGordon Ross show_dents(vnode_t *dvp, offset_t *offp, char *buf, int cnt)
4978329232eSGordon Ross {
4988329232eSGordon Ross 	char time_buf[40];
4998329232eSGordon Ross 	struct stat64 st;
5008329232eSGordon Ross 	vnode_t *vp;
5018329232eSGordon Ross 	char *p;
5028329232eSGordon Ross 	dirent_t *d;
5038329232eSGordon Ross 	offset_t offset = (offset_t)-1L;
5048329232eSGordon Ross 	int error;
5058329232eSGordon Ross 	uint_t mode;
5068329232eSGordon Ross 	char type;
5078329232eSGordon Ross 
5088329232eSGordon Ross 	p = buf;
5098329232eSGordon Ross 	while (p < (buf + cnt)) {
5108329232eSGordon Ross 		d = (dirent_t *)(void *)p;
5118329232eSGordon Ross 		p += d->d_reclen;
5128329232eSGordon Ross 		offset = d->d_off;
5138329232eSGordon Ross 
5148329232eSGordon Ross 		error = fake_lookup(dvp, d->d_name, &vp);
5158329232eSGordon Ross 		if (error != 0) {
5168329232eSGordon Ross 			fprintf(stderr, "%s: lookup error=%d\n",
5178329232eSGordon Ross 			    d->d_name, error);
5188329232eSGordon Ross 			continue;
5198329232eSGordon Ross 		}
5208329232eSGordon Ross 		error = fake_stat(vp, &st, 0);
5218329232eSGordon Ross 		vn_rele(vp);
5228329232eSGordon Ross 		if (error != 0) {
5238329232eSGordon Ross 			fprintf(stderr, "%s: stat error=%d\n",
5248329232eSGordon Ross 			    d->d_name, error);
5258329232eSGordon Ross 			continue;
5268329232eSGordon Ross 		}
5278329232eSGordon Ross 
5288329232eSGordon Ross 		/*
5298329232eSGordon Ross 		 * Print type, mode, size, name
5308329232eSGordon Ross 		 * First mode (only dir, file expected here)
5318329232eSGordon Ross 		 */
5328329232eSGordon Ross 		if (S_ISDIR(st.st_mode)) {
5338329232eSGordon Ross 			type = 'd';
5348329232eSGordon Ross 		} else if (S_ISREG(st.st_mode)) {
5358329232eSGordon Ross 			type = ' ';
5368329232eSGordon Ross 		} else {
5378329232eSGordon Ross 			type = '?';
5388329232eSGordon Ross 		}
5398329232eSGordon Ross 		mode = st.st_mode & 0777;
5408329232eSGordon Ross 		(void) strftime(time_buf, sizeof (time_buf),
5418329232eSGordon Ross 		    "%b %e %T %Y", localtime(&st.st_mtime));
5428329232eSGordon Ross 
5438329232eSGordon Ross 		printf("%c 0%3o %9" PRIu64 "  %s  %s\n",
5448329232eSGordon Ross 		    type, mode,
5458329232eSGordon Ross 		    (uint64_t)st.st_size,
5468329232eSGordon Ross 		    time_buf,
5478329232eSGordon Ross 		    d->d_name);
5488329232eSGordon Ross 	}
5498329232eSGordon Ross 	*offp = offset;
5508329232eSGordon Ross }
5518329232eSGordon Ross 
5528329232eSGordon Ross /*
5538329232eSGordon Ross  * get rname [lname]
5548329232eSGordon Ross  */
5558329232eSGordon Ross void
do_get(int argc,char ** argv)5568329232eSGordon Ross do_get(int argc, char **argv)
5578329232eSGordon Ross {
5588329232eSGordon Ross 	struct stat64 st;
5598329232eSGordon Ross 	char *rname;
5608329232eSGordon Ross 	char *lname;
5618329232eSGordon Ross 	vnode_t *vp = NULL;
5628329232eSGordon Ross 	offset_t off;
5638329232eSGordon Ross 	ssize_t cnt, x;
5648329232eSGordon Ross 	int oflg = O_RDWR | O_CREAT;
5658329232eSGordon Ross 	int lfd = -1;
5668329232eSGordon Ross 	int error;
5678329232eSGordon Ross 
5688329232eSGordon Ross 	if (vfsp == NULL) {
5698329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
5708329232eSGordon Ross 		return;
5718329232eSGordon Ross 	}
5728329232eSGordon Ross 	if (argc < 2) {
5738329232eSGordon Ross 		fprintf(stderr, "rname required\n");
5748329232eSGordon Ross 		return;
5758329232eSGordon Ross 	}
5768329232eSGordon Ross 	rname = argv[1];
5778329232eSGordon Ross 	if (argc > 2) {
5788329232eSGordon Ross 		lname = argv[2];
5798329232eSGordon Ross 		/*
5808329232eSGordon Ross 		 * When local name is specified, overwrite.
5818329232eSGordon Ross 		 * Convenient for scripts etc.
5828329232eSGordon Ross 		 */
5838329232eSGordon Ross 		oflg |= O_TRUNC;
5848329232eSGordon Ross 	} else {
5858329232eSGordon Ross 		lname = rname;
5868329232eSGordon Ross 		/* Local file should not exist. */
5878329232eSGordon Ross 		oflg |= O_EXCL;
5888329232eSGordon Ross 	}
5898329232eSGordon Ross 
5908329232eSGordon Ross 	lfd = open(lname, oflg, 0644);
5918329232eSGordon Ross 	if (lfd < 0) {
5928329232eSGordon Ross 		perror(lname);
5938329232eSGordon Ross 		return;
5948329232eSGordon Ross 	}
5958329232eSGordon Ross 
5968329232eSGordon Ross 	error = vn_open(rname, 0, FREAD, 0, &vp, 0, 0);
5978329232eSGordon Ross 	if (error != 0) {
5988329232eSGordon Ross 		fprintf(stderr, "do_get, vn_open error=%d\n", error);
5998329232eSGordon Ross 		goto out;
6008329232eSGordon Ross 	}
6018329232eSGordon Ross 	error = fake_stat(vp, &st, 0);
6028329232eSGordon Ross 	if (error != 0) {
6038329232eSGordon Ross 		fprintf(stderr, "do_get, stat error=%d\n", error);
6048329232eSGordon Ross 		goto out;
6058329232eSGordon Ross 	}
6068329232eSGordon Ross 
6078329232eSGordon Ross 	off = 0;
6088329232eSGordon Ross 	do {
6098329232eSGordon Ross 		cnt = fake_pread(vp, tbuf, TBUFSZ, off);
6108329232eSGordon Ross 		if (cnt < 0) {
6118329232eSGordon Ross 			fprintf(stderr, "do_get, read %d\n", -cnt);
6128329232eSGordon Ross 			goto out;
6138329232eSGordon Ross 		}
6148329232eSGordon Ross 		x = write(lfd, tbuf, cnt);
6158329232eSGordon Ross 		if (x < 0) {
6168329232eSGordon Ross 			fprintf(stderr, "do_get, write %d\n", errno);
6178329232eSGordon Ross 			goto out;
6188329232eSGordon Ross 		}
6198329232eSGordon Ross 		off += x;
6208329232eSGordon Ross 	} while (off < st.st_size);
6218329232eSGordon Ross 
6228329232eSGordon Ross out:
6238329232eSGordon Ross 	if (vp != NULL)
6248329232eSGordon Ross 		vn_close_rele(vp, 0);
6258329232eSGordon Ross 	if (lfd != -1)
6268329232eSGordon Ross 		close(lfd);
6278329232eSGordon Ross }
6288329232eSGordon Ross 
6298329232eSGordon Ross /*
6308329232eSGordon Ross  * put lname [rname]
6318329232eSGordon Ross  */
6328329232eSGordon Ross void
do_put(int argc,char ** argv)6338329232eSGordon Ross do_put(int argc, char **argv)
6348329232eSGordon Ross {
6358329232eSGordon Ross 	struct stat64 rst;
6368329232eSGordon Ross 	struct stat st;
6378329232eSGordon Ross 	char *rname;
6388329232eSGordon Ross 	char *lname;
6398329232eSGordon Ross 	vnode_t *vp = NULL;
6408329232eSGordon Ross 	offset_t off;
6418329232eSGordon Ross 	ssize_t cnt, x;
6428329232eSGordon Ross 	int oflg = FREAD|FWRITE|FCREAT;
6438329232eSGordon Ross 	int lfd = -1;
6448329232eSGordon Ross 	int error;
6458329232eSGordon Ross 
6468329232eSGordon Ross 	if (vfsp == NULL) {
6478329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
6488329232eSGordon Ross 		return;
6498329232eSGordon Ross 	}
6508329232eSGordon Ross 	if (argc < 2) {
6518329232eSGordon Ross 		fprintf(stderr, "lname required\n");
6528329232eSGordon Ross 		return;
6538329232eSGordon Ross 	}
6548329232eSGordon Ross 	lname = argv[1];
6558329232eSGordon Ross 	if (argc > 2) {
6568329232eSGordon Ross 		rname = argv[2];
6578329232eSGordon Ross 		/*
6588329232eSGordon Ross 		 * When remote name is specified, overwrite.
6598329232eSGordon Ross 		 * Convenient for scripts etc.
6608329232eSGordon Ross 		 */
6618329232eSGordon Ross 		oflg |= FTRUNC;
6628329232eSGordon Ross 	} else {
6638329232eSGordon Ross 		rname = lname;
6648329232eSGordon Ross 		/* Remote file should not exist. */
6658329232eSGordon Ross 		oflg |= FEXCL;
6668329232eSGordon Ross 	}
6678329232eSGordon Ross 
6688329232eSGordon Ross 	lfd = open(lname, O_RDONLY, 0);
6698329232eSGordon Ross 	if (lfd < 0) {
6708329232eSGordon Ross 		perror(lname);
6718329232eSGordon Ross 		return;
6728329232eSGordon Ross 	}
6738329232eSGordon Ross 	error = fstat(lfd, &st);
6748329232eSGordon Ross 	if (error != 0) {
6758329232eSGordon Ross 		fprintf(stderr, "do_put, stat error=%d\n", error);
6768329232eSGordon Ross 		goto out;
6778329232eSGordon Ross 	}
6788329232eSGordon Ross 
6798329232eSGordon Ross 	error = vn_open(rname, 0, oflg, 0, &vp, 0, 0);
6808329232eSGordon Ross 	if (error != 0) {
6818329232eSGordon Ross 		fprintf(stderr, "do_put, vn_open error=%d\n", error);
6828329232eSGordon Ross 		goto out;
6838329232eSGordon Ross 	}
6848329232eSGordon Ross 
6858329232eSGordon Ross 	off = 0;
6868329232eSGordon Ross 	do {
6878329232eSGordon Ross 		cnt = pread(lfd, tbuf, TBUFSZ, off);
6888329232eSGordon Ross 		if (cnt < 0) {
6898329232eSGordon Ross 			fprintf(stderr, "do_put, read %d\n", errno);
6908329232eSGordon Ross 			goto out;
6918329232eSGordon Ross 		}
6928329232eSGordon Ross 		x = fake_pwrite(vp, tbuf, cnt, off);
6938329232eSGordon Ross 		if (x < 0) {
6948329232eSGordon Ross 			fprintf(stderr, "do_put, write %d\n", -x);
6958329232eSGordon Ross 			goto out;
6968329232eSGordon Ross 		}
6978329232eSGordon Ross 		off += cnt;
6988329232eSGordon Ross 	} while (off < st.st_size);
6998329232eSGordon Ross 
7008329232eSGordon Ross 	/* This getattr should go OtW. */
7018329232eSGordon Ross 	error = fake_stat(vp, &rst, 0);
7028329232eSGordon Ross 	if (error != 0) {
7038329232eSGordon Ross 		fprintf(stderr, "do_put, stat error=%d\n", error);
7048329232eSGordon Ross 		goto out;
7058329232eSGordon Ross 	}
7068329232eSGordon Ross 	if (rst.st_size != st.st_size) {
7078329232eSGordon Ross 		fprintf(stderr, "do_put, wrong size?\n");
7088329232eSGordon Ross 	}
7098329232eSGordon Ross 
7108329232eSGordon Ross out:
7118329232eSGordon Ross 	if (vp != NULL)
7128329232eSGordon Ross 		vn_close_rele(vp, 0);
7138329232eSGordon Ross 	if (lfd != -1)
7148329232eSGordon Ross 		close(lfd);
7158329232eSGordon Ross }
7168329232eSGordon Ross 
7178329232eSGordon Ross /*
7188329232eSGordon Ross  * rm rname
7198329232eSGordon Ross  */
7208329232eSGordon Ross void
do_rm(int argc,char ** argv)7218329232eSGordon Ross do_rm(int argc, char **argv)
7228329232eSGordon Ross {
7238329232eSGordon Ross 	char *rname;
7248329232eSGordon Ross 	int error;
7258329232eSGordon Ross 
7268329232eSGordon Ross 	if (vfsp == NULL) {
7278329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
7288329232eSGordon Ross 		return;
7298329232eSGordon Ross 	}
7308329232eSGordon Ross 	if (argc < 2) {
7318329232eSGordon Ross 		fprintf(stderr, "rname required\n");
7328329232eSGordon Ross 		return;
7338329232eSGordon Ross 	}
7348329232eSGordon Ross 	rname = argv[1];
7358329232eSGordon Ross 
7368329232eSGordon Ross 	error = fake_unlink(rname, 0);
7378329232eSGordon Ross 	if (error != 0) {
7388329232eSGordon Ross 		fprintf(stderr, "do_rm, unlink error=%d\n", error);
7398329232eSGordon Ross 	}
7408329232eSGordon Ross }
7418329232eSGordon Ross 
7428329232eSGordon Ross /*
7438329232eSGordon Ross  * mv fromname toname
7448329232eSGordon Ross  */
7458329232eSGordon Ross void
do_mv(int argc,char ** argv)7468329232eSGordon Ross do_mv(int argc, char **argv)
7478329232eSGordon Ross {
7488329232eSGordon Ross 	int error;
7498329232eSGordon Ross 
7508329232eSGordon Ross 	if (vfsp == NULL) {
7518329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
7528329232eSGordon Ross 		return;
7538329232eSGordon Ross 	}
7548329232eSGordon Ross 	if (argc < 3) {
7558329232eSGordon Ross 		fprintf(stderr, "from_name to_name required\n");
7568329232eSGordon Ross 		return;
7578329232eSGordon Ross 	}
7588329232eSGordon Ross 
7598329232eSGordon Ross 	error = fake_rename(argv[1], argv[2]);
7608329232eSGordon Ross 	if (error != 0) {
7618329232eSGordon Ross 		fprintf(stderr, "do_mv, rename error=%d\n", error);
7628329232eSGordon Ross 	}
7638329232eSGordon Ross }
7648329232eSGordon Ross 
7658329232eSGordon Ross /*
7668329232eSGordon Ross  * mkdir rname
7678329232eSGordon Ross  */
7688329232eSGordon Ross void
do_mkdir(int argc,char ** argv)7698329232eSGordon Ross do_mkdir(int argc, char **argv)
7708329232eSGordon Ross {
7718329232eSGordon Ross 	char *rname;
7728329232eSGordon Ross 	vnode_t *vp = NULL;
7738329232eSGordon Ross 	int error;
7748329232eSGordon Ross 
7758329232eSGordon Ross 	if (vfsp == NULL) {
7768329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
7778329232eSGordon Ross 		return;
7788329232eSGordon Ross 	}
7798329232eSGordon Ross 	if (argc < 2) {
7808329232eSGordon Ross 		fprintf(stderr, "rname required\n");
7818329232eSGordon Ross 		return;
7828329232eSGordon Ross 	}
7838329232eSGordon Ross 	rname = argv[1];
7848329232eSGordon Ross 
7858329232eSGordon Ross 	error = vn_open(rname, 0, FCREAT, 0, &vp, CRMKDIR, 0);
7868329232eSGordon Ross 	if (error != 0) {
7878329232eSGordon Ross 		fprintf(stderr, "do_mkdir, vn_open error=%d\n", error);
7888329232eSGordon Ross 	}
7898329232eSGordon Ross 
7908329232eSGordon Ross 	if (vp != NULL)
7918329232eSGordon Ross 		vn_close_rele(vp, 0);
7928329232eSGordon Ross }
7938329232eSGordon Ross 
7948329232eSGordon Ross /*
7958329232eSGordon Ross  * rmdir rname
7968329232eSGordon Ross  */
7978329232eSGordon Ross void
do_rmdir(int argc,char ** argv)7988329232eSGordon Ross do_rmdir(int argc, char **argv)
7998329232eSGordon Ross {
8008329232eSGordon Ross 	char *rname;
8018329232eSGordon Ross 	int error;
8028329232eSGordon Ross 
8038329232eSGordon Ross 	if (vfsp == NULL) {
8048329232eSGordon Ross 		fprintf(stderr, "mnt required first\n");
8058329232eSGordon Ross 		return;
8068329232eSGordon Ross 	}
8078329232eSGordon Ross 	if (argc < 2) {
8088329232eSGordon Ross 		fprintf(stderr, "rname required\n");
8098329232eSGordon Ross 		return;
8108329232eSGordon Ross 	}
8118329232eSGordon Ross 	rname = argv[1];
8128329232eSGordon Ross 
8138329232eSGordon Ross 	error = fake_unlink(rname, AT_REMOVEDIR);
8148329232eSGordon Ross 	if (error != 0) {
8158329232eSGordon Ross 		fprintf(stderr, "do_rmdir, unlink error=%d\n", error);
8168329232eSGordon Ross 	}
8178329232eSGordon Ross }
8188329232eSGordon Ross 
8198329232eSGordon Ross /*
8208329232eSGordon Ross  * Simple option setting
8218329232eSGordon Ross  *
8228329232eSGordon Ross  * Each arg is handled as one line in .nsmbrc [default]
8238329232eSGordon Ross  */
8248329232eSGordon Ross void
do_opt(int argc,char ** argv)8258329232eSGordon Ross do_opt(int argc, char **argv)
8268329232eSGordon Ross {
8278329232eSGordon Ross 	static char template[20] = "/tmp/fksmbclXXXXXX";
8288329232eSGordon Ross 	static char rcname[30];
8298329232eSGordon Ross 	char *tdname;
8308329232eSGordon Ross 	char *save_home;
8318329232eSGordon Ross 	FILE *fp;
8328329232eSGordon Ross 	int err, i;
8338329232eSGordon Ross 
8348329232eSGordon Ross 	if (argc < 2) {
8358329232eSGordon Ross 		fprintf(stderr, "opt {key}[=value]\n");
8368329232eSGordon Ross 		return;
8378329232eSGordon Ross 	}
8388329232eSGordon Ross 
8398329232eSGordon Ross 	tdname = mkdtemp(template);
8408329232eSGordon Ross 	if (tdname == NULL) {
8418329232eSGordon Ross 		perror("mkdtemp");
8428329232eSGordon Ross 		return;
8438329232eSGordon Ross 	}
8448329232eSGordon Ross 	(void) snprintf(rcname, sizeof (rcname),
8458329232eSGordon Ross 	    "%s/.nsmbrc", tdname);
8468329232eSGordon Ross 
8478329232eSGordon Ross 	fp = fopen(rcname, "w");
8488329232eSGordon Ross 	if (fp == NULL) {
8498329232eSGordon Ross 		perror(rcname);
8508329232eSGordon Ross 		goto out;
8518329232eSGordon Ross 	}
8528329232eSGordon Ross 	fprintf(fp, "[default]\n");
8538329232eSGordon Ross 	for (i = 1; i < argc; i++)
8548329232eSGordon Ross 		fprintf(fp, "%s\n", argv[i]);
8558329232eSGordon Ross 	fclose(fp);
8568329232eSGordon Ross 
8578329232eSGordon Ross 	save_home = ctx->ct_home;
8588329232eSGordon Ross 	ctx->ct_home = tdname;
8598329232eSGordon Ross 	err = smb_ctx_readrc(ctx);
8608329232eSGordon Ross 	ctx->ct_home = save_home;
8618329232eSGordon Ross 
8628329232eSGordon Ross 	if (err != 0)
8638329232eSGordon Ross 		fprintf(stderr, "readrc, err=%d\n", err);
8648329232eSGordon Ross 
8658329232eSGordon Ross out:
8668329232eSGordon Ross 	(void) unlink(rcname);
8678329232eSGordon Ross 	(void) rmdir(tdname);
8688329232eSGordon Ross }
8698329232eSGordon Ross 
8708329232eSGordon Ross /*
8718329232eSGordon Ross  * Command table
8728329232eSGordon Ross  */
8738329232eSGordon Ross static struct cmd_tbl_ent
8748329232eSGordon Ross cmd_tbl[] = {
8758329232eSGordon Ross 	{ do_help,	"help", "" },
8768329232eSGordon Ross 	{ do_exit,	"exit", "" },
8778329232eSGordon Ross 	{ do_logon,	"logon", "[user [dom [pass]]]" },
8788329232eSGordon Ross 	{ do_logoff,	"logoff", "[close-driver]" },
8798329232eSGordon Ross 	{ do_shares,	"shares", "" },
8808329232eSGordon Ross 	{ do_mount,	"mount",  "{share} [optstr]" },
8818329232eSGordon Ross 	{ do_unmount,	"umount", "" },
8828329232eSGordon Ross 	{ do_unmount,	"unmount", "" },
8838329232eSGordon Ross 	{ do_statfs,	"statfs", "" },
8848329232eSGordon Ross 	{ do_dir,	"dir",  "{rdir} [lfile]" },
8858329232eSGordon Ross 	{ do_dirx,	"dirx", "{rdir} [lfile]" },
8868329232eSGordon Ross 	{ do_get,	"get",  "{rfile} [lfile]" },
8878329232eSGordon Ross 	{ do_put,	"put",  "{lfile} [rfile]" },
8888329232eSGordon Ross 	{ do_mv,	"mv",   "{from} {to}" },
8898329232eSGordon Ross 	{ do_rm,	"rm",   "{rfile}" },
8908329232eSGordon Ross 	{ do_mkdir,	"mkdir", "{rfile}" },
8918329232eSGordon Ross 	{ do_rmdir,	"rmdir", "{rfile}" },
8928329232eSGordon Ross 	{ do_opt,	"opt",   "{option}" },
8938329232eSGordon Ross 	{ NULL, NULL, NULL }
8948329232eSGordon Ross };
8958329232eSGordon Ross 
8968329232eSGordon Ross /*
8978329232eSGordon Ross  * Provide a real function (one that prints something) to replace
8988329232eSGordon Ross  * the stub in libfakekernel.  This prints cmn_err() messages.
8998329232eSGordon Ross  */
9008329232eSGordon Ross void
fakekernel_putlog(char * msg,size_t len,int flags)9018329232eSGordon Ross fakekernel_putlog(char *msg, size_t len, int flags)
9028329232eSGordon Ross {
9038329232eSGordon Ross 
9048329232eSGordon Ross 	/*
9058329232eSGordon Ross 	 * [CE_CONT, CE_NOTE, CE_WARN, CE_PANIC] maps to
9068329232eSGordon Ross 	 * [SL_NOTE, SL_NOTE, SL_WARN, SL_FATAL]
9078329232eSGordon Ross 	 */
9088329232eSGordon Ross 	if (smb_debug == 0 && (flags & SL_NOTE))
9098329232eSGordon Ross 		return;
9108329232eSGordon Ross 	(void) fwrite(msg, 1, len, stdout);
9118329232eSGordon Ross 	(void) fflush(stdout);
9128329232eSGordon Ross }
9138329232eSGordon Ross 
914adee6784SGordon Ross /*
915adee6784SGordon Ross  * Print nsmb debug messages via driver smb_debugmsg()
916adee6784SGordon Ross  */
917adee6784SGordon Ross void
smb_debugmsg(const char * func,char * msg)918adee6784SGordon Ross smb_debugmsg(const char *func, char *msg)
919adee6784SGordon Ross {
920adee6784SGordon Ross 	if (smb_debug < 2)
921adee6784SGordon Ross 		return;
922adee6784SGordon Ross 	printf("[kmod] %s: %s\n", func, msg);
923adee6784SGordon Ross }
924adee6784SGordon Ross 
9258329232eSGordon Ross /*
9268329232eSGordon Ross  * Enable libumem debugging
9278329232eSGordon Ross  */
9288329232eSGordon Ross const char *
_umem_debug_init(void)9298329232eSGordon Ross _umem_debug_init(void)
9308329232eSGordon Ross {
9318329232eSGordon Ross 	return ("default,verbose"); /* $UMEM_DEBUG setting */
9328329232eSGordon Ross }
9338329232eSGordon Ross 
9348329232eSGordon Ross const char *
_umem_logging_init(void)9358329232eSGordon Ross _umem_logging_init(void)
9368329232eSGordon Ross {
9378329232eSGordon Ross 	return ("fail,contents"); /* $UMEM_LOGGING setting */
9388329232eSGordon Ross }
939