From a51e71fc6404cce20fb3160828339af5ae86a54f Mon Sep 17 00:00:00 2001 From: Boris Popov Date: Fri, 15 Oct 1999 09:59:48 +0000 Subject: [PATCH] Add mount_nwfs program. Now -current can mount NetWare volumes. --- sbin/Makefile | 2 +- sbin/mount_nwfs/Makefile | 15 ++ sbin/mount_nwfs/mount_nwfs.8 | 191 ++++++++++++++++ sbin/mount_nwfs/mount_nwfs.c | 372 +++++++++++++++++++++++++++++++ usr.sbin/mount_nwfs/Makefile | 15 ++ usr.sbin/mount_nwfs/mount_nwfs.8 | 191 ++++++++++++++++ usr.sbin/mount_nwfs/mount_nwfs.c | 372 +++++++++++++++++++++++++++++++ 7 files changed, 1157 insertions(+), 1 deletion(-) create mode 100644 sbin/mount_nwfs/Makefile create mode 100644 sbin/mount_nwfs/mount_nwfs.8 create mode 100644 sbin/mount_nwfs/mount_nwfs.c create mode 100644 usr.sbin/mount_nwfs/Makefile create mode 100644 usr.sbin/mount_nwfs/mount_nwfs.8 create mode 100644 usr.sbin/mount_nwfs/mount_nwfs.c diff --git a/sbin/Makefile b/sbin/Makefile index 08ba69997d41..7a39140ff42d 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -63,7 +63,7 @@ SUBDIR= adjkerntz \ vinum .if ${MACHINE_ARCH} == i386 -SUBDIR+= kget +SUBDIR+= kget mount_nwfs .endif .if exists(${.CURDIR}/${MACHINE_ARCH}) diff --git a/sbin/mount_nwfs/Makefile b/sbin/mount_nwfs/Makefile new file mode 100644 index 000000000000..53405963beb7 --- /dev/null +++ b/sbin/mount_nwfs/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + +PROG= mount_nwfs +SRCS= mount_nwfs.c getmntopts.c +MAN8= mount_nwfs.8 + +MOUNT= ${.CURDIR}/../mount +CFLAGS+= -DNWFS -I${MOUNT} + +.PATH: ${MOUNT} + +LDADD+= -lncp -lipx +DPADD+= ${LIBIPX} ${LIBNCP} + +.include diff --git a/sbin/mount_nwfs/mount_nwfs.8 b/sbin/mount_nwfs/mount_nwfs.8 new file mode 100644 index 000000000000..83a880f3882f --- /dev/null +++ b/sbin/mount_nwfs/mount_nwfs.8 @@ -0,0 +1,191 @@ +.\" $FreeBSD$ +.Dd Oct 14, 1999 +.Dt MOUNT_NWFS 8 +.Os FreeBSD 4.0 +.Sh NAME +.Nm mount_nwfs +.Nd mount NetWare volume from a NetWare file server +.Sh SYNOPSIS +.Nm mount_nwfs +.Op Fl Chv +.Ar -S Ar server +.Ar -U Ar user +.Ar "[connection options]" +.Ar -V Ar volume +.Op Fl M Ar mode +.Op Fl c Ar case +.Op Fl d Ar mode +.Op Fl f Ar mode +.Op Fl g Ar gid +.Op Fl l Ar locale +.Op Fl n Ar os2 +.Op Fl u Ar uid +.Op Fl w Ar scheme +.Ar node +.Nm mount_nwfs +.Op Fl options +.Ar /server:user/volume/path +.Ar node +.Sh DESCRIPTION +The +.Nm +command allow to mount volume from a NetWare server. It may use either +existing connection or create new: if no usable connection was found +it will try to establish a new one. Connection has count of references to it, +so when last mount will be dismounted connection will be closed. It is +possible to create connection without any mounts (but use it for them) with +.Xr ncplogin 1 . +.Pp +Note two forms of command line. In the first form, server and user specified +via +.Fl S +and +.Fl U +options respectively. In the second form server and user specified in +.Ar special +part of +.Xr mount 8 +command line arguments (the +.Fl S , +.Fl U +and +.Fl V +options aren't used in this case). This allows use of fstab file (see EXAMPLES below). +.Pp +The options are: +.Bl -tag -width indent +.It Fl S Ar server +name of NetWare server to connect. For native IP you will need also +.Fl A +option. +.It Fl U Ar user +name of user used in login sequence. +.It Fl "[connection options]" +See +.Xr ncplogin 1 +for details. +.It Fl V Ar volume +Volume name to mount. Volume name can also be specified after all options and +before +.Ar mount-point . +.It Ar node +Path to mount volume. +.It Fl c Ar case +Selects a +.Ar case +option which affects on name representation. +.Ar Case +can be one of the following: +.Bd -literal -offset indent +Value Meaning +l All existing file names converted to lower case. + Newly created file gets a lower case under OS2 name + space. This is default when mounting volumes with DOS + name space. +L Same as 'l' but file system tries to be case + insensitive. May not work well. +n No case conversion is performed. + Warning! Warning!: use this option with DOS name + space only as a last resort, because creating a lower + case name in the DOS name space can lead to an + unpredictable results. This is default when mounting + volume with OS2 name space. +u All existing file names converted to upper case. Newly + created file gets an upper case under OS2 name space. +U Same as 'u' but file system tries to be case insensitive. + May not work well. +.Ed +.It Fl f Ar mode, Fl d Ar mode +specifies permissions that should be assigned to files and directories. +The values must be specified as octal numbers. Default value for the file mode +taken from mount point, default value for the dir mode adds execute permission +where the file mode gives read permission. + +Note that these permissions can differ from the rights granted by NetWare +server. +.It Fl n Ar namespace +don't use +.Ar namespace . +Currently only +.Ar OS2 +can be here. +.It Fl v +prints version number. +.It Fl u Ar uid, Fl g Ar gid +User id and group id assigned to files. The default is owner and group id from +directory where volume is mounted. +.It Fl l Ar locale +Sets the locale for case conversion. By default +.Nm +tries to use an environment variable +.Ar LC_* . +.It Fl w Ar scheme +Selects a +.Ar scheme +used to convert file names between NetWare and FreeBSD. Currently only +.Ar koi2cp866 +and +.Ar asis +can be here. Please note, that scheme should be enabled at compile +time in config.mk file. +.It Fl M Ar mode +See +.Xr ncplogin 1 +for details. If this option is ommited, connection permissions +assumed the same as directory mode ( +.Ar -d ) +option. +.El +.Sh FILES +.Bl -tag -width /var/log/wtmp -compact +.It Pa ~/.nwfsrc +keeps description for each connection. See +.Xr nwfsrc 8 +for details. + +.Sh NOTES +Before any NCP connection can be established kernel must be configured +for IPX support, IPXrouted and KLD nwfs.ko should be loaded. +.Sh EXAMPLES +Next examples illustrates how to connect to NetWare server +.Ar nwserv +as user +.Ar GUEST +and mount volumes +.Ar SYS +and +.Ar VOL1 : +.Bd -literal -offset indent +mount_nwfs -S nwserv -U guest -V sys /nw/s1/sys +mount_nwfs /nwserv:guest/sys /nw/s1/sys +mount -t nwfs /nwserv:guest/vol1 /nw/s1/vol1 +mount -t nwfs /nwserv:boris/sys/home/boris /home/boris/nw/home +.Ed +.Pp +The last example mounts only subdirectory on a volume and equivalent +to NetWare 'map root' command. +.Pp +It is possible to use fstab for nwfs mounts: +.Bd -literal -offset indent +/nwserv:guest/sys /nw/s1/sys nwfs rw,noauto 0 0 +/nwserv:guest/vol1 /nw/s1/vol2 nwfs rw,noauto 0 0 +.Ed + +.Sh BUGS +to number a few + +.Sh CREDITS +In development of NetWare client for FreeBSD next sources was used: +.Pp +Documentation from NetWare NDK. +.Pp +ncpfs for Linux - written by Volker Lendecke (lendecke@math.uni-goettingen.de). +He grants me permission to publish parts of his code under BSD-style license, +.Pp +"Interrupt List" from Ralf Brown, +.Pp +Many files from /sys directory. + +.Sh AUTHOR +.An Boris Popov Aq bp@butya.kz , +.Aq rbp@chat.ru diff --git a/sbin/mount_nwfs/mount_nwfs.c b/sbin/mount_nwfs/mount_nwfs.c new file mode 100644 index 000000000000..363b8cc0200a --- /dev/null +++ b/sbin/mount_nwfs/mount_nwfs.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 1999, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "mntopts.h" + +#define NWFS_VFSNAME "nwfs" + +extern char *__progname; +static char mount_point[MAXPATHLEN + 1]; +static void usage(void); +static int parsercfile(struct ncp_conn_loginfo *li, struct nwfs_args *mdata); + +static struct mntopt mopts[] = { + MOPT_STDOPTS, + { NULL } +}; + +static int +parsercfile(struct ncp_conn_loginfo *li, struct nwfs_args *mdata) { + return 0; +} + +int +main(int argc, char *argv[]) { + int opt, error, mntflags, nlsopt; + char *p, *p1, tmp[1024]; + u_char *pv; + NWCONN_HANDLE connHandle; + struct nwfs_args mdata; + struct ncp_conn_loginfo li; + struct stat st; + struct vfsconf vfc; + struct nw_entry_info einfo; + + if (argc < 2) { + usage(); + exit(1); + } + if (argc == 2) { + if (strcmp(argv[1], "-h") == 0) { + usage(); + exit(0); + } else if (strcmp(argv[1], "-v") == 0) { + errx(EX_OK, "version %d.%d.%d", NWFS_VERSION / 100000, + (NWFS_VERSION % 10000) / 1000, + (NWFS_VERSION % 1000) / 100); + } + } + + error = getvfsbyname(NWFS_VFSNAME, &vfc); + if (error && vfsisloadable(NWFS_VFSNAME)) { + if(vfsload(NWFS_VFSNAME)) + err(EX_OSERR, "vfsload("NWFS_VFSNAME")"); + endvfsent(); + error = getvfsbyname(NWFS_VFSNAME, &vfc); + } + if (error) + errx(EX_OSERR, "NetWare filesystem is not available"); + + if(ncp_initlib()) exit(1); + + mntflags = error = 0; + bzero(&mdata,sizeof(mdata)); + mdata.uid = mdata.gid = -1; + nlsopt = 0; + + if (ncp_li_init(&li, argc, argv)) return 1; + /* + * A little bit weird, but I should figure out which server/user to use + * _before_ reading .rc file + */ + if (argc >= 3 && argv[argc-1][0] != '-' && argv[argc-2][0] != '-' && + argv[argc-2][0] == '/') { + p = argv[argc-2]; + error = 1; + do { + if (*p++ != '/') break; + p1 = tmp; + while (*p != ':' && *p != 0) *p1++ = *p++; + if (*p++ == 0) break; + *p1 = 0; + if (ncp_li_setserver(&li, tmp)) break; + p1 = tmp; + while (*p != '/' && *p != 0) *p1++ = *p++; + if (*p++ == 0) break; + *p1 = 0; + if (ncp_li_setuser(&li, tmp)) break; + p1 = tmp; + while (*p != '/' && *p != 0) *p1++ = *p++; + *p1 = 0; + if (strlen(tmp) > NCP_VOLNAME_LEN) { + fprintf(stderr, "Volume name too long: %s\n", tmp); + break; + } + ncp_str_upper(strcpy(mdata.mounted_vol,tmp)); + if (*p == '/') + p++; + p1 = mdata.root_path + 2; + pv = mdata.root_path + 1; + for(;*p;) { + *pv = 0; + while (*p != '/' && *p) { + *p1++ = *p++; + (*pv)++; + } + if (*pv) { + ncp_nls_mem_u2n(pv + 1, pv + 1, *pv); + pv += (*pv) + 1; + mdata.root_path[0]++; + } + if (*p++ == 0) break; + p1++; + } + error = 0; + } while(0); + if (error) + errx(EX_DATAERR, + "An error occured while parsing '%s'", + argv[argc - 2]); + } + if (ncp_li_readrc(&li)) return 1; + if (ncp_rc) { + parsercfile(&li,&mdata); + rc_close(ncp_rc); + } + while ((opt = getopt(argc, argv, STDPARAM_OPT"V:c:d:f:g:l:n:o:u:w:")) != EOF) { + switch (opt) { + case STDPARAM_ARGS: + if (ncp_li_arg(&li, opt, optarg)) { + return 1; + } + break; + case 'V': + if (strlen(optarg) > NCP_VOLNAME_LEN) + errx(EX_DATAERR, "Volume too long: %s\n", optarg); + ncp_str_upper(strcpy(mdata.mounted_vol,optarg)); + break; + case 'u': { + struct passwd *pwd; + + pwd = isdigit(optarg[0]) ? + getpwuid(atoi(optarg)) : getpwnam(optarg); + if (pwd == NULL) + errx(EX_NOUSER, "unknown user '%s'", optarg); + mdata.uid = pwd->pw_uid; + break; + } + case 'g': { + struct group *grp; + + grp = isdigit(optarg[0]) ? + getgrgid(atoi(optarg)) : getgrnam(optarg); + if (grp == NULL) + errx(EX_NOUSER, "unknown group '%s'", optarg); + mdata.gid = grp->gr_gid; + break; + } + case 'd': + errno = 0; + mdata.dir_mode = strtol(optarg, &p, 8); + if (errno || *p != 0) + errx(EX_DATAERR, "invalid value for directory mode"); + break; + case 'f': + errno = 0; + mdata.file_mode = strtol(optarg, &p, 8); + if (errno || *p != 0) + errx(EX_DATAERR, "invalid value for file mode"); + break; + case '?': + usage(); + exit(1); /*NOTREACHED*/ + case 'n': { + char *inp, *nsp; + + nsp = inp = optarg; + while ((nsp = strsep(&inp, ",;:")) != NULL) { + if (strcasecmp(nsp, "OS2") == 0) + mdata.flags |= NWFS_MOUNT_NO_OS2; + else if (strcasecmp(nsp, "LONG") == 0) + mdata.flags |= NWFS_MOUNT_NO_LONG; + else if (strcasecmp(nsp, "NFS") == 0) + mdata.flags |= NWFS_MOUNT_NO_NFS; + else + errx(EX_DATAERR, "Unknown namespace '%s'", nsp); + } + break; + }; + case 'l': + if (ncp_nls_setlocale(optarg) != 0) return 1; + mdata.flags |= NWFS_MOUNT_HAVE_NLS; + break; + case 'o': + getmntopts(optarg, mopts, &mntflags, 0); + break; + case 'c': + switch (optarg[0]) { + case 'l': + nlsopt |= NWHP_LOWER; + break; + case 'u': + nlsopt |= NWHP_UPPER; + break; + case 'n': + nlsopt |= NWHP_LOWER | NWHP_UPPER; + break; + case 'L': + nlsopt |= NWHP_LOWER | NWHP_NOSTRICT; + break; + case 'U': + nlsopt |= NWHP_UPPER | NWHP_NOSTRICT; + break; + default: + errx(EX_DATAERR, "invalid suboption '%c' for -c", + optarg[0]); + } + break; + case 'w': + if (ncp_nls_setrecodebyname(optarg) != 0) + return 1; + mdata.flags |= NWFS_MOUNT_HAVE_NLS; + break; + default: + usage(); + return 1; + } + } + + if (optind == argc - 2) { + optind++; + } else if (mdata.mounted_vol[0] == 0) + errx(EX_USAGE, "Volume name should be specified"); + + if (optind != argc - 1) { + usage(); + return 1; + } + realpath(argv[optind], mount_point); + + if (stat(mount_point, &st) == -1) + err(EX_OSERR, "could not find mount point %s", mount_point); + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + err(EX_OSERR, "can't mount on %s", mount_point); + } + if (ncp_geteinfo(mount_point, &einfo) == 0) + errx(EX_OSERR, "can't mount on %s twice", mount_point); + + if (mdata.uid == -1) { + mdata.uid = st.st_uid; + } + if (mdata.gid == -1) { + mdata.gid = st.st_gid; + } + if (mdata.file_mode == 0 ) { + mdata.file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + if (mdata.dir_mode == 0) { + mdata.dir_mode = mdata.file_mode; + if ((mdata.dir_mode & S_IRUSR) != 0) + mdata.dir_mode |= S_IXUSR; + if ((mdata.dir_mode & S_IRGRP) != 0) + mdata.dir_mode |= S_IXGRP; + if ((mdata.dir_mode & S_IROTH) != 0) + mdata.dir_mode |= S_IXOTH; + } + if (li.access_mode == 0) { + li.access_mode = mdata.dir_mode; + } +/* if (mdata.flags & NWFS_MOUNT_HAVE_NLS) {*/ + mdata.nls = ncp_nls; +/* }*/ + mdata.nls.opt = nlsopt; + error = ncp_li_check(&li); + if (error) + return 1; + li.opt |= NCP_OPT_WDOG; + /* well, now we can try to login, or use already established connection */ + error = ncp_li_login(&li,&connHandle); + if( error ){ + fprintf(stderr,"Cannot login to server %s,%s\n",li.server,strerror(errno)); + ncp_disconnect(connHandle); + return(1); + } + error = ncp_conn2ref(connHandle, &mdata.connRef); + if (error) { + fprintf(stderr,"Cannot convert handle to refernce. Consider this as a big bug.\n"); + ncp_disconnect(connHandle); + return(1); + } + strcpy(mdata.mount_point,mount_point); + mdata.version = NWFS_VERSION; + error = mount(NWFS_VFSNAME, mdata.mount_point, mntflags, (void*)&mdata); + if (error) { + fprintf(stderr,"mount error: %s\n", strerror(errno)); + ncp_disconnect(connHandle); + exit(1); + } + /* + * I'm leave along my handle, but kernel should keep own ... + */ + ncp_disconnect(connHandle); + /* we are done ?, impossible ... */ + return 0; +} + +static void +usage(void) { + printf("usage: %s [connection options] [options] \n" + " server:user/volume[/path] mount-point\n\n", __progname); + printf( + "see ncplogin(1) for details on connection options\n" + " -A host Netware/IP host address\n" + " -u uid uid the mounted files get\n" + " -g gid gid the mounted files get\n" + " -f mode permission the files get\n" + " -d mode permission the dirs get\n" + " -h print this help text\n" + " -v print nwfs version number\n" + "\n" + ); +} diff --git a/usr.sbin/mount_nwfs/Makefile b/usr.sbin/mount_nwfs/Makefile new file mode 100644 index 000000000000..53405963beb7 --- /dev/null +++ b/usr.sbin/mount_nwfs/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + +PROG= mount_nwfs +SRCS= mount_nwfs.c getmntopts.c +MAN8= mount_nwfs.8 + +MOUNT= ${.CURDIR}/../mount +CFLAGS+= -DNWFS -I${MOUNT} + +.PATH: ${MOUNT} + +LDADD+= -lncp -lipx +DPADD+= ${LIBIPX} ${LIBNCP} + +.include diff --git a/usr.sbin/mount_nwfs/mount_nwfs.8 b/usr.sbin/mount_nwfs/mount_nwfs.8 new file mode 100644 index 000000000000..83a880f3882f --- /dev/null +++ b/usr.sbin/mount_nwfs/mount_nwfs.8 @@ -0,0 +1,191 @@ +.\" $FreeBSD$ +.Dd Oct 14, 1999 +.Dt MOUNT_NWFS 8 +.Os FreeBSD 4.0 +.Sh NAME +.Nm mount_nwfs +.Nd mount NetWare volume from a NetWare file server +.Sh SYNOPSIS +.Nm mount_nwfs +.Op Fl Chv +.Ar -S Ar server +.Ar -U Ar user +.Ar "[connection options]" +.Ar -V Ar volume +.Op Fl M Ar mode +.Op Fl c Ar case +.Op Fl d Ar mode +.Op Fl f Ar mode +.Op Fl g Ar gid +.Op Fl l Ar locale +.Op Fl n Ar os2 +.Op Fl u Ar uid +.Op Fl w Ar scheme +.Ar node +.Nm mount_nwfs +.Op Fl options +.Ar /server:user/volume/path +.Ar node +.Sh DESCRIPTION +The +.Nm +command allow to mount volume from a NetWare server. It may use either +existing connection or create new: if no usable connection was found +it will try to establish a new one. Connection has count of references to it, +so when last mount will be dismounted connection will be closed. It is +possible to create connection without any mounts (but use it for them) with +.Xr ncplogin 1 . +.Pp +Note two forms of command line. In the first form, server and user specified +via +.Fl S +and +.Fl U +options respectively. In the second form server and user specified in +.Ar special +part of +.Xr mount 8 +command line arguments (the +.Fl S , +.Fl U +and +.Fl V +options aren't used in this case). This allows use of fstab file (see EXAMPLES below). +.Pp +The options are: +.Bl -tag -width indent +.It Fl S Ar server +name of NetWare server to connect. For native IP you will need also +.Fl A +option. +.It Fl U Ar user +name of user used in login sequence. +.It Fl "[connection options]" +See +.Xr ncplogin 1 +for details. +.It Fl V Ar volume +Volume name to mount. Volume name can also be specified after all options and +before +.Ar mount-point . +.It Ar node +Path to mount volume. +.It Fl c Ar case +Selects a +.Ar case +option which affects on name representation. +.Ar Case +can be one of the following: +.Bd -literal -offset indent +Value Meaning +l All existing file names converted to lower case. + Newly created file gets a lower case under OS2 name + space. This is default when mounting volumes with DOS + name space. +L Same as 'l' but file system tries to be case + insensitive. May not work well. +n No case conversion is performed. + Warning! Warning!: use this option with DOS name + space only as a last resort, because creating a lower + case name in the DOS name space can lead to an + unpredictable results. This is default when mounting + volume with OS2 name space. +u All existing file names converted to upper case. Newly + created file gets an upper case under OS2 name space. +U Same as 'u' but file system tries to be case insensitive. + May not work well. +.Ed +.It Fl f Ar mode, Fl d Ar mode +specifies permissions that should be assigned to files and directories. +The values must be specified as octal numbers. Default value for the file mode +taken from mount point, default value for the dir mode adds execute permission +where the file mode gives read permission. + +Note that these permissions can differ from the rights granted by NetWare +server. +.It Fl n Ar namespace +don't use +.Ar namespace . +Currently only +.Ar OS2 +can be here. +.It Fl v +prints version number. +.It Fl u Ar uid, Fl g Ar gid +User id and group id assigned to files. The default is owner and group id from +directory where volume is mounted. +.It Fl l Ar locale +Sets the locale for case conversion. By default +.Nm +tries to use an environment variable +.Ar LC_* . +.It Fl w Ar scheme +Selects a +.Ar scheme +used to convert file names between NetWare and FreeBSD. Currently only +.Ar koi2cp866 +and +.Ar asis +can be here. Please note, that scheme should be enabled at compile +time in config.mk file. +.It Fl M Ar mode +See +.Xr ncplogin 1 +for details. If this option is ommited, connection permissions +assumed the same as directory mode ( +.Ar -d ) +option. +.El +.Sh FILES +.Bl -tag -width /var/log/wtmp -compact +.It Pa ~/.nwfsrc +keeps description for each connection. See +.Xr nwfsrc 8 +for details. + +.Sh NOTES +Before any NCP connection can be established kernel must be configured +for IPX support, IPXrouted and KLD nwfs.ko should be loaded. +.Sh EXAMPLES +Next examples illustrates how to connect to NetWare server +.Ar nwserv +as user +.Ar GUEST +and mount volumes +.Ar SYS +and +.Ar VOL1 : +.Bd -literal -offset indent +mount_nwfs -S nwserv -U guest -V sys /nw/s1/sys +mount_nwfs /nwserv:guest/sys /nw/s1/sys +mount -t nwfs /nwserv:guest/vol1 /nw/s1/vol1 +mount -t nwfs /nwserv:boris/sys/home/boris /home/boris/nw/home +.Ed +.Pp +The last example mounts only subdirectory on a volume and equivalent +to NetWare 'map root' command. +.Pp +It is possible to use fstab for nwfs mounts: +.Bd -literal -offset indent +/nwserv:guest/sys /nw/s1/sys nwfs rw,noauto 0 0 +/nwserv:guest/vol1 /nw/s1/vol2 nwfs rw,noauto 0 0 +.Ed + +.Sh BUGS +to number a few + +.Sh CREDITS +In development of NetWare client for FreeBSD next sources was used: +.Pp +Documentation from NetWare NDK. +.Pp +ncpfs for Linux - written by Volker Lendecke (lendecke@math.uni-goettingen.de). +He grants me permission to publish parts of his code under BSD-style license, +.Pp +"Interrupt List" from Ralf Brown, +.Pp +Many files from /sys directory. + +.Sh AUTHOR +.An Boris Popov Aq bp@butya.kz , +.Aq rbp@chat.ru diff --git a/usr.sbin/mount_nwfs/mount_nwfs.c b/usr.sbin/mount_nwfs/mount_nwfs.c new file mode 100644 index 000000000000..363b8cc0200a --- /dev/null +++ b/usr.sbin/mount_nwfs/mount_nwfs.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 1999, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "mntopts.h" + +#define NWFS_VFSNAME "nwfs" + +extern char *__progname; +static char mount_point[MAXPATHLEN + 1]; +static void usage(void); +static int parsercfile(struct ncp_conn_loginfo *li, struct nwfs_args *mdata); + +static struct mntopt mopts[] = { + MOPT_STDOPTS, + { NULL } +}; + +static int +parsercfile(struct ncp_conn_loginfo *li, struct nwfs_args *mdata) { + return 0; +} + +int +main(int argc, char *argv[]) { + int opt, error, mntflags, nlsopt; + char *p, *p1, tmp[1024]; + u_char *pv; + NWCONN_HANDLE connHandle; + struct nwfs_args mdata; + struct ncp_conn_loginfo li; + struct stat st; + struct vfsconf vfc; + struct nw_entry_info einfo; + + if (argc < 2) { + usage(); + exit(1); + } + if (argc == 2) { + if (strcmp(argv[1], "-h") == 0) { + usage(); + exit(0); + } else if (strcmp(argv[1], "-v") == 0) { + errx(EX_OK, "version %d.%d.%d", NWFS_VERSION / 100000, + (NWFS_VERSION % 10000) / 1000, + (NWFS_VERSION % 1000) / 100); + } + } + + error = getvfsbyname(NWFS_VFSNAME, &vfc); + if (error && vfsisloadable(NWFS_VFSNAME)) { + if(vfsload(NWFS_VFSNAME)) + err(EX_OSERR, "vfsload("NWFS_VFSNAME")"); + endvfsent(); + error = getvfsbyname(NWFS_VFSNAME, &vfc); + } + if (error) + errx(EX_OSERR, "NetWare filesystem is not available"); + + if(ncp_initlib()) exit(1); + + mntflags = error = 0; + bzero(&mdata,sizeof(mdata)); + mdata.uid = mdata.gid = -1; + nlsopt = 0; + + if (ncp_li_init(&li, argc, argv)) return 1; + /* + * A little bit weird, but I should figure out which server/user to use + * _before_ reading .rc file + */ + if (argc >= 3 && argv[argc-1][0] != '-' && argv[argc-2][0] != '-' && + argv[argc-2][0] == '/') { + p = argv[argc-2]; + error = 1; + do { + if (*p++ != '/') break; + p1 = tmp; + while (*p != ':' && *p != 0) *p1++ = *p++; + if (*p++ == 0) break; + *p1 = 0; + if (ncp_li_setserver(&li, tmp)) break; + p1 = tmp; + while (*p != '/' && *p != 0) *p1++ = *p++; + if (*p++ == 0) break; + *p1 = 0; + if (ncp_li_setuser(&li, tmp)) break; + p1 = tmp; + while (*p != '/' && *p != 0) *p1++ = *p++; + *p1 = 0; + if (strlen(tmp) > NCP_VOLNAME_LEN) { + fprintf(stderr, "Volume name too long: %s\n", tmp); + break; + } + ncp_str_upper(strcpy(mdata.mounted_vol,tmp)); + if (*p == '/') + p++; + p1 = mdata.root_path + 2; + pv = mdata.root_path + 1; + for(;*p;) { + *pv = 0; + while (*p != '/' && *p) { + *p1++ = *p++; + (*pv)++; + } + if (*pv) { + ncp_nls_mem_u2n(pv + 1, pv + 1, *pv); + pv += (*pv) + 1; + mdata.root_path[0]++; + } + if (*p++ == 0) break; + p1++; + } + error = 0; + } while(0); + if (error) + errx(EX_DATAERR, + "An error occured while parsing '%s'", + argv[argc - 2]); + } + if (ncp_li_readrc(&li)) return 1; + if (ncp_rc) { + parsercfile(&li,&mdata); + rc_close(ncp_rc); + } + while ((opt = getopt(argc, argv, STDPARAM_OPT"V:c:d:f:g:l:n:o:u:w:")) != EOF) { + switch (opt) { + case STDPARAM_ARGS: + if (ncp_li_arg(&li, opt, optarg)) { + return 1; + } + break; + case 'V': + if (strlen(optarg) > NCP_VOLNAME_LEN) + errx(EX_DATAERR, "Volume too long: %s\n", optarg); + ncp_str_upper(strcpy(mdata.mounted_vol,optarg)); + break; + case 'u': { + struct passwd *pwd; + + pwd = isdigit(optarg[0]) ? + getpwuid(atoi(optarg)) : getpwnam(optarg); + if (pwd == NULL) + errx(EX_NOUSER, "unknown user '%s'", optarg); + mdata.uid = pwd->pw_uid; + break; + } + case 'g': { + struct group *grp; + + grp = isdigit(optarg[0]) ? + getgrgid(atoi(optarg)) : getgrnam(optarg); + if (grp == NULL) + errx(EX_NOUSER, "unknown group '%s'", optarg); + mdata.gid = grp->gr_gid; + break; + } + case 'd': + errno = 0; + mdata.dir_mode = strtol(optarg, &p, 8); + if (errno || *p != 0) + errx(EX_DATAERR, "invalid value for directory mode"); + break; + case 'f': + errno = 0; + mdata.file_mode = strtol(optarg, &p, 8); + if (errno || *p != 0) + errx(EX_DATAERR, "invalid value for file mode"); + break; + case '?': + usage(); + exit(1); /*NOTREACHED*/ + case 'n': { + char *inp, *nsp; + + nsp = inp = optarg; + while ((nsp = strsep(&inp, ",;:")) != NULL) { + if (strcasecmp(nsp, "OS2") == 0) + mdata.flags |= NWFS_MOUNT_NO_OS2; + else if (strcasecmp(nsp, "LONG") == 0) + mdata.flags |= NWFS_MOUNT_NO_LONG; + else if (strcasecmp(nsp, "NFS") == 0) + mdata.flags |= NWFS_MOUNT_NO_NFS; + else + errx(EX_DATAERR, "Unknown namespace '%s'", nsp); + } + break; + }; + case 'l': + if (ncp_nls_setlocale(optarg) != 0) return 1; + mdata.flags |= NWFS_MOUNT_HAVE_NLS; + break; + case 'o': + getmntopts(optarg, mopts, &mntflags, 0); + break; + case 'c': + switch (optarg[0]) { + case 'l': + nlsopt |= NWHP_LOWER; + break; + case 'u': + nlsopt |= NWHP_UPPER; + break; + case 'n': + nlsopt |= NWHP_LOWER | NWHP_UPPER; + break; + case 'L': + nlsopt |= NWHP_LOWER | NWHP_NOSTRICT; + break; + case 'U': + nlsopt |= NWHP_UPPER | NWHP_NOSTRICT; + break; + default: + errx(EX_DATAERR, "invalid suboption '%c' for -c", + optarg[0]); + } + break; + case 'w': + if (ncp_nls_setrecodebyname(optarg) != 0) + return 1; + mdata.flags |= NWFS_MOUNT_HAVE_NLS; + break; + default: + usage(); + return 1; + } + } + + if (optind == argc - 2) { + optind++; + } else if (mdata.mounted_vol[0] == 0) + errx(EX_USAGE, "Volume name should be specified"); + + if (optind != argc - 1) { + usage(); + return 1; + } + realpath(argv[optind], mount_point); + + if (stat(mount_point, &st) == -1) + err(EX_OSERR, "could not find mount point %s", mount_point); + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + err(EX_OSERR, "can't mount on %s", mount_point); + } + if (ncp_geteinfo(mount_point, &einfo) == 0) + errx(EX_OSERR, "can't mount on %s twice", mount_point); + + if (mdata.uid == -1) { + mdata.uid = st.st_uid; + } + if (mdata.gid == -1) { + mdata.gid = st.st_gid; + } + if (mdata.file_mode == 0 ) { + mdata.file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + if (mdata.dir_mode == 0) { + mdata.dir_mode = mdata.file_mode; + if ((mdata.dir_mode & S_IRUSR) != 0) + mdata.dir_mode |= S_IXUSR; + if ((mdata.dir_mode & S_IRGRP) != 0) + mdata.dir_mode |= S_IXGRP; + if ((mdata.dir_mode & S_IROTH) != 0) + mdata.dir_mode |= S_IXOTH; + } + if (li.access_mode == 0) { + li.access_mode = mdata.dir_mode; + } +/* if (mdata.flags & NWFS_MOUNT_HAVE_NLS) {*/ + mdata.nls = ncp_nls; +/* }*/ + mdata.nls.opt = nlsopt; + error = ncp_li_check(&li); + if (error) + return 1; + li.opt |= NCP_OPT_WDOG; + /* well, now we can try to login, or use already established connection */ + error = ncp_li_login(&li,&connHandle); + if( error ){ + fprintf(stderr,"Cannot login to server %s,%s\n",li.server,strerror(errno)); + ncp_disconnect(connHandle); + return(1); + } + error = ncp_conn2ref(connHandle, &mdata.connRef); + if (error) { + fprintf(stderr,"Cannot convert handle to refernce. Consider this as a big bug.\n"); + ncp_disconnect(connHandle); + return(1); + } + strcpy(mdata.mount_point,mount_point); + mdata.version = NWFS_VERSION; + error = mount(NWFS_VFSNAME, mdata.mount_point, mntflags, (void*)&mdata); + if (error) { + fprintf(stderr,"mount error: %s\n", strerror(errno)); + ncp_disconnect(connHandle); + exit(1); + } + /* + * I'm leave along my handle, but kernel should keep own ... + */ + ncp_disconnect(connHandle); + /* we are done ?, impossible ... */ + return 0; +} + +static void +usage(void) { + printf("usage: %s [connection options] [options] \n" + " server:user/volume[/path] mount-point\n\n", __progname); + printf( + "see ncplogin(1) for details on connection options\n" + " -A host Netware/IP host address\n" + " -u uid uid the mounted files get\n" + " -g gid gid the mounted files get\n" + " -f mode permission the files get\n" + " -d mode permission the dirs get\n" + " -h print this help text\n" + " -v print nwfs version number\n" + "\n" + ); +}