Compare commits

..

14 Commits

Author SHA1 Message Date
ncpfs archive import
011a5107c5 Import ncpfs 2.0.3 2026-04-28 20:39:58 +02:00
ncpfs archive import
7179281575 Import ncpfs 2.0.2 2026-04-28 20:39:58 +02:00
ncpfs archive import
b8d830f9a3 Import ncpfs 2.0.1 2026-04-28 20:39:58 +02:00
ncpfs archive import
b36a27bedb Import ncpfs 2.0.0 2026-04-28 20:39:58 +02:00
ncpfs archive import
7d0e3d011b Import ncpfs 0.24 2026-04-28 20:39:58 +02:00
ncpfs archive import
84cb1f167d Import ncpfs 0.23 2026-04-28 20:39:58 +02:00
ncpfs archive import
64f006632a Import ncpfs 0.22 2026-04-28 20:39:58 +02:00
ncpfs archive import
92f749a943 Import ncpfs 0.21 2026-04-28 20:39:58 +02:00
ncpfs archive import
6cb56005ea Import ncpfs 0.20 2026-04-28 20:39:58 +02:00
ncpfs archive import
0520c1d2f7 Import ncpfs 0.19 2026-04-28 20:39:57 +02:00
ncpfs archive import
d5ac4601b1 Import ncpfs 0.18 2026-04-28 20:39:57 +02:00
ncpfs archive import
1fa124bd7c Import ncpfs 0.17 2026-04-28 20:39:57 +02:00
ncpfs archive import
5753870858 Import ncpfs 0.16 2026-04-28 20:39:57 +02:00
ncpfs archive import
b8ce93c8bd Import ncpfs 0.15 2026-04-28 20:39:57 +02:00
125 changed files with 11173 additions and 1247 deletions

BIN
.downloads/ncpfs-0.15.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.16.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.17.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.18.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.19.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.20.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.21.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.22.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.23.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.24.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-2.0.0.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-2.0.1.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-2.0.2.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-2.0.3.tgz Normal file

Binary file not shown.

20
BUGS
View File

@@ -5,12 +5,12 @@ But there are really problems that might be fixed in the future.
-------------------------------------------------------------------------------
'df' returns 0:
Free disk space is distributed among the volumes in NetWare. df is
only able to report one number per mounted filesystem. As connections
are quite expensive for NetWare (with lwared that might change ...), I
rejected the alternative to mount only a single volume for a unix
mount point. So I simply return 0.
'df' returns 0: Free disk space is distributed among the volumes in
NetWare. df is only able to report one number per mounted
filesystem. As connections are quite expensive for NetWare (with
mars_nwe and lwared that might change ...), I rejected the alternative
to mount only a single volume for a unix mount point. So I simply
return 0.
-------------------------------------------------------------------------------
@@ -20,11 +20,3 @@ like
Nov 25 16:09:08 lx01 kernel: alloc_skb called nonatomically from interrupt 0000002e
These are a bit annoying, but completely harmless.
-------------------------------------------------------------------------------
ncpfs has a problem with NetWare 4.1, when files are created. I think
NW4.1 does not like some of the creation mode bits. If somebody with
access to a NW4.1 server could compile the kernel module for 1.2 with
-DDEBUG_NCP=2, and send me the syslog output gzipped/uuencoded, I
might find out more about that problem.

138
Changes
View File

@@ -1,5 +1,139 @@
I only began this file with ncpfs-0.12. If you're interested in older
versions, you can find them on linux01.gwdg.de:/pub/ncpfs/old.
versions, you can find them on ftp.gwdg.de:/pub/linux/misc/ncpfs/old.
ncpfs-2.0.2 -> ncpfs-2.0.3
- Removed the kernel-2.0 directory. Linus took the patch into 2.0.8.
So, if you want to use long file name support, upgrade to Linux
kernel version 2.0.8.
- Applied the lfn patch to the kernel-1.2 module with some light
testing. If you experience problems, tell it to me, and use the
ncpfs-2.0.2 kernel module, or upgrade to Linux 2.0.8.
- Added unencrypted login when no crypt key is returned.
- Hopefully improved error messages a bit
- Added some values to ipxparse
- For ELF systems, moved ncplib to /lib/libncp.so.1.x. This saves
about 1MB of disk space. As ncpfs grows, the saving will
increase. Please look at the Makefile to enable this.
- Enhanced nwfsinfo a bit. (Even with a manpage!)
- Added nwuserlist.
ncpfs-2.0.1 -> ncpfs-2.0.2
- Added some values to ipxparse.
- Added a patch against 2.0.7 for long file names support. I did not
apply this change to the 1.2-module. Please upgrade to 2.0.7 if you
want to use long file names.
- nwbpvalues can print ITEM properties
ncpfs-2.0.0 -> ncpfs-2.0.1
- Added some values to ipxparse.
- Added the little bindery utilities. Maybe someone has the time to
write a shellscript named 'nwadduser' ?
- Fixed a bug that made the __255 message reappear. Many thanks to
Guntram Blom for his detailed bug report.
- Fixed a bug that made ncpfs incompatible with W95's server
capabilities. Thanks to Tomasz Babczynski
<faster@dino.ict.pwr.wroc.pl> for this one.
ncpfs-0.24 -> ncpfs-2.0.0
- Changed the numbering scheme :-).
- Added npasswd. Many thanks to Guntram Blom for his work!
- Hopefully improved error messages a bit
- Hopefully made slist a bit more robust
ncpfs-0.23 -> ncpfs-0.24
- Fixed a bug that made it impossible to umount a filesystem after you
tried 'mkdir .' or 'mkdir ..'.
- Fixed a bad race condition when opening files.
- Made the default timeout values more robust.
ncpfs-0.22 -> ncpfs-0.23
- Fixed a memory allocation problem in nwmsg.c. Thanks to
Andrew Ross <anr1001@hermes.cam.ac.uk>
- slist hopefully does not ask for a password anymore.
- cleaned up error messages a bit.
- ncpmount now calls modprobe instead of insmod.
ncpfs-0.21 -> ncpfs-0.22
- removed a bad race condition in kernel-1.2/src/dir.c.
- handle 0x9999-responses from the ncp server correctly.
- Bindery functions in ncplib.c by Brian G. Reid (breid@tim.com)
- set blocksize to 512 to satisfy 'du -k'
ncpfs-0.20 -> ncpfs-0.21
- Included two bugfixes in ncplib.c found by Jeff Buhrt
<buhrt@iquest.net>.
- Included a bugfix in kernel code that could only show for servers
that do not support namespace calls. I should have tried ncpfs
against lwared... Thanks to Neil Turton <ndt1001@chu.cam.ac.uk> for
this fix.
ncpfs-0.19 -> ncpfs-0.20
- Changed the home site for ncpfs from linux01.gwdg.de:/pub/ncpfs
to ftp.gwdg.de:/pub/linux/misc/ncpfs. linux01 will remain available,
but we would like to reduce the load on that machine. Sites
mirroring linux01 please redirect your mirror software to
ftp.gwdg.de. Thanks.
- Removed a bug in ncplib.c that made slist require a full
login. Thanks to Neil Turton <ndt1001@chu.cam.ac.uk> for the hint.
- The first real user contribution: ncopy by Brian G. Reid
(breid@tim.com) and Tom C. Henderson (thenderson@tim.com). Many
thanks to you! If you find bugs in ncopy, tell them, not me ;-)
- Handle expired passwords. Thanks to "Mathew Lim" <M.Lim@sp.ac.sg>
for the hint.
ncpfs-0.18 -> ncpfs-0.19
- hacked around in ncplib.[ch] quite heavily.
- SAP handling in ipxparse.c. Thanks to Jeff Buhrt <buhrt@iquest.net>
- Changed error handling to use the com_err library. This should
eventually provide better error messages, because it's now much
easier to define nice messages.
- If no server is active, report this correctly
- added nsend
ncpfs-0.17 -> ncpfs-0.18
- Another attempt at solving the problem that -n is not working.
- Forgot nprint in 0.17 util/Makefile.
- nprint left connections open when it fails
- added options -r and -t to ncpmount to tune ncpfs connections.
ncpfs-0.16 -> ncpfs-0.17
- Changed the name of fsinfo to nwfsinfo, to avoid a name clash with
the X windows utility. Thanks to Henning Brockfeld
<Henning.Brockfeld@lrz.uni-muenchen.de> for this hint. (still
waiting for your scripts.. :-))
- made nwmsg available. This enables you to receive NetWare user
broadcast messages. Please note that you need at least kernel 1.3.68
for this feature.
- pserver now prints debugging output via syslog().
- Included ipxdump, a nice little utility, that has helped some
people.
- And now the big one: you can re-export ncpfs-mounted directories
with nfsd! You have to mount single volumes by specifying -V volume
to ncpmount, and call nfsd and mountd with the option --re-export.
See the manual page of ncpmount for more information. Please note
that I will send Linus the required patch on 1. March 1996, so you
will have to use kernel 1.2.13 or wait at least for 1.3.70.
ncpfs-0.15 -> ncpfs-0.16
- Included ipx-1.0, made available by Greg Page <greg@caldera.com>,
Caldera
- Made -n work for password-less accounts. Thanks to Alexander Jolk
<jolk@ap-pc513b.physik.uni-karlsruhe.de>.
- Fixed the kerneld support.
- Fixed the NetWare 4.1 problem. Many thanks to
Chatchai JANTARAPRIM <chat@ratree.psu.ac.th> and
hitesh.soneji@industry.net for their patience.
ncpfs-0.14 -> ncpfs-0.15
- A bug fixed that made normal mounting impossible. It was too late
yesterday. Sorry
- Manpage for pserver.c
ncpfs-0.13 -> ncpfs-0.14
@@ -15,4 +149,4 @@ ncpfs-0.12 -> ncpfs-0.13
- support for automatic loading of ncpfs.o by kerneld.
Thanks to Steven N. Hirsch <hirsch@emba.uvm.edu>.
- A subtle problem in the read routines has been removed by Uwe Bonnes
<bon@elektron.ikp.physik.th-darmstadt.de>. Thanks a lot.
<bon@elektron.ikp.physik.th-darmstadt.de>. Thanks a lot.

67
FAQ Normal file
View File

@@ -0,0 +1,67 @@
There is certainly not enough material to call this an FAQ, but some
questions reach me regularly. Probably the documenation is not clear
enough.
-------------------------------------------------------------------------------
Q: The ncpfs utilities like slist or ncpmount tell me that they can
not find a server, although I'm sure there are servers on my
net. What's wrong?
You probably used
ipx_configure --auto_interface=on --auto_primary=on
and you have Windows (95?) workstations on your network. Windows 95
makes Linux configure IPX interfaces for non-existent frame types. To
solve this problem, you have to configure your IPX interface manually
with the command
ipx_interface add -p <device> <frame>
For <device> use eth0, eth1 or whatever you network adapter is
called. The value for <frame> must match the frame type used on your
network. Possible values are 802.2, 802.3, SNAP and EtherII.
-------------------------------------------------------------------------------
Q: I have difficulties with NetWare 4.1. What can I do?
To be honest, I do not really know. Currently my only test equipment
is a NetWare 3.11 server. You should make your 4.1 Server as
3.x-compatible as it can be. As I do not know 4.1, you are on your own
doing this.
A promising hint that has already helped some people is to switch off
packet signatures on the 4.1 server, as ncpfs does not support them.
-------------------------------------------------------------------------------
Q: When I re-export ncpfs-mounted directories via nfs, I get messages like
'pwd: cannot get current directory', and other strange things happen to
the nfs clients. What's wrong?
When you want to export a directory via NFS, you have to do two things:
- You have to invoke mountd and nfsd with the option --re-export. On my
computer, both are invoked at system startup from the file
/etc/rc.d/rc.inet2.
- You can not export a complete NetWare server hierarchy with all volumes
under a single mount point. You have to mount a single server volume to
make it re-exportable. Invoke ncpmount with the option -V volume to do
this.
-------------------------------------------------------------------------------
Q: When I compile ncpfs, I get a message like the following:
make[1]: Entering directory `/home/me/netware/ncpfs/kernel-1.2/src'
gcc -D__KERNEL__ -I. -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer -I/home/me/netware/ncpfs/kernel-1.2 -DNCPFS_VERSION=\"0.17\" -c dir.c
dir.c:36: warning: `struct dirent' declared inside parameter list
dir.c:36: warning: its scope is only this definition or declaration,
...
You try to compile the part of ncpfs that is meant for kernel 1.2.13 under
kernel 1.3.x. Please look at the Makefile and comment out the
corresponding lines.

View File

@@ -2,31 +2,32 @@
# Makefile for the linux ncp-filesystem routines.
#
# KERNEL = 1.2
TOPDIR = $(shell pwd)
BINDIR = /usr/local/bin
INTERM_BINDIR = $(TOPDIR)/bin
SUBDIRS = util ipx-0.75 man
#
# The following 2 lines are for those who use Kernel version 1.2.x.
# If you have a kernel later than 1.3.53, please comment out the
# the following lines. You have to recompile your kernel
# and say 'y' when 'make config' asks you for IPX and ncpfs.
#
#SUBDIRS += kernel-1.2/src
#INCLUDES = -I$(TOPDIR)/kernel-1.2
VERSION = 2.0.3
# If you are using kerneld to autoload ncp support,
# uncomment this (kerneld is in linux since about 1.3.57):
# KERNELD = -DHAVE_KERNELD
#KERNELD = -DHAVE_KERNELD
export INCLUDES BINDIR INTERM_BINDIR KERNELD
# If your system is ELF, please uncomment the following line:
#HAVE_ELF=yes
TOPDIR = $(shell pwd)
BINDIR = /usr/local/bin
SBINDIR = /sbin
INTERM_BINDIR = $(TOPDIR)/bin
SUBDIRS = util ipx-1.0 man
KVERSION=$(shell uname -r | cut -b1-3)
ifeq ($(KVERSION),1.2)
SUBDIRS += kernel-1.2/src
INCLUDES = -I$(TOPDIR)/kernel-1.2
endif
export INCLUDES BINDIR INTERM_BINDIR SBINDIR KERNELD VERSION HAVE_ELF
all:
for i in $(SUBDIRS); do make -C $$i; done
for i in $(SUBDIRS); do make -C $$i all; done
dep:
for i in $(SUBDIRS); do make -C $$i dep; done
@@ -41,9 +42,10 @@ clean:
rm -f `find . -type f -name '*.out' -print`
for i in $(SUBDIRS); do make -C $$i clean; done
realclean: clean
mrproper: clean
rm -fr $(INTERM_BINDIR)/* ncpfs.tgz
make -C util realclean
make -C util mrproper
make -C ipxdump mrproper
modules: ncpfs.o
@@ -51,11 +53,15 @@ SRCPATH=$(shell pwd)
SRCDIR=$(shell basename $(SRCPATH))
DISTFILE=$(SRCDIR).tgz
dist: tgz
dist: mrproper
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \
mv $(DISTFILE) $(SRCDIR))
make dep
make all
tgz: realclean
tgz: mrproper
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \

81
README
View File

@@ -1,9 +1,24 @@
This is ncpfs, a free NetWare client filesystem for Linux. Besides
some little utilities it also contains nprint, which enables you to
print on NetWare print queues.
print on NetWare print queues. The opposite side, pserver, is also
provided.
I'm planning major changes in the structure of ncpfs for Linux 2.1.x
which will break the binary compatibility. So I changed the numbering
scheme for ncpfs. ncpfs-2.0.x will be the version to be used with
Linux 2.0.0 and older kernels, and ncpfs-2.1.x will be the version for
the development kernels.
INSTALLATION
Before you start the installation, make sure that your kernel has IPX
support compiled in. When 'make config' asks you for
The IPX protocol (CONFIG_IPX) [N/y/m/?]
simply answer 'y'. Probably you do not need the full internal net that
you are asked for next.
The installation of ncpfs depends on the kernel version you are
using. For kernel 1.2, you should simply type 'make' and look at
what's in the bin/ directory after that. Please be sure that your
@@ -11,10 +26,9 @@ kernel resides in /usr/src/linux, because the file
kernel-1.2/src/sock.c has to refer directly to it.
If you use Kernel 1.3, please be sure that you use at least
1.3.54. ncpfs does NOT work with any earlier 1.3.x kernel, especially
not with 1.3.53, although this one has a fs/ncpfs/ subdirectory.
1.3.71. ncpfs does NOT work with any earlier 1.3.x kernel.
If you use Kernel 1.3.54 or later, you might have to recompile your
If you use Kernel 1.3.71 or later, you might have to recompile your
kernel. With these kernels, the kernel part of ncpfs is already
included in the main source tree. If you want to use ncpfs, you should
say 'y' to 'make config' when you are asked for IPX, and again when it
@@ -22,10 +36,32 @@ asks for ncpfs. After you have rebooted with the new kernel, 'cat
/proc/filesystems' should show you a line saying that the kernel knows
ncpfs.
With Kernel 1.3.54 or later you also have to modify the Makefile in the
directory you found this README in. Please see the Makefile for the
necessary modifications. Then typing 'make' should work with no
problem.
If you are running kerneld, please uncomment the corresponding line in
the Makefile to reflect this.
If your system is ELF, please enable the use of the shared ncp-library
in the Makefile. This will save at least 1MB of disk space.
After you adapted your Makefile, type 'make' and, as root, 'make install'.
HELP
In the meantime my mail volume has grown considerably, so the response
time might be better at the LinWare mailing list than at my personal
email address. You can mail to and/or subscribe to the LinWare mailing
list:
Topics for the list:
- discussing LinWare server, its features, installation problems and bugs
- using IPX protocol under Linux
- IPX routing and router daemons under Linux
- mars_nwe
- ncpfs
You can subscribe to the list by sending the command "add linware" in
the mail message body to address: "listserv@sh.cvut.cz". Your
postings should be sent to: "linware@sh.cvut.cz".
USING NCPFS
@@ -77,6 +113,8 @@ Ales Dyrak has written lwared, which was the initial start for ncpfs.
Alan Cox has found some bugs I would probably never have found.
Look at the file Changes for others.
LIMITATIONS (compare these with smbfs :-)
@@ -86,27 +124,10 @@ limitation is the lack of uid, gid and permission information per
file. You have to assign those values once for a complete mounted
directory.
The second limitation is just as annoying as the first: You cannot
re-export a ncp-mounted directory by nfs. It is not possible because
the NFS protocol defines access to files through unique file handles,
which can be mapped to the device and inode numbers in unix NFS
servers. NCP does not have unique numbers per file, you only have the
path name. I implemented a caching scheme for inode numbers, which
gives unique inode numbers for every open file in the system. This is
just sufficient for local use of the files, because you can tell when
an inode number can be discarded. With NFS the situation is
different. You can never know when the client will access the file-id
you offered, so you would have to cache the inode numbers
indefinitely long. I think this should not be done in kernel mode, as
it would require an unlimited amount of RAM.
Those who looked at the kernel code a bit closer will have found out
that the last section is a little white lie. As I found out after the
first version of ncpfs, NetWare does indeed offer something like inode
numbers, although are only unique per volume. So one way to make ncpfs
re-exportable by nfs is to allocate a superblock per volume and show
the inode numbers to the user. I was just too lazy to do this
yet. Maybe once we will force Novell to make NetWare NFS
affordable... ;-)
You will not be able to access servers that require packet
signatures. This seems to be one of Novell's bigger secrets :-(.
Have fun with ncpfs!
Volker
lendecke@namu01.gwdg.de

15
TODO Normal file
View File

@@ -0,0 +1,15 @@
Here's a list of things I want to do. Feel free to send suggestions,
or even help me ;-).
- Add flags to pserver's command line, so that the print command can
find out the name of user who printed the job.
- do rtt estimation, like tcp does.
- Do better connection management. I imagine to create a ncpd.
- When ncp is done, one can think about mounting several volumes over
a single NCP connection. This should make the trade-off mentioned in
ncpmount.8 unnecessary.
- Do some kind of mapping of NCP uid's to unix uid's

9
ipx-1.0/COPYING Normal file
View File

@@ -0,0 +1,9 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the original work is
properly attributed to Greg Page and Caldera, Inc.
Neither the name of Greg Page nor Caldera, Inc. may be used to
endorse or promote products derived from this software without
specific prior written permission.
This software is provided by Greg Page and Caldera, Inc. "AS IS"
and without any express or implied warranties.

24
ipx-1.0/Gregs.Makefile Normal file
View File

@@ -0,0 +1,24 @@
CFLAGS = -O2 -Wall
UTILS = ipx_configure ipx_interface ipx_internal_net ipx_route
all: $(UTILS)
clean:
rm -f $(UTILS) *.o rip sap ipxrcv ipxsend
install: $(UTILS)
for i in $(UTILS); \
do \
install --strip $$i /sbin; \
install $$i.8 /usr/man/man8; \
done
install init.ipx /etc/rc.d/init.d/ipx
install -m 0644 config.ipx /etc/sysconfig/ipx
rm -f /etc/rc.d/rc2.d/S15ipx
ln -sf /etc/rc.d/init.d/ipx /etc/rc.d/rc2.d/S15ipx
rm -f /etc/rc.d/rc3.d/S15ipx
ln -sf /etc/rc.d/init.d/ipx /etc/rc.d/rc3.d/S15ipx
rm -f /etc/rc.d/rc5.d/S15ipx
ln -sf /etc/rc.d/init.d/ipx /etc/rc.d/rc5.d/S15ipx
rm -f /etc/rc.d/rc6.d/K55ipx
ln -sf /etc/rc.d/init.d/ipx /etc/rc.d/rc6.d/K55ipx

View File

@@ -5,16 +5,16 @@ UTILS = $(INTERM_BINDIR)/ipx_configure $(INTERM_BINDIR)/ipx_interface \
all: $(UTILS)
$(INTERM_BINDIR)/ipx_configure: ipx_configure.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_configure ipx_configure.o
$(CC) -o $(INTERM_BINDIR)/ipx_configure ipx_configure.o
$(INTERM_BINDIR)/ipx_interface: ipx_interface.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_interface ipx_interface.o
$(CC) -o $(INTERM_BINDIR)/ipx_interface ipx_interface.o
$(INTERM_BINDIR)/ipx_internal_net: ipx_internal_net.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_internal_net ipx_internal_net.o
$(CC) -o $(INTERM_BINDIR)/ipx_internal_net ipx_internal_net.o
$(INTERM_BINDIR)/ipx_route: ipx_route.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_route ipx_route.o
$(CC) -o $(INTERM_BINDIR)/ipx_route ipx_route.o
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
@@ -25,6 +25,6 @@ clean:
install: $(UTILS)
for i in $(UTILS); \
do \
install --strip $$i $(BINDIR); \
install $$i $(BINDIR); \
done

View File

@@ -47,7 +47,7 @@ This program is used to read/write two configuration parameters:
By default, these are both turned off.
The following are sample IPX programs:
The following are sample IPX programs (found in directory Samples):
ipxrcv.c and ipxsend.c
ipxsend will send a single packet to an instance of ipxrcv running on the

View File

@@ -51,7 +51,7 @@ main(int argc, char **argv)
htonl(sipx.sipx_network),
sipx.sipx_node[0], sipx.sipx_node[1],
sipx.sipx_node[2], sipx.sipx_node[3],
sipx.sipx_node[4], sipx.sipx_node[5]);
sipx.sipx_node[6], sipx.sipx_node[5]);
bptr += 2;
rp = (struct rip_data *) bptr;
while (result >= sizeof(struct rip_data)) {

7
ipx-1.0/config.ipx Normal file
View File

@@ -0,0 +1,7 @@
IPX_AUTO_PRIMARY=on
IPX_AUTO_INTERFACE=on
IPX_CONFIGURED=no
IPX_DEVICE=eth0
IPX_FRAME=802.2
IPX_INTERNAL_NET=no
IPX_NETNUM=0

41
ipx-1.0/init.ipx Normal file
View File

@@ -0,0 +1,41 @@
#!/bin/sh
#
# ipx Bring up/down IPX networking
#
# Source function library.
. /etc/rc.d/init.d/functions
. /etc/sysconfig/network
. /etc/sysconfig/ipx
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
# See how we were called.
case "$1" in
start)
if [ ${IPX_CONFIGURED} = "yes" ]; then
if [ ${IPX_INTERNAL_NET} = "yes" ]; then
/sbin/ipx_internal_net add ${IPX_NETNUM}
else
/sbin/ipx_interface add -p ${IPX_DEVICE} \
${IPX_FRAME} ${IPX_NETNUM}
fi
fi
ipx_configure \
--auto_primary=${IPX_AUTO_PRIMARY} \
--auto_interface=${IPX_AUTO_INTERFACE}
touch /var/lock/subsys/ipx
;;
stop)
ipx_configure --auto_primary=off --auto_interface=off
ipx_interface delall
rm -f /var/lock/subsys/ipx
;;
*)
echo "Usage: network {start|stop}"
exit 1
esac
exit 0

View File

@@ -1,3 +1,8 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
@@ -7,6 +12,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
struct option options[] = {
{ "auto_primary", required_argument, NULL, 1 },
@@ -61,8 +67,14 @@ main(int argc, char **argv)
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
int old_errno = errno;
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
if (old_errno == -EINVAL)
{
fprintf(stderr, "Probably you have no IPX support in "
"your kernel\n");
}
exit(-1);
}

View File

@@ -1,3 +1,8 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
@@ -10,6 +15,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
static struct ifreq id;
static char *progname;
@@ -19,7 +25,8 @@ usage(void)
{
fprintf(stderr, "Usage: %s add [-p] device frame_type [net_number]\n\
Usage: %s del device frame_type\n\
Usage: %s check device frame_type\n", progname, progname, progname);
Usage: %s delall\n\
Usage: %s check device frame_type\n", progname, progname, progname, progname);
exit(-1);
}
@@ -28,6 +35,9 @@ struct frame_type {
unsigned char ft_val;
} frame_types[] = {
{"802.2", IPX_FRAME_8022},
#ifdef IPX_FRAME_TR_8022
{"802.2TR", IPX_FRAME_TR_8022},
#endif
{"802.3", IPX_FRAME_8023},
{"SNAP", IPX_FRAME_SNAP},
{"EtherII", IPX_FRAME_ETHERII}
@@ -109,8 +119,14 @@ ipx_add_interface(int argc, char **argv)
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
int old_errno = errno;
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
if (old_errno == -EINVAL)
{
fprintf(stderr, "Probably you have no IPX support in "
"your kernel\n");
}
exit(-1);
}
@@ -162,6 +178,76 @@ ipx_add_interface(int argc, char **argv)
exit(-1);
}
int
ipx_delall_interface(int argc, char **argv)
{
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr;
int s;
int result;
char errmsg[80];
char buffer[80];
char device[20];
char frame_type[20];
int fti;
FILE *fp;
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
}
fp = fopen("/proc/net/ipx_interface", "r");
if (fp == NULL) {
fprintf(stderr,
"%s: Unable to open \"/proc/net/ipx_interface.\"\n",
progname);
exit(-1);
}
fgets(buffer, 80, fp);
while (fscanf(fp, "%s %s %s %s %s", buffer, buffer, buffer,
device, frame_type) == 5) {
sipx->sipx_network = 0L;
if (strcasecmp(device, "Internal") == 0) {
sipx->sipx_special = IPX_INTERNAL;
} else {
sipx->sipx_special = IPX_SPECIAL_NONE;
strcpy(id.ifr_name, device);
fti = lookup_frame_type(frame_type);
if (fti < 0) continue;
sipx->sipx_type = frame_types[fti].ft_val;
}
sipx->sipx_action = IPX_DLTITF;
sipx->sipx_family = AF_IPX;
result = ioctl(s, SIOCSIFADDR, &id);
if (result == 0) continue;
switch (errno) {
case EPROTONOSUPPORT:
fprintf(stderr, "%s: Invalid frame type (%s).\n",
progname, frame_type);
break;
case ENODEV:
fprintf(stderr, "%s: No such device (%s).\n",
progname, device);
break;
case EINVAL:
fprintf(stderr, "%s: No such IPX interface %s %s.\n",
progname, device, frame_type);
break;
default:
sprintf(errmsg, "%s: ioctl", progname);
perror(errmsg);
break;
}
}
exit(0);
}
int
ipx_del_interface(int argc, char **argv)
{
@@ -176,6 +262,7 @@ ipx_del_interface(int argc, char **argv)
}
sipx->sipx_network = 0L;
sipx->sipx_special = IPX_SPECIAL_NONE;
strcpy(id.ifr_name, argv[1]);
fti = lookup_frame_type(argv[2]);
if (fti < 0)
@@ -289,6 +376,10 @@ main(int argc, char **argv)
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_add_interface(argc-1, argv);
} else if (strncasecmp(argv[1], "delall", 6) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];
ipx_delall_interface(argc-1, argv);
} else if (strncasecmp(argv[1], "del", 3) == 0) {
for (i = 1; i < (argc-1); i++)
argv[i] = argv[i+1];

View File

@@ -1,3 +1,8 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

View File

@@ -1,3 +1,8 @@
/* Copyright (c) 1995-1996 Caldera, Inc. All Rights Reserved.
*
* See file COPYING for details.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

35
ipxdump/Makefile Normal file
View File

@@ -0,0 +1,35 @@
EXEC= ipxdump ipxparse
CFLAGS= -Wall -O2
OBJECTS= ipxutil.o
all: $(EXEC)
ipxdump: ipxdump.o $(OBJECTS)
$(CC) -o $@ ipxdump.o $(CFLAGS) $(OBJECTS)
ipxparse: ipxparse.o $(OBJECTS)
$(CC) -o $@ ipxparse.o $(CFLAGS) $(OBJECTS)
clean:
rm -f *.o $(EXEC) *~
modules: ncpfs.o
SRCPATH=$(shell pwd)
SRCDIR=$(shell basename $(SRCPATH))
DISTFILE=$(SRCDIR).tgz
mrproper: clean
rm -f $(DISTFILE)
dist: tgz
make all
tgz: mrproper
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \
mv $(DISTFILE) $(SRCDIR))

45
ipxdump/README Normal file
View File

@@ -0,0 +1,45 @@
This is a VERY stupid packet sniffer for IPX ethernet packets.
=============================================
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! S E C U R I T Y W A R N I N G ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
=============================================
If you are using unencrypted passwords, and use this tool to send a
dump to somebody else or store it on a computer, you might very well
store passwords there. So, be VERY careful! This is exactly the kind
of tools Novell designed the encrypted passwords for (or against).
I hacked it together to be able to help people with problems with
ncpfs. The socket handling was taken from Statnet-2.0.
You can use it to watch commercial NetWare clients when they talk to
servers. I divided the program into 2 parts, ipxdump and ipxparse.
ipxdump simply pumps all the IPX frames it receives to stdout.
If you use ipxdump to watch a workstation, you can use the simple
filter function ipxdump provides. You can call ipxdump with the node
address of the workstation you want to watch. This way only the
packets this workstation sends and receives are monitored. As an
example, I call ipxdump as
./ipxdump 00001B038B11
to look at my 286/10MHz test 'workstation'. ipxdump still generates
huge amounts of data, so you should be very careful to start it just
before you perform the operation (such as file creation for OS/2
clients with NW4.1 as a server, or a 'dir' on a directory with long
and short file names, or an encrypted password change ;-)) and stop it
directly after that. And, please gzip -9 and uuencode it before you
send it to anybody.
ipxparse will eventually take apart the dump that ipxdump
generates. They can as well be used in a pipe. Currently ipxparse does
not do anything sensible, but that will definitely change.
Volker Lendecke
<lendecke@namu01.gwdg.de>

245
ipxdump/ipxdump.c Normal file
View File

@@ -0,0 +1,245 @@
/* ipxdump.c */
/* Copyright 1996 Volker Lendecke, Goettingen, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <signal.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <netinet/protocols.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include "ipxutil.h"
struct ipx_address
{
unsigned long net;
unsigned char node[IPX_NODE_LEN];
unsigned short sock;
};
struct ipx_packet
{
unsigned short ipx_checksum;
#define IPX_NO_CHECKSUM 0xFFFF
unsigned short ipx_pktsize;
unsigned char ipx_tctrl;
unsigned char ipx_type;
#define IPX_TYPE_UNKNOWN 0x00
#define IPX_TYPE_RIP 0x01 /* may also be 0 */
#define IPX_TYPE_SAP 0x04 /* may also be 0 */
#define IPX_TYPE_SPX 0x05 /* Not yet implemented */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */
struct ipx_address ipx_dest __attribute__ ((packed));
struct ipx_address ipx_source __attribute__ ((packed));
};
void handle_frame (unsigned char *buf, int length, struct sockaddr *saddr);
void handle_ipx(char *frame, unsigned char *buf);
static int filter = 0;
static IPXNode filter_node;
static int exit_request = 0;
static void
int_handler()
{
exit_request = 1;
}
void
main (int argc, char *argv[])
{
int sd;
struct ifreq ifr, oldifr;
char *device = "eth0";
struct sockaddr saddr;
int sizeaddr;
unsigned char buf[4096];
int length;
signal(SIGINT, int_handler);
if (argc > 1)
{
if (ipx_sscanf_node(argv[1], filter_node) != 0)
{
fprintf(stderr, "usage: %s [node]\n", argv[0]);
exit(1);
}
filter = 1;
}
if ((sd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL))) < 0)
{
perror ("Can't get socket");
fprintf(stderr, "You must run %s as root\n", argv[0]);
exit (1);
}
/* SET PROMISC */
strcpy (oldifr.ifr_name, device);
if (ioctl (sd, SIOCGIFFLAGS, &oldifr) < 0)
{
close (sd);
perror ("Can't get flags");
exit (2);
}
/* This should be rewritten to cooperate with other net tools */
ifr = oldifr;
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (sd, SIOCSIFFLAGS, &ifr) < 0)
{
close (sd);
perror ("Can't set flags");
exit (3);
}
while ( exit_request == 0 )
{
/* This is the main data-gathering loop; keep it small
and fast */
sizeaddr = sizeof(saddr);
length = recvfrom (sd, buf, sizeof(buf), 0,
&saddr, &sizeaddr);
if (length < 0 ) continue;
handle_frame (buf, length, &saddr);
}
/* This should be rewritten to cooperate with other net tools */
if (ioctl (sd, SIOCSIFFLAGS, &oldifr) < 0)
{
close (sd);
perror ("Can't set flags");
exit (4);
}
close (sd);
exit (0);
}
void
handle_ipx (char *frame, unsigned char *buf)
{
int i;
struct ipx_packet *h = (struct ipx_packet *)buf;
struct sockaddr_ipx s_addr;
struct sockaddr_ipx d_addr;
int length = ntohs(h->ipx_pktsize);
memset(&s_addr, 0, sizeof(s_addr));
memset(&d_addr, 0, sizeof(d_addr));
memcpy(s_addr.sipx_node, h->ipx_source.node, sizeof(s_addr.sipx_node));
s_addr.sipx_port = h->ipx_source.sock;
s_addr.sipx_network = h->ipx_source.net;
memcpy(d_addr.sipx_node, h->ipx_dest.node, sizeof(d_addr.sipx_node));
d_addr.sipx_port = h->ipx_dest.sock;
d_addr.sipx_network = h->ipx_dest.net;
if (filter != 0)
{
if ( (memcmp(filter_node, s_addr.sipx_node,
sizeof(filter_node)) != 0)
&& (memcmp(filter_node, d_addr.sipx_node,
sizeof(filter_node)) != 0))
{
/* Not for us */
return;
}
}
printf("%s ", frame);
for (i = 0; i < length; i++)
{
printf("%2.2X", buf[i]);
}
printf("\n");
if (!isatty(STDOUT_FILENO))
{
fflush(stdout);
}
}
void
handle_other (unsigned char *buf, int length, struct sockaddr *saddr)
{
struct ethhdr *eth = (struct ethhdr *)buf;
unsigned char *p = &(buf[sizeof(struct ethhdr)]);
if (ntohs(eth->h_proto) < 1536)
{
/* This is a magic hack to spot IPX packets. Older
* Novell breaks the protocol design and runs IPX over
* 802.3 without an 802.2 LLC layer. We look for FFFF
* which isnt a used 802.2 SSAP/DSAP. This won't work
* for fault tolerant netware but does for the rest.
*/
if (*(unsigned short *)p == 0xffff)
{
handle_ipx("802.3", p);
return;
}
if ( (*(unsigned short *)p == htons(0xe0e0))
&& (p[2] == 0x03))
{
handle_ipx("802.2", p+3);
return;
}
if (memcmp(p, "\252\252\003\000\000\000\201\067", 8) == 0)
{
handle_ipx("snap", p+8);
return;
}
}
}
void
handle_frame (unsigned char *buf, int length, struct sockaddr *saddr)
{
/* Ethernet packet type ID field */
unsigned short packet_type = ((struct ethhdr *)buf)->h_proto;
switch( packet_type )
{
case __constant_ntohs(ETH_P_IPX):
handle_ipx("EtherII", &(buf[sizeof(struct ethhdr)]));
break;
default:
handle_other(buf, length, saddr);
break;
}
}

693
ipxdump/ipxparse.c Normal file
View File

@@ -0,0 +1,693 @@
/* ipxparse.c */
/* Copyright 1996 Volker Lendecke, Goettingen, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <signal.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <netinet/protocols.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <ctype.h>
#include "ipxutil.h"
#define DUMPALLSAPS /* #define if you want to dump all SAP's */
struct ipx_address
{
unsigned long net;
unsigned char node[IPX_NODE_LEN];
unsigned short sock;
};
struct ipx_packet
{
unsigned short ipx_checksum;
#define IPX_NO_CHECKSUM 0xFFFF
unsigned short ipx_pktsize;
unsigned char ipx_tctrl;
unsigned char ipx_type;
#define IPX_TYPE_UNKNOWN 0x00
#define IPX_TYPE_RIP 0x01 /* may also be 0 */
#define IPX_TYPE_SAP 0x04 /* may also be 0 */
#define IPX_TYPE_SPX 0x05 /* Not yet implemented */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */
struct ipx_address ipx_dest __attribute__ ((packed));
struct ipx_address ipx_source __attribute__ ((packed));
};
#define NCP_ALLOC_SLOT_REQUEST (0x1111)
#define NCP_REQUEST (0x2222)
#define NCP_DEALLOC_SLOT_REQUEST (0x5555)
struct ncp_request_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 function __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
#define NCP_REPLY (0x3333)
#define NCP_POSITIVE_ACK (0x9999)
struct ncp_reply_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 completion_code __attribute__ ((packed));
__u8 connection_state __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
#define NCP_BURST_PACKET (0x7777)
struct ncp_burst_header {
__u16 type __attribute__ ((packed));
__u8 system_flags __attribute__ ((packed));
__u8 stream_type __attribute__ ((packed));
__u32 source_conn __attribute__ ((packed));
__u32 dest_conn __attribute__ ((packed));
__u32 packet_sequence __attribute__ ((packed));
__u32 send_delay __attribute__ ((packed));
__u16 burst_sequence __attribute__ ((packed));
__u16 ack_sequence __attribute__ ((packed));
__u32 burst_length __attribute__ ((packed));
__u32 data_offset __attribute__ ((packed));
__u16 data_bytes __attribute__ ((packed));
__u16 missing_frags __attribute__ ((packed));
};
void handle_ipx (unsigned char *buf, int length, char *frame, int no);
void handle_ncp (struct sockaddr_ipx *source,
struct sockaddr_ipx *target,
unsigned char *buf, int length, int no);
int handle_burst(struct sockaddr_ipx *source,
struct sockaddr_ipx *target,
unsigned char *buf, int length, int no);
#define SAP_MAX_SERVER_NAME_LENGTH 48 /* in network packets */
#define SAP_MAX_SAPS_PER_PACKET 7
#define SAP_SHUTDOWN 16 /* Magic "hops" value to stop SAP advertising */
/* SAP Query structure (returned in sap_packet as an array)
* NBO == Network Byte Order)
*/
typedef struct saps {
__u16 serverType __attribute__ ((packed)); /* NBO */
__u8 serverName[SAP_MAX_SERVER_NAME_LENGTH] __attribute__ ((packed));
struct ipx_address serverAddress __attribute__ ((packed));
__u16 serverHops __attribute__ ((packed)); /* NBO */
} SAPS;
/* General Service/Nearest Server Response SAP packet */
union sap_packet {
unsigned short sapOperation;
struct sap_query {
__u16 sapOperation __attribute__ ((packed));
__u16 serverType __attribute__ ((packed));
} query;
struct sap_response {
__u16 sapOperation __attribute__ ((packed));
/* each SAP can has a max of SAP_MAX_SAPS_PER_PACKET packets */
SAPS sap[SAP_MAX_SAPS_PER_PACKET] __attribute__ ((packed));
} response;
};
/* print out one SAP record */
static void
print_sap(FILE *file, SAPS *sapp)
{
fprintf(file, " Name:%s, serverType 0x%x, ",
sapp->serverName,
ntohs(sapp->serverType));
ipx_fprint_network(file, ntohl(sapp->serverAddress.net));
fprintf(file, ":");
ipx_fprint_node(file, sapp->serverAddress.node);
fprintf(file, ":");
ipx_fprint_port(file, ntohs(sapp->serverAddress.sock));
fprintf(file, " (Hops %d)\n", ntohs(sapp->serverHops));
}
void
handle_ipx (unsigned char *buf, int length, char *frame, int no)
{
struct ipx_packet *h = (struct ipx_packet *)buf;
struct sockaddr_ipx s_addr;
struct sockaddr_ipx d_addr;
union sap_packet *sappacket;
int hbo_dsock; /* Host Byte Order of Destination SOCKet */
int hbo_sapop; /* Host Byte Order of SAP OPeration */
memset(&s_addr, 0, sizeof(s_addr));
memset(&d_addr, 0, sizeof(d_addr));
memcpy(s_addr.sipx_node, h->ipx_source.node, sizeof(s_addr.sipx_node));
s_addr.sipx_port = h->ipx_source.sock;
s_addr.sipx_network = h->ipx_source.net;
memcpy(d_addr.sipx_node, h->ipx_dest.node, sizeof(d_addr.sipx_node));
d_addr.sipx_port = h->ipx_dest.sock;
d_addr.sipx_network = h->ipx_dest.net;
printf("%6.6d %s from ", no, frame);
ipx_print_saddr(&s_addr);
printf(" to ");
ipx_print_saddr(&d_addr);
printf("\n");
if (handle_burst(&s_addr, &d_addr, buf + sizeof(struct ipx_packet),
length - sizeof(struct ipx_packet), no) != 0)
{
return;
}
if ( (ntohs(s_addr.sipx_port) == 0x451)
|| (ntohs(d_addr.sipx_port) == 0x451))
{
handle_ncp(&s_addr, &d_addr, buf + sizeof(struct ipx_packet),
length - sizeof(struct ipx_packet), no);
}
else /* next 3 handle IPX by type vs by socket (one or other) */
/* Note: most things use either ipx_type OR socket, not both */
if (h->ipx_type == 0x01)
printf(" type 0x01 (RIP packet (router))\n");
else
if (h->ipx_type == 0x05)
printf(" type 0x05 (SPX sequenced packet)\n");
else
if (h->ipx_type == 0x14)
printf(" type 0x14 (propogated Client-NetBios)\n");
else
{
hbo_dsock = ntohs(d_addr.sipx_port);
if (hbo_dsock == 0x452) /* SAP */
{
sappacket = (union sap_packet *)
(buf + sizeof(struct ipx_packet));
hbo_sapop = ntohs(sappacket->sapOperation);
if ((hbo_sapop == 0x01) || (hbo_sapop == 0x03))
{
printf(" type 0x%x, SAP op:0x%x %s Query, "
"serverType 0x%x wanted\n",
h->ipx_type, hbo_sapop,
(hbo_sapop == 0x01)?"General Service" :
(hbo_sapop == 0x03)?"Nearest Server" :
"Error",
ntohs(sappacket->query.serverType));
}
else
{
int hops;
hops = ntohs(sappacket->
response.sap[0].serverHops);
printf(" type 0x%x, SAP op:0x%x %s %s\n",
h->ipx_type, hbo_sapop,
(hbo_sapop == 0x02)
? "General Service Response" :
(hbo_sapop == 0x04)
? "Nearest Server Response" :
"Unknown",
(hops >= SAP_SHUTDOWN)
? "[Shutdown]" : "");
/* Service ending */
if (hops >= SAP_SHUTDOWN)
{
print_sap(stdout,
sappacket->response.sap);
}
#ifdef DUMPALLSAPS
/* If you want to dump all SAP's */
else
{ int num_saps;
SAPS *sapp;
num_saps = (length
- sizeof(struct ipx_packet)
- 2) / sizeof(SAPS);
sapp = sappacket->response.sap;
for(; num_saps > 0; sapp++, num_saps--)
print_sap(stdout, sapp);
}
#endif /* DUMPALLSAPS */
}
}
else /* Other IPX types */
printf(" type 0x%x, Socket 0x%x (%s)\n", h->ipx_type,
hbo_dsock,
(hbo_dsock == 0x451) ? "NCP" :
/* (hbo_dsock == 0x452) ? "SAP" :*/
(hbo_dsock == 0x453) ? "RIP" :
(hbo_dsock == 0x455) ? "Client-NetBios" :
(hbo_dsock == 0x456) ? "Diags" :
(hbo_dsock == 0x002) ? "Xecho" :
(hbo_dsock == 0x8063) ? "NVT2" : "Other");
}
}
int handle_burst(struct sockaddr_ipx *source,
struct sockaddr_ipx *target,
unsigned char *buf, int length, int no)
{
struct ncp_burst_header *rq = (struct ncp_burst_header *)buf;
if (rq->type != NCP_BURST_PACKET)
{
return 0;
}
printf("Burst Packet\n");
printf("Stream Type: %02X, System Flags: %02X\n",
rq->stream_type, rq->system_flags);
printf("Source Conn: %08X, Dest Conn: %08X, Packet Seq: %08X\n",
rq->source_conn, rq->dest_conn,
(unsigned int)ntohl(rq->packet_sequence));
printf("Send Delay: %08X, Burst Seq: %04X, Ack Seq: %04X\n",
(unsigned int)ntohl(rq->send_delay), ntohs(rq->burst_sequence),
ntohs(rq->ack_sequence));
printf("Burst Length: %08X\n", (unsigned int)ntohl(rq->burst_length));
printf("Data Offset: %08X, Data Bytes: %04X, Missing Frags: %04X\n",
(unsigned int)ntohl(rq->data_offset), ntohs(rq->data_bytes),
ntohs(rq->missing_frags));
if (ntohs(rq->data_bytes) == 24)
{
struct ncp_burst_request
{
struct ncp_burst_header h __attribute__ ((packed));
__u32 function __attribute__ ((packed));
__u32 file_handle __attribute__ ((packed));
__u8 reserved[8] __attribute__ ((packed));
__u32 file_offset __attribute__ ((packed));
__u32 number_of_bytes __attribute__ ((packed));
} *brq = (struct ncp_burst_request *)rq;
printf("Assuming Burst Request:\n");
printf("%s: Handle %08X, Offset %08X, Bytes %08X\n",
brq->function == 1 ? "Read " : "Write",
brq->file_handle,
(unsigned int)ntohl(brq->file_offset),
(unsigned int)ntohl(brq->number_of_bytes));
}
printf("\n");
return 1;
}
void handle_ncp (struct sockaddr_ipx *source,
struct sockaddr_ipx *target,
unsigned char *buf, int length, int no)
{
struct ncp_request_header *rq = (struct ncp_request_header *)buf;
struct ncp_reply_header *rs = (struct ncp_reply_header *)buf;
unsigned char *data = NULL;
int data_length = 0;
int i;
if (ntohs(rq->type) == NCP_REQUEST)
{
/* Request */
printf("NCP request: conn: %-5d, seq: %-3d, task: %-3d, ",
rq->conn_low + 256 * rq->conn_high,
rq->sequence, rq->task);
data = buf + sizeof(struct ncp_request_header);
data_length = length - sizeof(struct ncp_request_header);
switch(rq->function)
{
case 18:
printf("fn: %-3d\n", rq->function);
printf("Get Volume Info with Number\n");
break;
case 20:
printf("fn: %-3d\n", rq->function);
printf("Get File Server Date and Time\n");
break;
case 21:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[2]);
switch(data[2])
{
case 0:
printf("Send Broadcast Message\n");
break;
case 1:
printf("Get Broadcast Message\n");
break;
}
data += 3;
data_length -= 3;
break;
case 22:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[2]);
switch(data[2])
{
case 00:
printf("Set Directory Handle\n");
break;
case 01:
printf("Get Directory Path\n");
break;
case 02:
printf("Scan Directory Information\n");
break;
case 03:
printf("Get Effective Directory Rights\n");
break;
case 05:
printf("Get Volume Number\n");
break;
case 06:
printf("Get Volume Name\n");
break;
case 10:
printf("Create directory\n");
break;
case 18:
printf("Allocate Permanent Dir Handle\n");
break;
case 20:
printf("Deallocate Directory Handle\n");
break;
case 21:
printf("Get Volume Info with handle\n");
break;
case 39:
printf("Add ext. Trustee to Dir or File\n");
break;
case 48:
printf("Get Name Space Directory Entry\n");
break;
}
data += 3;
data_length -= 3;
break;
case 23:
printf("fn: %-3d, subfn: %-3d\n", rq->function,
data[2]);
switch(data[2])
{
case 17:
printf("Get Fileserver Information\n");
break;
case 22:
printf("Get Station's logged Info (old)\n");
break;
case 23:
printf("Get Crypt Key\n");
break;
case 24:
printf("Encrypted Login\n");
break;
case 28:
printf("Get Connection Information\n");
break;
case 50:
printf("Create Bindery Object\n");
break;
case 53:
printf("Get Bindery Object ID\n");
break;
case 54:
printf("Get Bindery Object Name\n");
break;
case 55:
printf("Scan Bindery Object\n");
break;
case 57:
printf("Create Property\n");
break;
case 59:
printf("Change Property Security\n");
break;
case 60:
printf("Scan Property\n");
break;
case 61:
printf("Read Property Value\n");
break;
case 62:
printf("Write Property Value\n");
break;
case 65:
printf("Add Bindery Object to Set\n");
break;
case 67:
printf("Is Bindery Object in Set\n");
break;
case 70:
printf("Get Bindery Access Level\n");
break;
case 72:
printf("Get Bindery Object Access Level\n");
break;
case 75:
printf("Keyed change password\n");
break;
}
data += 3;
data_length -= 3;
break;
case 24:
printf("fn: %-3d\n", rq->function);
printf("End of Job\n");
break;
case 33:
printf("fn: %-3d\n", rq->function);
printf("Negotiate Buffer size\n");
break;
case 34:
printf("fn: %-3d, subfn: %-3d\n", rq->function,
data[2]);
data += 3;
data_length -= 3;
break;
case 62:
printf("fn: %-3d\n", rq->function);
printf("File Search Initialize\n");
break;
case 63:
printf("fn: %-3d\n", rq->function);
printf("File Search Continue\n");
break;
case 64:
printf("fn: %-3d\n", rq->function);
printf("Search for a file\n");
break;
case 66:
printf("fn: %-3d\n", rq->function);
printf("Close File\n");
break;
case 67:
printf("fn: %-3d\n", rq->function);
printf("Create File\n");
break;
case 72:
printf("fn: %-3d\n", rq->function);
printf("Read from File\n");
break;
case 73:
printf("fn: %-3d\n", rq->function);
printf("Write to File\n");
break;
case 75:
printf("fn: %-3d\n", rq->function);
printf("Set File Time Date Stamp\n");
break;
case 76:
printf("fn: %-3d\n", rq->function);
printf("Open File (old)\n");
break;
case 87:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[0]);
switch(data[0])
{
case 1:
{
unsigned char *p = &(data[0]);
printf("Open Create File or Subdirectory\n");
printf("Name Space: %d\n", p[1]);
printf("Open Create Mode: %x\n", p[2]);
printf("Search Attributes: %x\n",
*(__u16 *)&(p[3]));
printf("Return Information Mask: %x\n",
(unsigned int)(*(__u32 *)&(p[5])));
printf("Desired Access Rights: %x\n",
*(__u16 *)&(p[9]));
break;
}
case 2:
printf("Initialize Search\n");
break;
case 3:
printf("Search for File or Subdirectory\n");
break;
case 6:
printf("Obtain File Or Subdirectory "
"Information\n");
break;
case 8:
printf("Delete a File Or Subdirectory\n");
break;
case 12:
printf("Allocate Short Directory Handle\n");
break;
}
data += 1;
data_length -= 1;
break;
case 97:
printf("fn: %-3d\n", rq->function);
printf("Get Big Packet NCP Max Packet Size\n");
break;
case 101:
printf("fn: %-3d\n", rq->function);
printf("Packet Burst Connection Request\n");
break;
default:
printf("fn: %-3d\n", rq->function);
}
}
if (ntohs(rs->type) == NCP_REPLY)
{
printf("NCP respons: conn: %-5d, seq: %-3d, task: %-3d, ",
rs->conn_low + 256 * rs->conn_high,
rs->sequence, rs->task);
printf("compl: %-3d, conn_st: %-3d\n",
rs->completion_code, rs->connection_state);
data = buf + sizeof(struct ncp_reply_header);
data_length = length - sizeof(struct ncp_reply_header);
}
if (data == NULL)
{
data = buf;
data_length = length;
}
i = 0;
while (i < data_length)
{
int j;
for (j = i; j < i+16; j++)
{
if (j >= data_length)
{
printf(" ");
}
else
{
printf("%-2.2X", data[j]);
}
}
printf(" ");
for (j = i; j < i+16; j++)
{
if (j >= data_length)
{
break;
}
if (isprint(data[j]))
{
printf("%c", data[j]);
}
else
{
printf(".");
}
}
printf("\n");
i += 16;
}
printf("\n");
}
void
main (int argc, char *argv[])
{
unsigned char buf[16384];
unsigned char packet[8192];
unsigned char *b;
int len;
int i = 1;
while (fgets(buf, sizeof(buf), stdin) != NULL)
{
if (strlen(buf) == sizeof(buf)-1)
{
fprintf(stderr, "line too long\n");
exit(1);
}
b = strchr(buf, ' ');
if (b == NULL)
{
fprintf(stderr, "illegal line format\n");
exit(1);
}
*b = '\0';
b += 1;
len = 0;
while ((b[0] != '\0') && (b[1] != '\0'))
{
unsigned int value;
if (sscanf(b, "%2x", &value) != 1)
{
fprintf(stderr, "illegal packet\n");
exit(1);
}
packet[len] = value;
b += 2;
len += 1;
}
handle_ipx(packet, len, buf, i);
i += 1;
}
exit (0);
}

129
ipxdump/ipxutil.c Normal file
View File

@@ -0,0 +1,129 @@
/*
IPX support library - general functions
Copyright (C) 1994, 1995 Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
Copyright (C) 1996, Volker Lendecke <lendecke@namu01.gwdg.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <netinet/in.h>
#include "ipxutil.h"
void
ipx_fprint_node(FILE *file, IPXNode node)
{
fprintf(file,"%02X%02X%02X%02X%02X%02X",
(unsigned char)node[0],
(unsigned char)node[1],
(unsigned char)node[2],
(unsigned char)node[3],
(unsigned char)node[4],
(unsigned char)node[5]
);
}
void
ipx_fprint_network(FILE *file, IPXNet net)
{
fprintf(file,"%08lX",net);
}
void
ipx_fprint_port(FILE *file, IPXPort port)
{
fprintf(file,"%04X",port);
}
void
ipx_fprint_saddr(FILE *file, struct sockaddr_ipx *sipx)
{
ipx_fprint_network(file,ntohl(sipx->sipx_network));
fprintf(file,":");
ipx_fprint_node(file,sipx->sipx_node);
fprintf(file,":");
ipx_fprint_port(file,ntohs(sipx->sipx_port));
}
void
ipx_print_node(IPXNode node)
{
ipx_fprint_node(stdout,node);
}
void
ipx_print_network(IPXNet net)
{
ipx_fprint_network(stdout,net);
}
void
ipx_print_port(IPXPort port)
{
ipx_fprint_port(stdout,port);
}
void
ipx_print_saddr(struct sockaddr_ipx *sipx)
{
ipx_fprint_saddr(stdout,sipx);
}
void
ipx_assign_node(IPXNode dest, IPXNode src)
{
memcpy(dest,src,sizeof(IPXNode));
}
int
ipx_node_equal(IPXNode n1, IPXNode n2)
{
return memcmp(n1,n2,sizeof(IPXNode))==0;
}
int
ipx_sscanf_node(char *buf, IPXNode node)
{
int i;
int n[6];
if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
&(n[0]), &(n[1]), &(n[2]),
&(n[3]), &(n[4]), &(n[5]))) != 6)
{
return -1;
}
for (i=0; i<6; i++)
{
node[i] = n[i];
}
return 0;
}
int
ipx_sscanf_net(char *buf, IPXNet *target)
{
if (sscanf(buf, "%8lX", target) == 1)
{
return 0;
}
return -1;
}
IPXNode ipx_this_node={0,0,0,0,0,0};
IPXNode ipx_broadcast_node={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
char ipx_err_string[IPX_MAX_ERROR+1]="no error detected";

65
ipxdump/ipxutil.h Normal file
View File

@@ -0,0 +1,65 @@
/*
IPX support library
Copyright (C) 1994, 1995 Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
Copyright (C) 1996, Volker Lendecke <lendecke@namu01.gwdg.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __IPXUTIL_H__
#define __IPXUTIL_H__
#include <stdio.h>
#include <linux/ipx.h>
#define IPX_MAX_ERROR (255)
#define IPX_THIS_NET (0)
#define IPX_THIS_NODE (ipx_this_node)
#define IPX_BROADCAST (ipx_broadcast_node)
#define IPX_AUTO_PORT (0)
#define IPX_USER_PTYPE (0)
#define IPX_IS_INTERNAL (1)
typedef unsigned char IPXNode[6];
typedef unsigned long int IPXNet;
typedef unsigned short int IPXPort;
typedef unsigned short int hop_t;
typedef unsigned short int tick_t;
void ipx_print_node(IPXNode node);
void ipx_print_network(IPXNet net);
void ipx_print_port(IPXPort port);
void ipx_print_saddr(struct sockaddr_ipx* sipx);
void ipx_fprint_node(FILE* file,IPXNode node);
void ipx_fprint_network(FILE* file,IPXNet net);
void ipx_fprint_port(FILE* file,IPXPort port);
void ipx_fprint_saddr(FILE* file,struct sockaddr_ipx* sipx);
int ipx_sscanf_node(char *buf, IPXNode node);
int ipx_sscanf_net(char *buf, IPXNet *target);
void ipx_assign_node(IPXNode dest,IPXNode src);
int ipx_node_equal(IPXNode n1,IPXNode n2);
extern IPXNode ipx_this_node;
extern IPXNode ipx_broadcast_node;
extern char ipx_err_string[IPX_MAX_ERROR+1];
#endif

View File

@@ -1,5 +1,5 @@
/*
* ncp_fs.h
* ncp.h
*
* Copyright (C) 1995 by Volker Lendecke
*
@@ -116,6 +116,12 @@ struct ncp_file_info {
__u16 update_time;
};
/* Defines for Name Spaces */
#define NW_NS_DOS 0
#define NW_NS_MAC 1
#define NW_NS_NFS 2
#define NW_NS_FTAM 3
#define NW_NS_OS2 4
/* Defines for ReturnInformationMask */
#define RIM_NAME (0x0001L)

View File

@@ -34,17 +34,16 @@ struct ncp_fs_info {
int buffer_size; /* The negotiated buffer size, to be
used for read/write requests! */
/* Not used yet, but here some day the namespace numbers will be
stored. */
int volume_number;
__u32 directory_id;
};
#define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *)
#define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t)
#define NCP_IOC_NCPREQUEST _IOR('n', 1, struct ncp_ioctl_request)
#define NCP_IOC_GETMOUNTUID _IOW('n', 2, uid_t)
#define NCP_IOC_CONN_LOGGED_IN _IO('n', 3)
#define NCP_GET_FS_INFO_VERSION (1)
#define NCP_IOC_GET_FS_INFO _IOWR('i', 1, unsigned char *)
#define NCP_IOC_GET_FS_INFO _IOWR('n', 4, struct ncp_fs_info)
/*
* The packet size to allocate. One page should be enough.
@@ -62,7 +61,7 @@ struct ncp_fs_info {
#define NCP_READDIR_CACHE_SIZE 64
#define NCP_MAX_RPC_TIMEOUT (60) /* 6 seconds */
#define NCP_MAX_RPC_TIMEOUT (6*HZ)
/* Guess, what 0x564c is :-) */
#define NCP_SUPER_MAGIC 0x564c
@@ -126,9 +125,12 @@ extern struct inode_operations ncp_dir_inode_operations;
void ncp_free_inode_info(struct ncp_inode_info *i);
void ncp_free_all_inodes(struct ncp_server *server);
void ncp_init_root(struct ncp_server *server);
int ncp_conn_logged_in(struct ncp_server *server);
int ncp_stat_root(struct ncp_server *server);
void ncp_init_dir_cache(void);
void ncp_invalid_dir_cache(unsigned long ino);
void ncp_invalid_dir_cache(struct inode *ino);
struct ncp_inode_info *ncp_find_inode(struct inode *inode);
ino_t ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info);
void ncp_invalidate_all_inodes(struct ncp_server *server);
void ncp_free_dir_cache(void);
int ncp_date_dos2unix(__u16 time, __u16 date);

View File

@@ -28,6 +28,7 @@ struct ncp_inode_info {
number of references in memory */
struct ncp_inode_info *dir;
struct ncp_inode_info *next, *prev;
struct inode *inode;
struct nw_file_info finfo;
};

View File

@@ -21,8 +21,9 @@ struct ncp_server {
interest for us later, so we store
it completely. */
struct file *ncp_filp; /* File pointer to ncp socket */
__u8 name_space[NCP_NUMBER_OF_VOLUMES];
struct file *ncp_filp; /* File pointer to ncp socket */
struct file *wdog_filp; /* File pointer to wdog socket */
void *data_ready; /* The wdog socket gets a new
data_ready callback. We store the
@@ -35,7 +36,8 @@ struct ncp_server {
u8 completion; /* Status message from server */
u8 conn_status; /* Bit 4 = 1 ==> Server going down, no
requests allowed anymore */
requests allowed anymore.
Bit 0 = 1 ==> Server is down. */
int buffer_size; /* Negotiated bufsize */
@@ -56,6 +58,18 @@ struct ncp_server {
char root_path; /* '\0' */
};
static inline int
ncp_conn_valid(struct ncp_server *server)
{
return ((server->conn_status & 0x11) == 0);
}
static inline void
ncp_invalidate_conn(struct ncp_server *server)
{
server->conn_status |= 0x01;
}
#endif /* __KERNEL__ */
#endif

View File

@@ -13,7 +13,7 @@
#include <linux/ncp.h>
#include <linux/ncp_fs_i.h>
#define NCP_MOUNT_VERSION 1
#define NCP_MOUNT_VERSION 2
#define NCP_USERNAME_LEN (NCP_BINDERY_NAME_LEN)
#define NCP_PASSWORD_LEN 20
@@ -26,14 +26,14 @@ struct ncp_mount_data {
int version;
unsigned int ncp_fd; /* The socket to the ncp port */
unsigned int wdog_fd; /* Watchdog packets come here */
unsigned int message_fd; /* Not used yet, maybe for messages */
unsigned int message_fd; /* Message notifications come here */
uid_t mounted_uid; /* Who may umount() this filesystem? */
struct sockaddr_ipx serv_addr;
unsigned char server_name[49];
unsigned char server_name[NCP_BINDERY_NAME_LEN];
unsigned char username[NCP_USERNAME_LEN+1];
unsigned char password[NCP_PASSWORD_LEN+1];
unsigned char mount_point[PATH_MAX+1];
unsigned char mounted_vol[NCP_VOLNAME_LEN+1];
unsigned int time_out; /* How long should I wait after
sending a NCP request? */

View File

@@ -3,7 +3,7 @@
#
CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \
$(INCLUDES) \
$(INCLUDES) -DNCPFS_VERSION=\"$(VERSION)\"\
# -DDEBUG_NCP=1 -DDEBUG_NCP_MALLOC
# -DDEBUG_NCP_MALLOC

View File

@@ -20,6 +20,7 @@
#include <linux/ncp_fs.h>
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include "ncplib_kernel.h"
struct ncp_dirent {
@@ -47,7 +48,7 @@ static struct inode *
ncp_iget(struct inode *dir, struct nw_file_info *finfo);
static struct ncp_inode_info *
ncp_find_inode(struct inode *dir, const char *name);
ncp_find_dir_inode(struct inode *dir, const char *name);
static int
ncp_lookup(struct inode *dir, const char *__name,
@@ -96,13 +97,27 @@ str_lower(char *name)
}
}
static inline int
ncp_namespace(struct inode *i)
{
struct ncp_server *server = NCP_SERVER(i);
struct nw_info_struct *info = NCP_ISTRUCT(i);
return server->name_space[info->volNumber];
}
static inline int
ncp_preserve_case(struct inode *i)
{
return (ncp_namespace(i) == NW_NS_OS2);
}
static struct file_operations ncp_dir_operations = {
NULL, /* lseek - default */
ncp_dir_read, /* read - bad */
NULL, /* write - bad */
ncp_readdir, /* readdir */
NULL, /* select - default */
ncp_ioctl, /* ioctl - default */
ncp_ioctl, /* ioctl */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
@@ -129,6 +144,58 @@ struct inode_operations ncp_dir_inode_operations = {
};
/* Here we encapsulate the inode number handling that depends upon the
* mount mode: When we mount a complete server, the memory address of
* the npc_inode_info is used as an inode. When only a single volume
* is mounted, then the dirEntNum is used as the inode number. As this
* is unique for the complete volume, this should enable the NFS
* exportability of a ncpfs-mounted volume.
*/
static inline int
ncp_single_volume(struct ncp_server *server)
{
return (server->m.mounted_vol[0] != '\0');
}
inline ino_t
ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
{
return ncp_single_volume(server)
? info->finfo.i.dirEntNum : (ino_t)info;
}
static inline int
ncp_is_server_root(struct inode *inode)
{
struct ncp_server *s = NCP_SERVER(inode);
return ( (!ncp_single_volume(s))
&& (inode->i_ino == ncp_info_ino(s, &(s->root))));
}
struct ncp_inode_info *
ncp_find_inode(struct inode *inode)
{
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_inode_info *root = &(server->root);
struct ncp_inode_info *this = root;
ino_t ino = inode->i_ino;
do
{
if (ino == ncp_info_ino(server, this))
{
return this;
}
this = this->next;
}
while (this != root);
return NULL;
}
static int
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
{
@@ -142,21 +209,40 @@ ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
all inodes that are in memory. That's why it's enough to index the
directory cache by the inode number. */
static int c_dev = 0;
static unsigned long c_ino = 0;
static int c_size;
static int c_seen_eof;
static int c_last_returned_index;
static struct ncp_dirent* c_entry = NULL;
static int c_lock = 0;
static struct wait_queue *c_wait = NULL;
static inline void
ncp_lock_dircache(void)
{
while (c_lock)
sleep_on(&c_wait);
c_lock = 1;
}
static inline void
ncp_unlock_dircache(void)
{
c_lock = 0;
wake_up(&c_wait);
}
static int
ncp_readdir(struct inode *inode, struct file *filp,
struct dirent *dirent, int count)
{
int result, i = 0;
int result = 0;
int i = 0;
int index = 0;
struct ncp_dirent *entry = NULL;
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino);
struct ncp_inode_info *dir = NCP_INOP(inode);
int filldir(struct dirent *dirent,
const char *name, int len,
@@ -170,9 +256,9 @@ ncp_readdir(struct inode *inode, struct file *filp,
return 1;
}
DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
inode->i_ino, c_ino);
DPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
DPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
inode->i_ino, c_ino);
if (!inode || !S_ISDIR(inode->i_mode))
{
@@ -180,6 +266,12 @@ ncp_readdir(struct inode *inode, struct file *filp,
return -EBADF;
}
if (!ncp_conn_valid(server))
{
return -EIO;
}
ncp_lock_dircache();
if (c_entry == NULL)
{
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
@@ -187,32 +279,37 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (c_entry == NULL)
{
printk("ncp_readdir: no MEMORY for cache\n");
return -ENOMEM;
result = -ENOMEM;
goto finished;
}
}
if (filp->f_pos == 0)
{
ncp_invalid_dir_cache(inode->i_ino);
if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0)
ncp_invalid_dir_cache(inode);
if (filldir(dirent,".",1, filp->f_pos,
ncp_info_ino(server, dir)) < 0)
{
return 0;
goto finished;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
result = ROUND_UP(NAME_OFFSET(dirent)+i+1);
goto finished;
}
if (filp->f_pos == 1)
{
if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0)
if (filldir(dirent,"..",2, filp->f_pos,
ncp_info_ino(server, dir->dir)) < 0)
{
return 0;
goto finished;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
result = ROUND_UP(NAME_OFFSET(dirent)+i+1);
goto finished;
}
if (inode->i_ino == c_ino)
if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
{
for (i = 0; i < c_size; i++)
{
@@ -226,47 +323,54 @@ ncp_readdir(struct inode *inode, struct file *filp,
}
if ((entry == NULL) && c_seen_eof)
{
return 0;
goto finished;
}
}
if (entry == NULL)
{
int entries;
DDPRINTK("ncp_readdir: Not found in cache.\n");
if (inode->i_ino == (int)&(server->root))
if (ncp_is_server_root(inode))
{
result = ncp_read_volume_list(server, filp->f_pos,
NCP_READDIR_CACHE_SIZE);
DPRINTK("ncp_read_volume_list returned %d\n", result);
entries = ncp_read_volume_list(server, filp->f_pos,
NCP_READDIR_CACHE_SIZE);
DPRINTK("ncp_read_volume_list returned %d\n", entries);
}
else
{
result = ncp_do_readdir(server, inode, filp->f_pos,
NCP_READDIR_CACHE_SIZE,
c_entry);
DPRINTK("ncp_readdir returned %d\n", result);
entries = ncp_do_readdir(server, inode, filp->f_pos,
NCP_READDIR_CACHE_SIZE,
c_entry);
DPRINTK("ncp_readdir returned %d\n", entries);
}
if (result < 0)
if (entries < 0)
{
c_dev = 0;
c_ino = 0;
return result;
result = entries;
goto finished;
}
if (result > 0)
if (entries > 0)
{
c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
c_dev = inode->i_dev;
c_ino = inode->i_ino;
c_size = result;
c_size = entries;
entry = c_entry;
c_last_returned_index = 0;
index = 0;
for (i = 0; i < c_size; i++)
if (!ncp_preserve_case(inode))
{
str_lower(c_entry[i].i.entryName);
for (i = 0; i < c_size; i++)
{
str_lower(c_entry[i].i.entryName);
}
}
}
}
@@ -274,7 +378,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (entry == NULL)
{
/* Nothing found, even from a ncp call */
return 0;
goto finished;
}
if (index < c_size)
@@ -282,34 +386,48 @@ ncp_readdir(struct inode *inode, struct file *filp,
/* We found it. For getwd(), we have to return the
correct inode in d_ino if the inode is currently in
use. Otherwise the inode number does not
matter. (You can argue a lot about this..) */
matter. (You can argue a lot about this..) */
struct ncp_inode_info *ino_info;
ino_info = ncp_find_inode(inode, entry->i.entryName);
ino_t ino;
/* Some programs seem to be confused about a zero
inode number, so we set it to one. Thanks to
Gordon Chaffee for this one. */
if (ino_info == NULL)
if (ncp_single_volume(server))
{
ino_info = (struct ncp_inode_info *) 1;
}
ino = (ino_t)(entry->i.dirEntNum);
}
else
{
struct ncp_inode_info *ino_info;
ino_info = ncp_find_dir_inode(inode,
entry->i.entryName);
DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
/* Some programs seem to be confused about a
* zero inode number, so we set it to one.
* Thanks to Gordon Chaffee for this one. */
if (ino_info == NULL)
{
ino_info = (struct ncp_inode_info *) 1;
}
ino = (ino_t)(ino_info);
}
DPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
DPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
entry->f_pos, (ino_t)ino_info) < 0)
entry->f_pos, ino) < 0)
{
return 0;
goto finished;
}
filp->f_pos += 1;
index += 1;
entry += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
result = ROUND_UP(NAME_OFFSET(dirent)+i+1);
goto finished;
}
return 0;
finished:
ncp_unlock_dircache();
return result;
}
static int
@@ -334,7 +452,7 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
if (ncp_get_volume_info_with_number(server, i, &info) != 0)
{
return total_count;
return (total_count - fpos);
}
if (strlen(info.volume_name) > 0)
@@ -353,12 +471,12 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
DPRINTK("ncp_read_volumes: found vol: %s\n",
info.volume_name);
if (ncp_do_lookup(server, NULL,
info.volume_name,
&(entry->i)) != 0)
if (ncp_lookup_volume(server,
info.volume_name,
&(entry->i)) != 0)
{
printk("ncpfs: could not lookup vol "
"%s\n", info.volume_name);
DPRINTK("ncpfs: could not lookup vol "
"%s\n", info.volume_name);
continue;
}
@@ -438,15 +556,17 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
void
ncp_init_dir_cache(void)
{
c_dev = 0;
c_ino = 0;
c_entry = NULL;
}
void
ncp_invalid_dir_cache(unsigned long ino)
ncp_invalid_dir_cache(struct inode *inode)
{
if (ino == c_ino)
if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
{
c_dev = 0;
c_ino = 0;
c_seen_eof = 0;
}
@@ -517,7 +637,8 @@ ncp_iget(struct inode *dir, struct nw_file_info *finfo)
root->next->prev = new_inode_info;
root->next = new_inode_info;
if (!(inode = iget(dir->i_sb, (int)new_inode_info)))
if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
new_inode_info))))
{
printk("ncp_iget: iget failed!");
return NULL;
@@ -567,6 +688,7 @@ ncp_init_root(struct ncp_server *server)
root->finfo.opened = 0;
i->attributes = aDIR;
i->dataStreamSize = 1024;
i->dirEntNum = i->DosDirNum = 0;
i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
@@ -581,6 +703,25 @@ ncp_init_root(struct ncp_server *server)
return;
}
int
ncp_conn_logged_in(struct ncp_server *server)
{
if (server->m.mounted_vol[0] == '\0')
{
return 0;
}
str_upper(server->m.mounted_vol);
if (ncp_lookup_volume(server, server->m.mounted_vol,
&(server->root.finfo.i)) != 0)
{
return -ENOENT;
}
str_lower(server->root.finfo.i.entryName);
return 0;
}
void
ncp_free_all_inodes(struct ncp_server *server)
{
@@ -611,7 +752,7 @@ ncp_free_all_inodes(struct ncp_server *server)
complete linear search through the inodes belonging to this
filesystem. This has to be fixed. */
static struct ncp_inode_info *
ncp_find_inode(struct inode *dir, const char *name)
ncp_find_dir_inode(struct inode *dir, const char *name)
{
struct ncp_server *server = NCP_SERVER(dir);
struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
@@ -624,9 +765,15 @@ ncp_find_inode(struct inode *dir, const char *name)
do
{
if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
if ( (result->dir->finfo.i.dirEntNum == dir_info->dirEntNum)
&& (result->dir->finfo.i.volNumber == dir_info->volNumber)
&& (strcmp(result->finfo.i.entryName, name) == 0))
&& (strcmp(result->finfo.i.entryName, name) == 0)
/* The root dir is never looked up using this
* routine. Without the following test a root
* directory 'sys' in a volume named 'sys' could
* never be looked up, because
* server->root->dir==server->root. */
&& (result != &(server->root)))
{
return result;
}
@@ -646,7 +793,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
struct ncp_server *server;
struct ncp_inode_info *result_info;
int found_in_cache;
int down_case = 0;
char name[len+1];
*result = NULL;
@@ -658,9 +805,14 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
return -ENOENT;
}
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
server = NCP_SERVER(dir);
if (!ncp_conn_valid(server))
{
iput(dir);
return -EIO;
}
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
/* Fast cheat for . */
if (len == 0 || (len == 1 && __name[0] == '.'))
@@ -679,7 +831,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
parent->state = NCP_INODE_LOOKED_UP;
}
*result = iget(dir->i_sb, (int)parent);
*result = iget(dir->i_sb, ncp_info_ino(server, parent));
iput(dir);
if (*result == 0)
{
@@ -693,8 +845,8 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
memcpy(name, __name, len);
name[len] = 0;
result_info = ncp_find_inode(dir, name);
lock_super(dir->i_sb);
result_info = ncp_find_dir_inode(dir, name);
if (result_info != 0)
{
@@ -706,7 +858,8 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
/* Here we convert the inode_info address into an
inode number */
*result = iget(dir->i_sb, (int)result_info);
*result = iget(dir->i_sb, ncp_info_ino(server, result_info));
unlock_super(dir->i_sb);
iput(dir);
if (*result == NULL)
@@ -721,8 +874,10 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
server. */
found_in_cache = 0;
if (dir->i_ino == c_ino)
ncp_lock_dircache();
if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
{
int first = c_last_returned_index;
int i;
@@ -744,33 +899,56 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
}
while (i != first);
}
ncp_unlock_dircache();
if (found_in_cache == 0)
{
str_upper(name);
int res;
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
NCP_ISTRUCT(dir)->entryName, name);
if (ncp_do_lookup(server,
dir->i_ino == (int)&(NCP_SERVER(dir)->root)
? NULL : NCP_ISTRUCT(dir),
name, &(finfo.i)) != 0)
if (ncp_is_server_root(dir))
{
str_upper(name);
down_case = 1;
res = ncp_lookup_volume(server, name, &(finfo.i));
}
else
{
if (!ncp_preserve_case(dir))
{
str_upper(name);
down_case = 1;
}
res = ncp_obtain_info(server,
NCP_ISTRUCT(dir)->volNumber,
NCP_ISTRUCT(dir)->dirEntNum,
name, &(finfo.i));
}
if (res != 0)
{
unlock_super(dir->i_sb);
iput(dir);
return -ENOENT;
}
}
finfo.opened = 0;
str_lower(finfo.i.entryName);
if (down_case != 0)
{
str_lower(finfo.i.entryName);
}
if (!(*result = ncp_iget(dir, &finfo)))
{
unlock_super(dir->i_sb);
iput(dir);
return -EACCES;
}
unlock_super(dir->i_sb);
iput(dir);
return 0;
}
@@ -790,33 +968,51 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
iput(dir);
return -ENOENT;
}
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if (!ncp_preserve_case(dir))
{
str_upper(_name);
}
lock_super(dir->i_sb);
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
OC_MODE_CREATE|OC_MODE_OPEN,
OC_MODE_CREATE|OC_MODE_OPEN|
OC_MODE_REPLACE,
0, AR_READ|AR_WRITE,
&finfo) != 0)
{
unlock_super(dir->i_sb);
iput(dir);
return -EACCES;
}
ncp_invalid_dir_cache(dir->i_ino);
ncp_invalid_dir_cache(dir);
if (!ncp_preserve_case(dir))
{
str_lower(finfo.i.entryName);
}
str_lower(finfo.i.entryName);
finfo.access = O_RDWR;
if (!(*result = ncp_iget(dir, &finfo)) < 0)
{
ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
unlock_super(dir->i_sb);
iput(dir);
return -EINVAL;
}
unlock_super(dir->i_sb);
iput(dir);
return 0;
}
@@ -833,12 +1029,17 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
|| ( (len == 2)
&& (name[1] == '.'))))
{
iput(dir);
return -EEXIST;
}
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if (!ncp_preserve_case(dir))
{
str_upper(_name);
}
if (!dir || !S_ISDIR(dir->i_mode))
{
@@ -846,6 +1047,11 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
iput(dir);
return -ENOENT;
}
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
@@ -857,7 +1063,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
else
{
error = 0;
ncp_invalid_dir_cache(dir->i_ino);
ncp_invalid_dir_cache(dir);
}
iput(dir);
@@ -876,8 +1082,14 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL)
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
if (ncp_find_dir_inode(dir, name) != NULL)
{
iput(dir);
error = -EBUSY;
}
else
@@ -885,17 +1097,21 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if (!ncp_preserve_case(dir))
{
str_upper(_name);
}
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir),
_name)) == 0)
{
ncp_invalid_dir_cache(dir->i_ino);
ncp_invalid_dir_cache(dir);
}
else
{
error = -EINVAL;
error = -EACCES;
}
}
iput(dir);
@@ -914,25 +1130,35 @@ ncp_unlink(struct inode *dir, const char *name, int len)
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL)
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
if (ncp_find_dir_inode(dir, name) != NULL)
{
iput(dir);
error = -EBUSY;
}
else
{
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if (!ncp_preserve_case(dir))
{
str_upper(_name);
}
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir),
_name)) == 0)
{
ncp_invalid_dir_cache(dir->i_ino);
ncp_invalid_dir_cache(dir);
}
else
{
error = -EINVAL;
error = -EACCES;
}
}
iput(dir);
@@ -954,6 +1180,12 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
goto finished;
}
if (!ncp_conn_valid(NCP_SERVER(old_dir)))
{
res = -EIO;
goto finished;
}
if (!new_dir || !S_ISDIR(new_dir->i_mode))
{
printk("ncp_rename: new inode is NULL or not a directory\n");
@@ -961,8 +1193,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
goto finished;
}
if ( (ncp_find_inode(old_dir, old_name) != NULL)
|| (ncp_find_inode(new_dir, new_name) != NULL))
if ( (ncp_find_dir_inode(old_dir, old_name) != NULL)
|| (ncp_find_dir_inode(new_dir, new_name) != NULL))
{
res = -EBUSY;
goto finished;
@@ -970,11 +1202,19 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
strncpy(_old_name, old_name, old_len);
_old_name[old_len] = '\0';
str_upper(_old_name);
if (!ncp_preserve_case(old_dir))
{
str_upper(_old_name);
}
strncpy(_new_name, new_name, new_len);
_new_name[new_len] = '\0';
str_upper(_new_name);
if (!ncp_preserve_case(new_dir))
{
str_upper(_new_name);
}
res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
NCP_ISTRUCT(old_dir), _old_name,
@@ -982,8 +1222,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
if (res == 0)
{
ncp_invalid_dir_cache(old_dir->i_ino);
ncp_invalid_dir_cache(new_dir->i_ino);
ncp_invalid_dir_cache(old_dir);
ncp_invalid_dir_cache(new_dir);
}
else
{

View File

@@ -21,6 +21,7 @@
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/ncp_fs.h>
#include <linux/locks.h>
#include "ncplib_kernel.h"
#include <linux/malloc.h>
@@ -50,8 +51,10 @@ ncp_make_open(struct inode *i, int right)
DPRINTK("ncp_make_open: dirent->opened = %d\n", finfo->opened);
lock_super(i->i_sb);
if (finfo->opened == 0)
{
finfo->access = -1;
/* tries max. rights */
if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
@@ -69,12 +72,10 @@ ncp_make_open(struct inode *i, int right)
{
finfo->access = O_RDONLY;
}
else
{
return -EACCES;
}
}
unlock_super(i->i_sb);
if ( ((right == O_RDONLY) && ( (finfo->access == O_RDONLY)
|| (finfo->access == O_RDWR)))
|| ((right == O_WRONLY) && ( (finfo->access == O_WRONLY)
@@ -99,6 +100,10 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
DPRINTK("ncp_file_read: inode = NULL\n");
return -EINVAL;
}
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
if (!S_ISREG(inode->i_mode))
{
@@ -178,6 +183,10 @@ ncp_file_write(struct inode *inode, struct file *file, char *buf,
DPRINTK("ncp_file_write: inode = NULL\n");
return -EINVAL;
}
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
if (!S_ISREG(inode->i_mode))
{
@@ -239,6 +248,7 @@ ncp_file_write(struct inode *inode, struct file *file, char *buf,
if (pos > inode->i_size)
{
inode->i_size = pos;
ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
}
DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);

View File

@@ -61,50 +61,25 @@ ncp_read_inode(struct inode *inode)
inode->i_ino. Just to make sure everything went well, we
check it's there. */
struct ncp_inode_info *inode_info
= (struct ncp_inode_info *)(inode->i_ino);
struct ncp_inode_info *inode_info = ncp_find_inode(inode);
#if 1
struct ncp_inode_info *root = &(NCP_SERVER(inode)->root);
struct ncp_inode_info *check_info = root;
do
if (inode_info == NULL)
{
if (inode_info == check_info)
{
if (check_info->state == NCP_INODE_LOOKED_UP)
{
DDPRINTK("ncp_read_inode: found it!\n");
goto good;
}
else
{
printk("ncp_read_inode: "
"state != NCP_INODE_LOOKED_UP\n");
goto good;
}
}
check_info = check_info->next;
}
while (check_info != root);
/* Ok, now we're in trouble. The inode info is not there. What
should we do now??? */
printk("ncp_read_inode: inode info not found\n");
return;
}
/* Ok, now we're in trouble. The inode info is not there. What
should we do now??? */
printk("ncp_read_inode: inode info not found\n");
return;
good:
DDPRINTK("ncp_read_inode: read entry %s\n",
inode_info->finfo.i.entryName);
#endif
inode_info->state = NCP_INODE_VALID;
NCP_INOP(inode) = inode_info;
inode_info->inode = inode;
if (NCP_ISTRUCT(inode)->attributes & aDIR)
{
inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
/* for directories in dataStreamSize seems to be some
/* for directories dataStreamSize seems to be some
Object ID ??? */
inode->i_size = 512;
}
@@ -119,7 +94,7 @@ ncp_read_inode(struct inode *inode)
inode->i_nlink = 1;
inode->i_uid = NCP_SERVER(inode)->m.uid;
inode->i_gid = NCP_SERVER(inode)->m.gid;
inode->i_blksize = 1024;
inode->i_blksize = 512;
inode->i_rdev = 0;
if ((inode->i_blksize != 0) && (inode->i_size != 0))
@@ -157,7 +132,9 @@ static void
ncp_put_inode(struct inode *inode)
{
struct nw_file_info *finfo = NCP_FINFO(inode);
struct super_block *sb = inode->i_sb;
lock_super(sb);
if (finfo->opened != 0)
{
if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0)
@@ -176,10 +153,11 @@ ncp_put_inode(struct inode *inode)
{
DDPRINTK("ncp_put_inode: put directory %ld\n",
inode->i_ino);
ncp_invalid_dir_cache(inode->i_ino);
ncp_invalid_dir_cache(inode);
}
clear_inode(inode);
unlock_super(sb);
}
struct super_block *
@@ -204,6 +182,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
printk("ncp warning: mount version %s than kernel\n",
(data->version < NCP_MOUNT_VERSION) ?
"older" : "newer");
sb->s_dev = 0;
return NULL;
}
if ( (data->ncp_fd >= NR_OPEN)
@@ -253,6 +233,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server->wait = NULL;
server->packet = NULL;
server->buffer_size = 0;
server->conn_status = 0;
server->m = *data;
server->m.file_mode = (server->m.file_mode &
@@ -302,7 +283,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
if (!(sb->s_mounted = iget(sb, (int)&(server->root))))
if (!(sb->s_mounted = iget(sb, ncp_info_ino(server, &(server->root)))))
{
sb->s_dev = 0;
printk("ncp_read_super: get root inode failed\n");
@@ -393,6 +374,11 @@ ncp_notify_change(struct inode *inode, struct iattr *attr)
int info_mask;
struct nw_modify_dos_info info;
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
if ((result = inode_change_ok(inode, attr)) < 0)
return result;
@@ -480,7 +466,7 @@ ncp_notify_change(struct inode *inode, struct iattr *attr)
result = 0;
}
ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir));
ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
return result;
}
@@ -510,6 +496,7 @@ init_module( void)
ncp_init_dir_cache();
register_filesystem(&ncp_fs_type);
printk("ncpfs version %s loaded\n", NCPFS_VERSION);
return 0;
}

View File

@@ -29,6 +29,26 @@ ncp_ioctl (struct inode * inode, struct file * filp,
struct ncp_fs_info info;
struct ncp_server *server = NCP_SERVER(inode);
/*
* Binary compatible with 1.3.XX releases.
* Take this out in 2.1.0 development series.
* <mec@duracef.shout.net> 12 Mar 1996
*/
switch(cmd) {
case _IOR('n', 1, unsigned char *):
cmd = NCP_IOC_NCPREQUEST;
break;
case _IOR('u', 1, uid_t):
cmd = NCP_IOC_GETMOUNTUID;
break;
case _IO('l', 1):
cmd = NCP_IOC_CONN_LOGGED_IN;
break;
case _IOWR('i', 1, unsigned char *):
cmd = NCP_IOC_GET_FS_INFO;
break;
}
switch(cmd) {
case NCP_IOC_NCPREQUEST:
@@ -79,6 +99,16 @@ ncp_ioctl (struct inode * inode, struct file * filp,
return server->reply_size;
case NCP_IOC_CONN_LOGGED_IN:
if ( (permission(inode, MAY_WRITE) != 0)
&& (current->uid != server->m.mounted_uid))
{
return -EACCES;
}
return ncp_conn_logged_in(server);
case NCP_IOC_GET_FS_INFO:
if ( (permission(inode, MAY_WRITE) != 0)
@@ -106,6 +136,8 @@ ncp_ioctl (struct inode * inode, struct file * filp,
info.mounted_uid = server->m.mounted_uid;
info.connection = server->connection;
info.buffer_size = server->buffer_size;
info.volume_number = NCP_ISTRUCT(inode)->volNumber;
info.directory_id = NCP_ISTRUCT(inode)->DosDirNum;
memcpy_tofs((struct ncp_fs_info *)arg, &info, sizeof(info));
return 0;

View File

@@ -135,6 +135,11 @@ ncp_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{
DPRINTK("ncp_mmap: called\n");
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
/* only PAGE_COW or read-only supported now */
if (vma->vm_flags & VM_SHARED)
return -EINVAL;

View File

@@ -188,25 +188,6 @@ ncp_get_volume_info_with_number(struct ncp_server *server, int n,
return 0;
}
int
ncp_get_volume_number(struct ncp_server *server, const char *name, int *target)
{
int result;
ncp_init_request_s(server, 5);
ncp_add_pstring(server, name);
if ((result = ncp_request(server, 22)) != 0)
{
ncp_unlock_server(server);
return result;
}
*target = ncp_reply_byte(server, 0);
ncp_unlock_server(server);
return 0;
}
int
ncp_close_file(struct ncp_server *server, const char *file_id)
{
@@ -266,65 +247,27 @@ ncp_extract_file_info(void *structure, struct nw_info_struct *target)
target->entryName[*name_len] = '\0';
return;
}
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target)
ncp_obtain_info(struct ncp_server *server,
__u8 vol_num, __u32 dir_base,
char *path, /* At most 1 component */
struct nw_info_struct *target)
{
__u8 vol_num;
__u32 dir_base;
int result;
char *volname = NULL;
if (target == NULL)
{
return -EINVAL;
}
if (dir == NULL)
{
DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
/* Access a volume's root directory */
ncp_init_request(server);
ncp_add_byte(server, 22); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, 0, 0, 0, /* no handle */
path);
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
dir_base = ncp_reply_dword(server, 4);
vol_num = ncp_reply_byte (server, 8);
ncp_unlock_server(server);
volname = path;
path = NULL;
}
else
{
vol_num = dir->volNumber;
dir_base = dir->DosDirNum;
}
ncp_init_request(server);
ncp_add_byte(server, 6); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* dos name space as dest */
ncp_add_byte(server, server->name_space[vol_num]);
ncp_add_byte(server, server->name_space[vol_num]);
ncp_add_word(server, 0xff); /* get all */
ncp_add_dword(server, RIM_ALL);
ncp_add_handle_path(server, vol_num, dir_base, 1,
path);
ncp_add_handle_path(server, vol_num, dir_base, 1, path);
if ((result = ncp_request(server, 87)) != 0)
{
@@ -333,17 +276,93 @@ ncp_do_lookup(struct ncp_server *server,
}
ncp_extract_file_info(ncp_reply_data(server, 0), target);
ncp_unlock_server(server);
return 0;
}
if (volname != NULL)
static inline int
ncp_has_os2_namespace(struct ncp_server *server, __u8 volume)
{
int result;
__u8 *namespace;
__u16 no_namespaces;
ncp_init_request(server);
ncp_add_byte(server, 24); /* Subfunction: Get Name Spaces Loaded */
ncp_add_word(server, 0);
ncp_add_byte(server, volume);
if ((result = ncp_request(server, 87)) != 0)
{
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
ncp_unlock_server(server);
return 0;
}
no_namespaces = ncp_reply_word(server, 0);
namespace = ncp_reply_data(server, 2);
while (no_namespaces > 0)
{
DPRINTK("get_namespaces: found %d on %d\n", *namespace,volume);
if (*namespace == 4)
{
DPRINTK("get_namespaces: found OS2\n");
ncp_unlock_server(server);
return 1;
}
namespace += 1;
no_namespaces -= 1;
}
ncp_unlock_server(server);
return 0;
}
int
ncp_lookup_volume(struct ncp_server *server,
char *volname,
struct nw_info_struct *target)
{
int result;
int volnum;
DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
ncp_init_request(server);
ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
ncp_add_byte(server, 0); /* DOS namespace */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* faked volume number */
ncp_add_dword(server, 0); /* faked dir_base */
ncp_add_byte(server, 0xff); /* Don't have a dir_base */
ncp_add_byte(server, 1); /* 1 path component */
ncp_add_pstring(server, volname);
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
memset(target, 0, sizeof(*target));
target->DosDirNum = target->dirEntNum = ncp_reply_dword(server, 4);
target->volNumber = volnum = ncp_reply_byte(server, 8);
ncp_unlock_server(server);
server->name_space[volnum] = ncp_has_os2_namespace(server,volnum)?4:0;
DPRINTK("lookup_vol: namespace[%d] = %d\n",
volnum, server->name_space[volnum]);
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
target->attributes = aDIR;
return 0;
}
int
ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
struct nw_info_struct *file,
@@ -354,14 +373,14 @@ ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
ncp_init_request(server);
ncp_add_byte(server, 7); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, server->name_space[file->volNumber]);
ncp_add_byte(server, 0); /* reserved */
ncp_add_word(server, 0x8006); /* search attribs: all */
ncp_add_dword(server, info_mask);
ncp_add_mem(server, info, sizeof(*info));
ncp_add_handle_path(server, file->volNumber,
file->DosDirNum, 1, NULL);
file->dirEntNum, 1, NULL);
if ((result = ncp_request(server, 87)) != 0)
{
@@ -381,11 +400,11 @@ ncp_del_file_or_subdir(struct ncp_server *server,
ncp_init_request(server);
ncp_add_byte(server, 8); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, server->name_space[dir->volNumber]);
ncp_add_byte(server, 0); /* reserved */
ncp_add_word(server, 0x8006); /* search attribs: all */
ncp_add_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
dir->dirEntNum, 1, name);
if ((result = ncp_request(server, 87)) != 0)
{
@@ -417,12 +436,19 @@ ncp_open_create_file_or_subdir(struct ncp_server *server,
struct nw_file_info *target)
{
int result;
__u16 search_attribs = 0x0006;
__u8 volume = (dir != NULL) ? dir->volNumber : target->i.volNumber;
if ((create_attributes & aDIR) != 0)
{
search_attribs |= 0x8000;
}
ncp_init_request(server);
ncp_add_byte(server, 1); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, server->name_space[volume]);
ncp_add_byte(server, open_create_mode);
ncp_add_word(server, 0x8006);
ncp_add_word(server, search_attribs);
ncp_add_dword(server, RIM_ALL);
ncp_add_dword(server, create_attributes);
/* The desired acc rights seem to be the inherited rights mask
@@ -431,13 +457,11 @@ ncp_open_create_file_or_subdir(struct ncp_server *server,
if (dir != NULL)
{
ncp_add_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
ncp_add_handle_path(server, volume, dir->dirEntNum, 1, name);
}
else
{
ncp_add_handle_path(server,
target->i.volNumber, target->i.DosDirNum,
ncp_add_handle_path(server, volume, target->i.dirEntNum,
1, NULL);
}
@@ -473,9 +497,9 @@ ncp_initialize_search(struct ncp_server *server,
ncp_init_request(server);
ncp_add_byte(server, 2); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, server->name_space[dir->volNumber]);
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, dir->volNumber, dir->DosDirNum, 1, NULL);
ncp_add_handle_path(server, dir->volNumber, dir->dirEntNum, 1, NULL);
if ((result = ncp_request(server, 87)) != 0)
{
@@ -499,7 +523,7 @@ ncp_search_for_file_or_subdir(struct ncp_server *server,
ncp_init_request(server);
ncp_add_byte(server, 3); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, server->name_space[seq->volNumber]);
ncp_add_byte(server, 0); /* data stream (???) */
ncp_add_word(server, 0xffff); /* Search attribs */
ncp_add_dword(server, RIM_ALL); /* return info mask */
@@ -534,19 +558,19 @@ ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
ncp_init_request(server);
ncp_add_byte(server, 4); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, server->name_space[old_dir->volNumber]);
ncp_add_byte(server, 1); /* rename flag */
ncp_add_word(server, 0x8006); /* search attributes */
/* source Handle Path */
ncp_add_byte(server, old_dir->volNumber);
ncp_add_dword(server, old_dir->DosDirNum);
ncp_add_dword(server, old_dir->dirEntNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 source component */
/* dest Handle Path */
ncp_add_byte(server, new_dir->volNumber);
ncp_add_dword(server, new_dir->DosDirNum);
ncp_add_dword(server, new_dir->dirEntNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 destination component */

View File

@@ -114,10 +114,16 @@ ncp_write(struct ncp_server *server, const char *file_id,
const char *source, int *bytes_written);
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target);
ncp_obtain_info(struct ncp_server *server,
__u8 vol_num, __u32 dir_base,
char *path, /* At most 1 component */
struct nw_info_struct *target);
int
ncp_lookup_volume(struct ncp_server *server,
char *volname,
struct nw_info_struct *target);
int
ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,

View File

@@ -222,6 +222,7 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
int timeout;
int retrans;
int major_timeout_seen;
int acknowledge_seen;
int n;
int addrlen;
unsigned long old_mask;
@@ -243,7 +244,8 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
return -EBADF;
}
init_timeout = server->m.time_out;
max_timeout = NCP_MAX_RPC_TIMEOUT*HZ/10;
max_timeout = NCP_MAX_RPC_TIMEOUT;
acknowledge_seen = 0;
retrans = server->m.retry_count;
major_timeout_seen = 0;
old_mask = current->blocked;
@@ -296,11 +298,14 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
{
if (timeout > max_timeout)
{
/* JEJB/JSP 2/7/94
* This is useful to see if the system is
* hanging */
printk("NCP max timeout reached\n");
timeout = max_timeout;
/* JEJB/JSP 2/7/94
* This is useful to see if the system is
* hanging */
if (acknowledge_seen == 0)
{
printk("NCP max timeout reached\n");
}
timeout = max_timeout;
}
current->timeout = jiffies + timeout;
schedule();
@@ -373,6 +378,9 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
sock->ops->recvfrom(sock, (void *)&reply,
sizeof(reply), 1, 0,
NULL, &addrlen);
n = 0;
timeout = max_timeout;
acknowledge_seen = 1;
goto re_select;
}
@@ -401,9 +409,8 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
* a null buffer yet. */
sock->ops->recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0,
NULL, &addrlen);
#if 1
printk("ncp_rpc_call: reply mismatch\n");
#endif
DPRINTK("ncp_rpc_call: reply mismatch\n");
goto re_select;
}
/*
@@ -491,7 +498,7 @@ ncp_request(struct ncp_server *server, int function)
if (result != 0)
{
DPRINTK("ncp_completion_code: %d\n", result);
DPRINTK("ncp_completion_code: %x\n", result);
}
return result;
}

View File

@@ -1,6 +1,10 @@
MAN1= slist nprint pqlist
MAN1= slist nprint pqlist nsend pserver ncopy npasswd
MAN1 += nwbols nwboprops nwbpvalues nwfsinfo nwuserlist
MAN5= nwclient
MAN8= ncpmount ncpumount ipx_configure ipx_interface ipx_internal_net ipx_route
MAN8= ncpmount ncpumount ipx_configure ipx_interface ipx_internal_net \
ipx_route nwmsg
MAN8 += nwbocreate nwborm nwbpadd nwbpcreate nwbprm
MAN8 += nwgrant nwrevoke

View File

@@ -1,6 +1,6 @@
.TH IPX_CONFIGURE 8 "IPX Utilities" "Caldera, Inc."
.SH NAME
ipx_configure \- display/configure IPX behavior
ipx_configure \- query/configure IPX behavior
.SH SYNOPSIS
.B ipx_configure
[\-\-help]
@@ -8,7 +8,7 @@ ipx_configure \- display/configure IPX behavior
[\-\-auto_primary=[on|off]]
.SH DESCRIPTION
.B ipx_configure
displays or configures IPX behavior with respect to automatic IPX
queries or configures IPX behavior with respect to automatic IPX
interface detection. IPX can be configured to automatically create
interfaces as they are detected. It can also be configured to
automatically select a primary interface when none is explicitly
@@ -23,20 +23,15 @@ arguments is described in the section
.SS OPTIONS
.TP
.I "\-\-auto_interface=[on|off]"
This argument enables or disables the feature that will automatically detect
whether IPX is use on a network interface. If
.B on
and IPX packets are seen on an interface that interface will be automatically
flagged as an IPX interface. The default setting is
.B off.
This argument either turns on or off the behavior of automatically creating
interfaces.
.TP
.I "\-\-auto_primary=[on|off]"
This argument enables or disables the feature that will automatically select
which IPX interface will be the primary IPX interface. The default setting is
.B off.
This argument either turns on or off the behavior of automatically selecting
a primary interface.
.TP
.I "\-\-help"
Displays summarised usage instructions.
Print out information about utility.
.SH FILES
.I /proc/net/ipx_interface
.SH BUGS

View File

@@ -1,6 +1,6 @@
.TH IPX_INTERFACE 8 "IPX Utilities" "Caldera, Inc."
.SH NAME
ipx_interface \- add, delete, or display IPX interface configuration.
ipx_interface \- add, delete, or display an IPX interface
.SH SYNOPSIS
.B ipx_interface
add [-p] device frame_type [network number]
@@ -9,17 +9,20 @@ add [-p] device frame_type [network number]
del device frame_type
.LP
.B ipx_interface
delall
.LP
.B ipx_interface
check device frame_type
.LP
.B ipx_interface
help
.SH DESCRIPTION
.B ipx_interface
adds, deletes, or displays the configuration of the specified IPX interface.
adds, deletes, or displays IPX interfaces depending on the option selected.
.P
An IPX interface is the item to which IPX sockets are bound.
An IPX interface has an associated IPX Network Number, a physical device
and frame type. A sample IPX Interface might look like:
An IPX interface corresponds to an IPX Network Number which corresponds
to a physical device and frame type. A sample IPX Interface would be:
.LP
Network Number: 0x00ABCDEF
.LP
@@ -35,21 +38,25 @@ or default interface.
.I add
This option is used to create an IPX interface. If the
.B -p
flag is used, the interface is flagged as the
.B PRIMARY
interface. The IPX network number may optionally be specified. If it is not
specified it is set to 0 which indicates it should be automatically detected
by analysis of the existing IPX traffic on the network.
flag is used, the interface is made
.B
PRIMARY.
The network number can be optionally assigned. If it is not assigned, it
is set to 0 which indicates it should be detected from the traffic on the
network.
.TP
.I del
This option is used to delete an IPX interface.
.TP
.I delall
This option is used to delete all IPX interfaces.
.TP
.I check
This option is used to display the network number associated with a specified
device and frame type combination.
This option is used to display the device, frame type, and network number
of an IPX interface.
.TP
.I help
This option displays summarised usage instructions.
This option displays information about the utility.
.SH FILES
.I /proc/net/ipx_interface /proc/net/ipx_route
.SH BUGS

View File

@@ -1,6 +1,6 @@
.TH IPX_ROUTE 8 "IPX Utilities" "Caldera, Inc."
.SH NAME
ipx_route \- add or delete an IPX route.
ipx_route \- add or delete IPX route
.SH SYNOPSIS
.B ipx_route
add target_network router_network router_node
@@ -10,11 +10,11 @@ del target_network
.SH DESCRIPTION
.B ipx_route
adds or deletes an IPX route.
The kernel IPX software stores only one route to any target network.
The kernel IPX stores only one route per target network at a time.
.SS OPTIONS
.TP
.I add
This option is used to configure a route to a target network.
This option is used to set up the route to a target network.
.TP
.I del
This option is used to delete the route to a target network.

96
man/ncopy.1 Normal file
View File

@@ -0,0 +1,96 @@
.\"
.\" Man page for the ncopy program
.\"
.TH NCOPY 1 17/03/1996 ncopy ncopy
.SH NAME
ncopy \- NetWare file copy
.SH SYNOPSIS
.B ncopy -V
.B ncopy
[
.B -vn
]
[
.B -s
.I amount
]
.B file destinationfile|directory
.B ncopy
[
.B -vn
]
[
.B -s
.I amount
]
.B file1
[
.B file2 ...
]
.B directory
.SH DESCRIPTION
With
.B ncopy
you can copy files to different locations on a single NetWare file
server without generating excess network traffic. The program uses
a NetWare function to do the copy rather than transferring the file
across the network for both the read and write.
If the last argument is a directory,
.B ncopy
will copy the source file(s) into the directory. If only two files
are given and the last argument is not a directory, it will copy the
source file to the destination file.
If the source and destination files are not on the same NetWare server
(or are not on NetWare servers at all),
.B ncopy
will do a normal file copy.
.SH OPTIONS
.B -V
.RS 3
Show version number and exit
.RE
.B -v
.RS 3
Verbose copy. Will show current file and percentage completion.
.RE
.B -n
.RS 3
Nice NetWare copy. Will sleep for a second between copying blocks on
the NetWare server. Gives other people a chance to do some work on
the NetWare server when you are copying large files. This has no
effect if you are not copying on a NetWare server.
.RE
.B -s
.I amount
.RS 3
Nice time slice factor. Used in conjunction with the
.B -n
option, this specifies the number of 100K blocks to copy before sleeping.
Default is 10. (1 Megabyte)
.RE
.SH BUGS
.B ncopy
cannot recurse into directories.
Does not work on NetWare volumes mounted with the
.I -V
option to
.B ncpmount.
.SH "SEE ALSO"
.B ncpmount(8), ncpumount(8)
.SH CREDITS
ncopy was written by Brian G. Reid (breid@tim.com) and
Tom C. Henderson (thenderson@tim.com).
Many thanks to Volker Lendecke (lendecke@namu01.gwdg.de) for the ncpfs
and ncplib which made ncopy possible.

View File

@@ -33,7 +33,18 @@ ncpmount \- mount all volumes of a specified Novell fileserver.
] [
.B -d
.I dir mode
]
] [
.B -V
.I volume
] [
.B -t
.I time_out
] [
.B -r
.I retry_count
] [
.B -v
]
mount-point
.SH DESCRIPTION
@@ -186,6 +197,71 @@ can very well choose a file mode that tells that you have. This
certainly cannot override the restrictions imposed by the server.
.RE
.B -V
.I volume
.RS 3
There are 2 general ways you can mount a NetWare server's disk space:
Either you can mount all volumes under one directory, or you can mount
only a single volume.
When you choose to mount the complete disk space at once, you have the
advantage that only one Linux mount point and only one
NetWare connection is used for all the volumes of this server. Both of
these are limited resources. (Although raising the number of Linux
mount points is significantly cheaper than raising the number of
available NetWare connections ;-))
When you specify to mount a single volume by using the option
.B -V
.I volume,
you have the big advantage that nfsd is able to re-export this mounted
directory. You must invoke
.B nfsd
and
.B mountd
with the option
.I --re-export
to make nfsd re-export ncpfs mounted directories. This uses one Linux
mount point and one NetWare connection per mounted volume. Maybe
sometime in the future I will make it possible to mount all volumes on
different mount points, using only one connection.
.RE
.B -t
.I time_out
.RS 3
With
.B -t
you can adjust the time ncpfs waits for the server to answer a request
it sent. Use the option to raise the timeout value when your ncpfs
connections seem to be unstable although your servers are well
up. This can happen when you have very busy servers, or servers that
are very far away.
.I time_out
is specified in 1/100s, the current default value is 60.
.RE
.B -r
.I retry_count
.RS 3
As
.B -t, -r
can be used to tune the ncpfs connection to the server. With
retry_count you can specify how many times ncpfs will attempt to send
a packet to the server before it decides the connection is dead. The
current default value is 5.
Currently ncpfs is not too clever when trying to find out that
connections are dead. If anybody knows how to do that correctly, as it
is done by commercial workstations, please tell me.
.RE
.B -v
.RS 3
Print ncpfs version number
.RE
.SH NOTES
You must configure the IPX subsystem before ncpmount will work.
It is especially important that there is a route to the internal network
@@ -205,7 +281,7 @@ Most diagnostics issued by ncpfs are logged by syslogd. Normally
nothing is printed, only error situations are logged there.
.SH SEE ALSO
.B syslogd(8), ncpumount(8)
.B syslogd(8), ncpumount(8), nfsd(8), mountd(8)
.SH CREDITS
ncpfs would not have been possible without lwared, written by Ales

55
man/npasswd.1 Normal file
View File

@@ -0,0 +1,55 @@
.TH NPASSWD 1 06/22/1996 npasswd npasswd
.SH NAME
npasswd \- Change a user's password
.SH SYNOPSIS
.B npasswd
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
]
.B -t
.I object type
]
.SH DESCRIPTION
With
.B npasswd,
you can change your password on a NetWare server.
.B npasswd
asks for the old password and twice for the new password. Then it
changes the password on the server.
.SH OPTIONS
.B -h
.RS 3
With -h npasswd prints a little help text.
.RE
.B -S
.I server
.RS 3
is the name of the server you want to use.
.RE
.B -U
.I user name
.RS 3
is the name of the bindery object whose password is to be changed.
.RE
.B -t
.I object type
.RS 3
is the bindery object type of the object whose password is to be
changed.
.RE
.SH CREDITS
npasswd would not have been possible without the work of Guntram
Blom. Look at nwcrypt.c for his work.

108
man/nsend.1 Normal file
View File

@@ -0,0 +1,108 @@
.TH NSEND 1 03/21/1996 nsend nsend
.SH NAME
nsend \- Send messages to users
.SH SYNOPSIS
.B nsend
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
]
.I user message
.SH DESCRIPTION
With
.B nsend,
you can send messages to the user's workstations.
.B nsend
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of .nwclient MUST be 600, for security reasons.
.SH OPTIONS
.B user
.RS 3
.B user
is the NetWare User-ID of the user to receive the message.
.RE
.B message
.RS 3
.B message
is the message to be sent. Please note that this has to be a single
command line argument. If you want to send a message that contains
spaces, you have to quote them on the command line. For example, to
annoy your system administrator, you should try
nsend supervisor 'I know how this works!'
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user name
.RS 3
If the user name your NetWare administrator gave to you differs
from your unix user-id, you should use
.B -U
to tell the server about you NetWare user name.
.RE
.B -P
.I password
.RS 3
You may want to give the password required by the server on the
command line. You should be careful to use passwords in scripts.
.RE
.B -n
.RS 3
.B -n
should be given to mount shares which do not require a password to log in.
If neither
.B -n
nor
.B -P
are given, nsend prompts for a password.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.SH BUGS
nsend only supports servers with up to 255 connections. I do not know
the NCP functions for larger servers. If anybody knows them, please
tell me!
.SH SEE ALSO
.B nwclient(5), nprint(1), slist(1), ncpmount(8), ncpumount(8)
.SH CREDITS
nsend was written by looking at mars_nwe's message handling. Thanks to
Martin Stover <mstover@freeway.de>

133
man/nwbocreate.8 Normal file
View File

@@ -0,0 +1,133 @@
.TH NWBOCREATE 8 7/9/1996 nwbocreate nwbocreate
.SH NAME
nwbocreate \- Create a NetWare Bindery Object
.SH SYNOPSIS
.B nwbocreate
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -r
.I read-flag
] [
.B -w
.I write-flag
]
.SH DESCRIPTION
.B nwbocreate
creates the specified NetWare Bindery Object.
.B nwbocreate
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwbocreate
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be created.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B -r
.I read-flag
.B -w
.I write-flag
.RS 3
Read security and write security may each have one of the following values:
ANYONE: Anyone may access the object
LOGGED: Anyone who is logged in may access the
object
OBJECT: Anyone who is logged in as the object or
SUPERVISOR equivalent may access the
object
SUPERVISOR: Anyone who is logged in as SUPERVISOR
equivalent may access the object
NETWARE: Only the Bindery may access the object
.RE
.SH AUTHORS
nwbocreate was written by Volker Lendecke with the corresponding
Caldera utility in mind. See the Changes file of ncpfs for other
contributors.

117
man/nwbols.1 Normal file
View File

@@ -0,0 +1,117 @@
.TH NWBOLS 1 7/9/1996 nwbols nwbols
.SH NAME
nwbols \- List NetWare Bindery Objects
.SH SYNOPSIS
.B nwbols
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -t
.I type
] [
.B -v
] [
.B pattern
]
.SH DESCRIPTION
.B nwbols
lists the specified NetWare Bindery Objects visible for the user.
.B nwbols
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwbols
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -t
.I type
.RS 3
You can restrict the objects listed by specifying the type of the
objects to be listed.
.I type
must be given as a decimal number.
.RE
.B pattern
.RS 3
Specifying a pattern is another way to restrict the objects
listed. Please note that this pattern is evaluated by the NetWare
server. grep would be a better candidate for complex patterns.
.RE
.B -v
.RS 3
By default, the object's name, its ID and its type are listed by
.B nwbols.
In the verbose mode, activated by
.B -v,
the object flags, its security byte and the properties flag is also
listed.
.RE
.SH AUTHORS
nwbols was written by Volker Lendecke. See the Changes file of ncpfs
for other contributors.

118
man/nwboprops.1 Normal file
View File

@@ -0,0 +1,118 @@
.TH NWBOPROPS 1 7/9/1996 nwboprops nwboprops
.SH NAME
nwboprops \- List properies of a NetWare Bindery Object
.SH SYNOPSIS
.B nwboprops
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -v
]
.SH DESCRIPTION
.B nwboprops
lists all the properties of the specified NetWare Bindery Objects.
.B nwboprops
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwboprops
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be inspected.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B -v
.RS 3
By default, only the property name is listed. In verbose mode,
activated by
.B -v,
the property flag, the property security byte and the value flag are
also listed.
.RE
.SH AUTHORS
nwboprops was written by Volker Lendecke with the corresponding
Caldera utility in mind. See the Changes file of ncpfs for other
contributors.

106
man/nwborm.8 Normal file
View File

@@ -0,0 +1,106 @@
.TH NWBORM 8 7/9/1996 nwborm nwborm
.SH NAME
nwborm \- Remove a NetWare Bindery Object
.SH SYNOPSIS
.B nwborm
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
]
.SH DESCRIPTION
.B nwborm
removes the specified NetWare Bindery Objects.
.B nwborm
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwborm
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be deleted.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.SH AUTHORS
nwborm was written by Volker Lendecke with the corresponding Caldera
utility in mind. See the Changes file of ncpfs for other contributors.

145
man/nwbpadd.8 Normal file
View File

@@ -0,0 +1,145 @@
.TH NWBPADD 8 7/9/1996 nwbpadd nwbpadd
.SH NAME
nwbpadd \- Set the value of a NetWare Bindery Property
.SH SYNOPSIS
.B nwbpadd
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -p
.I property
]
.B value
.SH DESCRIPTION
.B nwbpadd
sets the value of a ITEM type property, and adds bindery objects to a
SET type property.
.B nwbpadd
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwbpadd
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be touched.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B -p
.I property
.RS 3
The name of the property to be set.
.RE
.B value
.RS 3
If property is of type SET, value is an object id in hexadecimal
notation. Otherwise, value is either a string value to be written, or
a count of bytes to be written. The latter is assumed if more than one
value argument is given. The count is decimal, and the following
arguments are interpreted as bytes in hexadecimal notation.
Examples:
All these examples assume the existence of the file
$HOME/.nwclient. Otherwise, the server and user would have to be
specified.
nwbpadd -o linus -t 1 -p groups_i\\'m_in os_hackers
In this example, user linus is added to the group os_hackers. Please
note that the ' has to be quoted.
nwbpadd -o linus -t 1 -p identification "Linus Torvalds"
User linus is given his real name :-).
nwbpadd -o linus -t 1 -p revision -v 04 00 00 01 0b
A new 4-byte binary value 0x0000010b (hi-lo order, no byte-swapping) is added
to the "REVISION" property of the user "linus".
.SH AUTHORS
nwbpadd was written by Volker Lendecke with the corresponding Caldera
utility in mind. See the Changes file of ncpfs for other contributors.

154
man/nwbpcreate.8 Normal file
View File

@@ -0,0 +1,154 @@
.TH NWBPCREATE 8 7/9/1996 nwbpcreate nwbpcreate
.SH NAME
nwbpcreate \- Create a NetWare Bindery Propery
.SH SYNOPSIS
.B nwbpcreate
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -p
.I property
] [
.B -s
] [
.B -r
.I read-flag
] [
.B -w
.I write-flag
]
.SH DESCRIPTION
.B nwbpcreate
creates the specified NetWare Bindery Propery.
.B nwbpcreate
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwbpcreate
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be touched.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B -p
.I property
.RS 3
The name of the property to be created.
.RE
.B -s
.RS 3
By default,
.B nwbpcreate
creates properties of type ITEM. If you want to create a property of
type SET, such as groups_i\\'m_in, you must use the
.B -s
option.
.RE
.B -r
.I read-flag
.B -w
.I write-flag
.RS 3
Read security and write security may each have one of the following values:
ANYONE: Anyone may access the property
LOGGED: Anyone who is logged in may access the
property
OBJECT: Anyone who is logged in as the object or
SUPERVISOR equivalent may access the
property
SUPERVISOR: Anyone who is logged in as SUPERVISOR
equivalent may access the property
NETWARE: Only the Bindery may access the property
.RE
.SH AUTHORS
nwbpcreate was written by Volker Lendecke with the corresponding
Caldera utility in mind. See the Changes file of ncpfs for other
contributors.

116
man/nwbprm.8 Normal file
View File

@@ -0,0 +1,116 @@
.TH NWBPRM 8 7/9/1996 nwbprm nwbprm
.SH NAME
nwbprm \- Remove a NetWare Bindery Propery
.SH SYNOPSIS
.B nwbprm
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -p
.I property
]
.SH DESCRIPTION
.B nwbprm
removes the specified NetWare Bindery Propery.
.B nwbprm
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwbprm
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be touched.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B -p
.I property
.RS 3
The name of the property to be removed.
.RE
.SH AUTHORS
nwbprm was written by Volker Lendecke with the corresponding
Caldera utility in mind. See the Changes file of ncpfs for other
contributors.

128
man/nwbpvalues.1 Normal file
View File

@@ -0,0 +1,128 @@
.TH NWBPVALUES 8 7/9/1996 nwbpvalues nwbpvalues
.SH NAME
nwbpvalues \- Print a NetWare Bindery Propery's contents
.SH SYNOPSIS
.B nwbpvalues
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -p
.I property
] [
.B -v
]
.SH DESCRIPTION
.B nwbpvalues
prints the contents of a SET property.
.B nwbpvalues
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwbpvalues
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be looked up.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B -p
.I property
.RS 3
The name of the property to be printed.
.RE
.B -v
.RS 3
By default, the object's name, its ID and its type are listed by
.B nwbols.
In the verbose mode, activated by
.B -v,
the object flags, its security byte and the properties flag is also
listed.
.RE
.SH AUTHORS
nwbpvalues was written by Volker Lendecke with the corresponding
Caldera utility in mind. See the Changes file of ncpfs for other
contributors.

52
man/nwfsinfo.1 Normal file
View File

@@ -0,0 +1,52 @@
.TH NWFSINFO 1 07/22/1996 nwfsinfo nwfsinfo
.SH NAME
nwfsinfo \- Print some information about the file server
.SH SYNOPSIS
.B nwfsinfo
[
.B -h
] [
.B -S
.I server
] [
.B -t
] [
.B -i
] [
.B -d
]
.SH DESCRIPTION
.B nwfsinfo
prints some of the information the NetWare servers present without
logging in. The options control what is printed. You should try the
different options to find out what is printed when.
.SH OPTIONS
.B -h
.RS 3
With -h nwfsinfo prints a little help text.
.RE
.B -S
.I server
.RS 3
is the name of the server you want to know something about.
.RE
.B -t
.RS 3
Print what the file server believes to be the current time.
.RE
.B -d
.RS 3
Print the so-called file server description strings.
.RE
.B -i
.RS 3
Print the extended file server information such as NetWare version,
maximum connections an others.
.RE

148
man/nwgrant.8 Normal file
View File

@@ -0,0 +1,148 @@
.TH NWGRANT 8 7/9/1996 nwgrant nwgrant
.SH NAME
nwgrant \- Add Trustee Rights to a directory
.SH SYNOPSIS
.B nwgrant
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -r
.I rights
]
.B directory
.SH DESCRIPTION
.B nwgrant
adds the specified bindery object with the corresponding trustee
rights to the directory.
.B nwgrant
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwgrant
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be added as trustee.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B -r
.I rights
.RS 3
You must tell
.B nwgrant
which rights it should grant to the bindery object.
The new rights for the object is specified by
.I rights,
which is the sum of the following hexadecimal individual rights values:
00 = no access
01 = read access
02 = write access
04 = open access
08 = create access
10 = delete access
20 = ownership access
40 = search access
80 = modify access
for a possible total of "ff" for all rights.
.RE
.B directory
.RS 3
You must specify the directory to which to add the object as
trustee. This has to be done in fully qualified NetWare notation.
Example:
nwgrant -o linus -t 1 -r ff 'data:home\\linus'
With this example, user linus is given all rights to his home
directory on the data volume. This example assumes the existence of
the file $HOME/.nwclient.
.SH AUTHORS
nwgrant was written by Volker Lendecke with the corresponding NetWare
utility in mind. See the Changes file of ncpfs for other contributors.

33
man/nwmsg.8 Normal file
View File

@@ -0,0 +1,33 @@
.TH NWMSG 8 02/29/1996 nwmsg nwmsg
.SH NAME
nwmsg \- Deliver NetWare user broadcast messages
.SH SYNOPSIS
.B nwmsg
.I mount-point
.SH DESCRIPTION
.B nwmsg
is called by kerneld when a broadcast message arrives from a NetWare
server.
.B nwmsg
fetches this message via the mount point and delivers it to
the user using the same way write(1) uses.
Please note that
.I kerneld
must run when broadcast messages should be delivered to users.
NetWare servers can send asynchronous broadcast messages to users,
either on explicit request by another user, or when the server is
shutdown. The client workstation is informed about this event by an
IPX packet on a special socket, the message socket.
This can happen at any time, so the user has to be informed about this
event whenever it appears. I chose to use the kerneld feature of the
Linux kernel to call the program nwmsg. For nwmsg, I used the relevant
parts of the
.I write
program, so you can expect the NetWare broadcast
messages to appear where user messages would appear.
.SH SEE ALSO
ncpmount(8), kerneld(8), write(1)

124
man/nwrevoke.8 Normal file
View File

@@ -0,0 +1,124 @@
.TH NWREVOKE 8 7/9/1996 nwrevoke nwrevoke
.SH NAME
nwrevoke \- Revoke a Trustee Right from a directory
.SH SYNOPSIS
.B nwrevoke
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -o
.I object name
] [
.B -t
.I type
] [
.B -r
.I rights
]
.B directory
.SH DESCRIPTION
.B nwrevoke
revokes the specified bindery object with the corresponding trustee
rights from the directory.
.B nwrevoke
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwrevoke
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -o
.I object name
.RS 3
The name of the object to be added as trustee.
.RE
.B -t
.I object type
.RS 3
The type of the object.
.I Object type
must be specified as a decimal value. Common values are 1 for user
objects, 2 for group objects and 3 for print queues. Other values are
allowed, but are usually used for specialized applications.
.RE
.B directory
.RS 3
You must specify the directory from which to remove the object as
trustee. This has to be done in fully qualified NetWare notation.
Example:
nwrevoke -o linus -t 1 'src:bsd_src'
With this example, user linus is removed as trustee from the bsd_src
directory on the src volume.
.SH AUTHORS
nwrevoke was written by Volker Lendecke with the corresponding NetWare
utility in mind. See the Changes file of ncpfs for other contributors.

93
man/nwuserlist.1 Normal file
View File

@@ -0,0 +1,93 @@
.TH NWUSERLIST 1 7/22/1996 nwuserlist nwuserlist
.SH NAME
nwuserlist \- List Users logged in at a NetWare server
.SH SYNOPSIS
.B nwuserlist
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -a
]
.SH DESCRIPTION
.B nwuserlist
lists the users logged in at a NetWare server, together with their
connection number and their login time.
.B nwuserlist
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of $HOME/.nwclient MUST be 600 for security reasons.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for login.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for login. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nwuserlist
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the login.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -a
.RS 3
With option -a the IPX address of the station the user is logged in
from is printed as well.
.RE
.SH AUTHORS
nwuserlist was written by Volker Lendecke. See the Changes file of ncpfs
for other contributors.

142
man/pserver.1 Normal file
View File

@@ -0,0 +1,142 @@
.TH PSERVER 1 02/10/1996 pserver pserver
.SH NAME
pserver \- NetWare print server
.SH SYNOPSIS
.B pserver
[
.B -S
.I server
] [
.B -h
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -q
.I queue name
] [
.B -c
.I command
] [
.B -j
.I job type
] [
.B -t
.I timeout
] [
.B -d
]
.SH DESCRIPTION
.B pserver
is a program that connects to print queues on NetWare servers and
feeds incoming print jobs to the Linux printing system.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the print server name at the server.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for the print server at the server. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, pserver
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if the print server does not require a password.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -q
.I queue name
.RS 3
.B queue name
is the name of the print queue you want to service.
.RE
.B -c
.I command
.RS 3
When a job is received from the print queue, pserver forks off a new
process, and feeds the job file to stdin.
.I command
is the printing command that is executed for each job. The default
command is 'lpr'.
.RE
.B -j
.I job type
.RS 3
Each job in a NetWare print queue has a job type. For print jobs, this
corresponds to the number of the form the job should be printed
on. You can tell pserver that it should only receive jobs for one
specific form from the queue. The default is -1, which means that
everything is received.
.RE
.B -t
.I timeout
.RS 3
Pserver is not informed by NetWare servers when new jobs arrive. So a
polling scheme has to be used. When there are no jobs to service,
.I timeout
tells pserver how long to wait between two requests. The default is 30
seconds. When a job is finished, pserver asks the NetWare server
immediately for a new job, and does not wait
.I timeout
seconds.
.RE
.B -d
.RS 3
Normally, pserver daemonizes itself.
.B -d
tells it not to do so. This is useful if you want to see the
diagnostic messages that are printed when a error occurs.
.RE
.SH SEE ALSO
.B nwclient(5), slist(1), pqlist(1), ncpmount(8), ncpumount(8)
.SH CREDITS
pserver was written by Volker Lendecke (lendecke@namu01.gwdg.de)

View File

@@ -1,17 +0,0 @@
Begin3
Title: ncpfs
Version: 0.14
Entered-date: 09. February 1996
Description: With ncpfs you can mount volumes of your novell
server under Linux. You need kernel 1.2.x or
1.3.54 and above. ncpfs does NOT work with any 1.3.x
kernel below 1.3.54.
Keywords: filesystem kernel ncp novell netware
Author: lendecke@namu01.gwdg.de (Volker Lendecke)
Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke)
Primary-site: linux01.gwdg.de:/pub/ncpfs
Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/
~70k ncpfs-0.14.tgz
~ 1k ncpfs-0.14.lsm
Copying-policy: GPL
End

19
ncpfs-2.0.3.lsm Normal file
View File

@@ -0,0 +1,19 @@
Begin3
Title: ncpfs
Version: 2.0.3
Entered-date: 22. July 1996
Description: With ncpfs you can mount volumes of your netware
server under Linux. You can also print to netware
print queues and spool netware print queues to the
Linux printing system. You need kernel 1.2.x or
1.3.71 and above. ncpfs does NOT work with any 1.3.x
kernel below 1.3.71.
Keywords: filesystem ncp novell netware printing
Author: lendecke@namu01.Num.Math.Uni-Goettingen.de (Volker Lendecke)
Maintained-by: lendecke@namu01.Num.Math.Uni-Goettingen.de (Volker Lendecke)
Primary-site: ftp.gwdg.de:/pub/linux/misc/ncpfs
Alternate-site: sunsite.unc.edu:/pub/Linux/system/Filesystems/ncpfs
~128k ncpfs-2.0.3.tgz
~ 1k ncpfs-2.0.3.lsm
Copying-policy: GPL
End

View File

@@ -2,40 +2,91 @@
# Makefile for the linux ncp-filesystem routines.
#
UTIL_EXECS = ncpmount ncpumount nprint slist pqlist fsinfo pserver
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
USERUTILS = slist pqlist nwfsinfo pserver nprint nsend ncopy npasswd
USERUTILS += nwbols nwbocreate nwborm nwboprops
USERUTILS += nwbpcreate nwbprm nwbpvalues nwbpadd
USERUTILS += nwgrant nwrevoke nwuserlist
UIDUTILS = ncpmount ncpumount
SBINUTILS = nwmsg
# CFLAGS = -Wall $(INCLUDES) -O2 $(KERNELD)
CFLAGS = -Wall $(INCLUDES) $(KERNELD) -O2
UTIL_EXECS = $(USERUTILS) $(UIDUTILS) $(SBINUTILS)
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
CFLAGS = -Wall $(INCLUDES) $(KERNELD) -DNCPFS_VERSION=\"$(VERSION)\"
CC = gcc
#CFLAGS += -g
CFLAGS += -O2
ifeq ($(HAVE_ELF),yes)
PIC_FLAG = -fPIC
NCP_LIB = libncp.so.1.0
LIB_LINK_COMMAND = gcc -shared -Wl,-soname,libncp.so.1 -o $(NCP_LIB)
INSTALL_LIB = install $(NCP_LIB) -m 755 /lib; \
ln -sf $(NCP_LIB) /lib/libncp.so.1; \
ldconfig
export PIC_FLAG
else
NCP_LIB = libncp.a
LIB_LINK_COMMAND = ar r libncp.a
endif
default:
make -C ..
all: $(UTILS) ncptest
install: all
for i in $(UTIL_EXECS); \
do install --strip $(INTERM_BINDIR)/$$i -m 755 $(BINDIR); done
for i in $(UIDUTILS); do chmod 4755 $(BINDIR)/$$i; done
do install $(INTERM_BINDIR)/$$i -m 755 $(BINDIR); done
for i in $(UIDUTILS); \
do install $(INTERM_BINDIR)/$$i -m 4755 $(BINDIR); done
for i in $(SBINUTILS); \
do install $(INTERM_BINDIR)/$$i -m 755 $(SBINDIR); done
$(INSTALL_LIB)
$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) ncplib.o
$(CC) -o $@ $(addsuffix .o,$(notdir $@)) ncplib.o
$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) $(NCP_LIB)
$(CC) -o $@ $(addsuffix .o,$(notdir $@)) -L. -lncp
ncplib.o: ncplib.c ncplib.h
$(CC) $(CFLAGS) -finline-functions -c ncplib.c
ncplib.o: ncplib.c ncplib.h ncplib_err.h
$(CC) $(CFLAGS) $(PIC_FLAG) -finline-functions -c ncplib.c
COM_ERR_CFILES = com_err/com_err.c com_err/error_message.c com_err/et_name.c \
com_err/init_et.c
$(NCP_LIB): ncplib.o ncplib_err.o $(COM_ERR_CFILES)
make -C com_err
$(LIB_LINK_COMMAND) ncplib.o ncplib_err.o \
com_err/com_err.o com_err/error_message.o com_err/et_name.o \
com_err/init_et.o
ln -sf libncp.so.1.0 libncp.so.1
ncplib_err.o: ncplib_err.h ncplib_err.c
$(CC) $(CFLAGS) $(PIC_FLAG) -c ncplib_err.c
ncplib_err.h: ncplib_err.et
com_err/compile_et ncplib_err
ncplib_err.c: ncplib_err.et
com_err/compile_et ncplib_err
test: test.o ncplib.o
$(CC) -o test test.o ncplib.o
ncptest: ncptest.o ncplib.o
$(CC) -o ncptest ncptest.o ncplib.o
ncptest: ncptest.o $(NCP_LIB)
$(CC) -o ncptest ncptest.o -L. -lncp
dep:
dep: ncplib_err.h
make -C com_err dep
$(CPP) -M $(INCLUDES) *.c > .depend
clean:
rm -f *.o *~ slist test ncptest
make -C com_err clean
rm -f *.o *~ slist test ncptest ncplib_err.[ch] libncp.a
rm -f libncp.so.*
realclean: clean
mrproper: clean
make -C com_err mrproper
rm -f $(UTILS) .depend $(DISTFILE)
#

1
util/com_err.h Symbolic link
View File

@@ -0,0 +1 @@
com_err/com_err.h

49
util/com_err/ChangeLog Normal file
View File

@@ -0,0 +1,49 @@
Wed Jan 31 11:06:08 1996 <tytso@rsts-11.mit.edu>
* Release of E2fsprogs version 1.02
Mon Sep 4 21:44:47 1995 Remy Card <card@bbj>
* Makefile.in: Added support for BSD shared libraries.
Sat Aug 12 03:11:28 1995 Remy Card <card@bbj>
* Makefile.in (install): Install static libraries in $(ulibdir)
(/usr/lib on Linux) instead of $(libdir) (/lib on Linux).
Sat Aug 5 11:44:17 1995 Theodore Y. Ts'o <tytso@lurch.mit.edu>
* Makefile.in (DLL_INSTALL_DIR, ELF_INSTALL_DIR): Set the
installation directories correctly.
Thu Jun 15 23:39:51 1995 Remy Card <card@bbj>
* Makefile.in: Added support for ELF shared libraries.
Fixed typos in the compilation rules.
(distclean): Added compile_et.sh.
Sat Jun 10 19:56:13 1995 Theodore Y. Ts'o <tytso@lurch.mit.edu>
* compile_et.sh.in: Use ET_DIR instead of srcdir to determine the
location of the et directory.
Thu Jun 8 12:45:41 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
* vfprintf.c (vfprintf): Only compile this function if vfprintf
doesn't already exist and _doprnt does.
* compile_et.sh: Moved to compile_et.sh.in.
* Makefile.in: Rewritten to conform to GNU coding standards and
support separate compilation directories.
Don't preprocess compile_et.sh, as this is now done by configure.
Mon Nov 7 21:17:48 1994 Remy Card <card@bbj>
* Makefile: Added a dummy install target in case shared libraries
are not built.
Thu Sep 8 22:33:33 1994 (tytso@rsx-11)
* com_err.c (default_com_err_proc): Reversed order of \n\r to make
jik happy.

25
util/com_err/Makefile Normal file
View File

@@ -0,0 +1,25 @@
#
# Makefile for the com_err library
#
OBJECTS = com_err.o error_message.o et_name.o init_et.o
CFLAGS = -Wall -O2 $(PIC_FLAG)
all: $(OBJECTS)
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
clean:
rm -f *.o
mrproper: clean
rm -f .depend
#
# include a dependency file if one exists
#
ifeq (.depend,$(wildcard .depend))
include .depend
endif

96
util/com_err/com_err.3 Normal file
View File

@@ -0,0 +1,96 @@
.\" Copyright (c) 1988 Massachusetts Institute of Technology,
.\" Student Information Processing Board. All rights reserved.
.\"
.\" $Header: /mit/krb5/.cvsroot/src/util/et/com_err.3,v 1.1 1993/06/03 12:29:34 tytso Exp $
.\"
.TH COM_ERR 3 "22 Nov 1988" SIPB
.SH NAME
com_err \- common error display routine
.SH SYNOPSIS
.nf
#include <com_err.h>
.PP
void com_err (whoami, code, format, ...);
const char *whoami;
long code;
const char *format;
.PP
proc = set_com_err_hook (proc);
.fi
void (*
.I proc
) (const char *, long, const char *, va_list);
.nf
.PP
proc = reset_com_err_hook ();
.PP
void initialize_XXXX_error_table ();
.fi
.SH DESCRIPTION
.I Com_err
displays an error message on the standard error stream
.I stderr
(see
.IR stdio (3S))
composed of the
.I whoami
string, which should specify the program name or some subportion of
a program, followed by an error message generated from the
.I code
value (derived from
.IR compile_et (1)),
and a string produced using the
.I format
string and any following arguments, in the same style as
.IR fprintf (3).
The behavior of
.I com_err
can be modified using
.I set_com_err_hook;
this defines a procedure which is called with the arguments passed to
.I com_err,
instead of the default internal procedure which sends the formatted
text to error output. Thus the error messages from a program can all
easily be diverted to another form of diagnostic logging, such as
.IR syslog (3).
.I Reset_com_err_hook
may be used to restore the behavior of
.I com_err
to its default form. Both procedures return the previous ``hook''
value. These ``hook'' procedures must have the declaration given for
.I proc
above in the synopsis.
The
.I initialize_XXXX_error_table
routine is generated mechanically by
.IR compile_et (1)
from a source file containing names and associated strings. Each
table has a name of up to four characters, which is used in place of
the
.B XXXX
in the name of the routine. These routines should be called before
any of the corresponding error codes are used, so that the
.I com_err
library will recognize error codes from these tables when they are
used.
The
.B com_err.h
header file should be included in any source file that uses routines
from the
.I com_err
library; executable files must be linked using
.I ``-lcom_err''
in order to cause the
.I com_err
library to be included.
.\" .IR for manual entries
.\" .PP for paragraph breaks
.SH "SEE ALSO"
compile_et (1), syslog (3).
Ken Raeburn, "A Common Error Description Library for UNIX".

114
util/com_err/com_err.c Normal file
View File

@@ -0,0 +1,114 @@
/*
* Copyright 1987, 1988 by MIT Student Information Processing Board.
*
* For copyright info, see mit-sipb-copyright.h.
*/
#include <stdio.h>
#include "com_err.h"
#include "mit-sipb-copyright.h"
#include "error_table.h"
#include "internal.h"
#if !defined(__STDC__) && !defined(STDARG_PROTOTYPES)
#include <varargs.h>
#define VARARGS
#endif
static void
#ifdef __STDC__
default_com_err_proc (const char *whoami, errcode_t code, const
char *fmt, va_list args)
#else
default_com_err_proc (whoami, code, fmt, args)
const char *whoami;
errcode_t code;
const char *fmt;
va_list args;
#endif
{
if (whoami) {
fputs(whoami, stderr);
fputs(": ", stderr);
}
if (code) {
fputs(error_message(code), stderr);
fputs(" ", stderr);
}
if (fmt) {
vfprintf (stderr, fmt, args);
}
/* should do this only on a tty in raw mode */
putc('\r', stderr);
putc('\n', stderr);
fflush(stderr);
}
#ifdef __STDC__
typedef void (*errf) (const char *, errcode_t, const char *, va_list);
#else
typedef void (*errf) ();
#endif
errf com_err_hook = default_com_err_proc;
#ifdef __STDC__
void com_err_va (const char *whoami, errcode_t code, const char *fmt,
va_list args)
#else
void com_err_va (whoami, code, fmt, args)
const char *whoami;
errcode_t code;
const char *fmt;
va_list args;
#endif
{
(*com_err_hook) (whoami, code, fmt, args);
}
#ifndef VARARGS
void com_err (const char *whoami,
errcode_t code,
const char *fmt, ...)
{
#else
void com_err (va_alist)
va_dcl
{
const char *whoami, *fmt;
errcode_t code;
#endif
va_list pvar;
if (!com_err_hook)
com_err_hook = default_com_err_proc;
#ifdef VARARGS
va_start (pvar);
whoami = va_arg (pvar, const char *);
code = va_arg (pvar, errcode_t);
fmt = va_arg (pvar, const char *);
#else
va_start(pvar, fmt);
#endif
com_err_va (whoami, code, fmt, pvar);
va_end(pvar);
}
errf set_com_err_hook (new_proc)
errf new_proc;
{
errf x = com_err_hook;
if (new_proc)
com_err_hook = new_proc;
else
com_err_hook = default_com_err_proc;
return x;
}
errf reset_com_err_hook () {
errf x = com_err_hook;
com_err_hook = default_com_err_proc;
return x;
}

40
util/com_err/com_err.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* Header file for common error description library.
*
* Copyright 1988, Student Information Processing Board of the
* Massachusetts Institute of Technology.
*
* For copyright and distribution info, see the documentation supplied
* with this package.
*/
#ifndef __COM_ERR_H
typedef long errcode_t;
#ifdef __STDC__
#include <stdarg.h>
/* ANSI C -- use prototypes etc */
void com_err (const char *, long, const char *, ...);
void com_err_va (const char *whoami, errcode_t code, const char *fmt,
va_list args);
char const *error_message (long);
extern void (*com_err_hook) (const char *, long, const char *, va_list);
void (*set_com_err_hook (void (*) (const char *, long, const char *, va_list)))
(const char *, long, const char *, va_list);
void (*reset_com_err_hook (void)) (const char *, long, const char *, va_list);
int init_error_table(const char * const *msgs, int base, int count);
#else
/* no prototypes */
void com_err ();
void com_err_va ();
char *error_message ();
extern void (*com_err_hook) ();
void (*set_com_err_hook ()) ();
void (*reset_com_err_hook ()) ();
int init_error_table();
#endif
#define __COM_ERR_H
#endif /* ! defined(__COM_ERR_H) */

View File

@@ -0,0 +1,554 @@
\input texinfo @c -*-texinfo-*-
@c $Header: /mit/krb5/.cvsroot/src/util/et/com_err.texinfo,v 1.1 1993/06/03 12:29:38 tytso Exp $
@c $Source: /mit/krb5/.cvsroot/src/util/et/com_err.texinfo,v $
@c $Locker: $
@c Note that although this source file is in texinfo format (more
@c or less), it is not yet suitable for turning into an ``info''
@c file. Sorry, maybe next time.
@c
@c In order to produce hardcopy documentation from a texinfo file,
@c run ``tex com_err.texinfo'' which will load in texinfo.tex,
@c provided in this distribution. (texinfo.tex is from the Free
@c Software Foundation, and is under different copyright restrictions
@c from the rest of this package.)
@ifinfo
@barfo
@end ifinfo
@iftex
@tolerance 10000
@c Mutate section headers...
@begingroup
@catcode#=6
@gdef@secheading#1#2#3{@secheadingi {#3@enspace #1}}
@endgroup
@end iftex
@setfilename com_err
@settitle A Common Error Description Library for UNIX
@ifinfo
This file documents the use of the Common Error Description library.
Copyright (C) 1987, 1988 Student Information Processing Board of the
Massachusetts Institute of Technology.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
used in advertising or publicity pertaining to distribution of the software
without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B.
make no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
Note that the file texinfo.tex, provided with this distribution, is from
the Free Software Foundation, and is under different copyright restrictions
from the remainder of this package.
@end ifinfo
@ignore
Permission is granted to process this file through Tex and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
@setchapternewpage odd
@titlepage
@center @titlefont{A Common Error Description}
@center @titlefont{Library for UNIX}
@sp 2
@center Ken Raeburn
@center Bill Sommerfeld
@sp 1
@center MIT Student Information Processing Board
@sp 3
@center last updated 1 January 1989
@center for version 1.2
@center ***DRAFT COPY ONLY***
@vskip 2in
@center @b{Abstract}
UNIX has always had a clean and simple system call interface, with a
standard set of error codes passed between the kernel and user
programs. Unfortunately, the same cannot be said of many of the
libraries layered on top of the primitives provided by the kernel.
Typically, each one has used a different style of indicating errors to
their callers, leading to a total hodgepodge of error handling, and
considerable amounts of work for the programmer. This paper describes
a library and associated utilities which allows a more uniform way for
libraries to return errors to their callers, and for programs to
describe errors and exceptional conditions to their users.
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1987, 1988 by the Student Information Processing
Board of the Massachusetts Institute of Technology.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
used in advertising or publicity pertaining to distribution of the software
without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B.
make no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
Note that the file texinfo.tex, provided with this distribution, is from
the Free Software Foundation, and is under different copyright restrictions
from the remainder of this package.
@end titlepage
@ifinfo
@c should put a menu here someday....
@end ifinfo
@page
@section Why com_err?
In building application software packages, a programmer often has to
deal with a number of libraries, each of which can use a different
error-reporting mechanism. Sometimes one of two values is returned,
indicating simply SUCCESS or FAILURE, with no description of errors
encountered. Sometimes it is an index into a table of text strings,
where the name of the table used is dependent on the library being
used when the error is generated; since each table starts numbering at
0 or 1, additional information as to the source of the error code is
needed to determine which table to look at. Sometimes no text messages are
supplied at all, and the programmer must supply them at any point at which
he may wish to report error conditions.
Often, a global variable is assigned some value describing the error, but
the programmer has to know in each case whether to look at @code{errno},
@code{h_errno}, the return value from @code{hes_err()}, or whatever other
variables or routines are specified.
And what happens if something
in the procedure of
examining or reporting the error changes the same variable?
The package we have developed is an attempt to present a common
error-handling mechanism to manipulate the most common form of error code
in a fashion that does not have the problems listed above.
A list of up to 256 text messages is supplied to a translator we have
written, along with the three- to four-character ``name'' of the error
table. The library using this error table need only call a routine
generated from this error-table source to make the table ``known'' to the
com_err library, and any error code the library generates can be converted
to the corresponding error message. There is also a default format for
error codes accidentally returned before making the table known, which is
of the form @samp{unknown code foo 32}, where @samp{foo} would be the name
of the table.
@section Error codes
Error codes themselves are 32 bit (signed) integers, of which the high
order 24 bits are an identifier of which error table the error code is
from, and the low order 8 bits are a sequential error number within
the table. An error code may thus be easily decomposed into its component
parts. Only the lowest 32 bits of an error code are considered significant
on systems which support wider values.
Error table 0 is defined to match the UNIX system call error table
(@code{sys_errlist}); this allows @code{errno} values to be used directly
in the library (assuming that @code{errno} is of a type with the same width
as @t{long}). Other error table numbers are formed by compacting together
the first four characters of the error table name. The mapping between
characters in the name and numeric values in the error code are defined in
a system-independent fashion, so that two systems that can pass integral
values between them can reliably pass error codes without loss of meaning;
this should work even if the character sets used are not the same.
(However, if this is to be done, error table 0 should be avoided, since the
local system call error tables may differ.)
Any variable which is to contain an error code should be declared @t{long}.
The draft proposed American National Standard for C (as of May, 1988)
requires that @t{long} variables be at least 32 bits; any system which does
not support 32-bit @t{long} values cannot make use of this package (nor
much other software that assumes an ANSI-C environment base) without
significant effort.
@section Error table source file
The error table source file begins with the declaration of the table name,
as
@example
error_table @var{tablename}
@end example
Individual error codes are
specified with
@example
error_code @var{ERROR_NAME}, @var{"text message"}
@end example
where @samp{ec} can also be used as a short form of @samp{error_code}. To
indicate the end of the table, use @samp{end}. Thus, a (short) sample
error table might be:
@example
error_table dsc
error_code DSC_DUP_MTG_NAME,
"Meeting already exists"
ec DSC_BAD_PATH,
"A bad meeting pathname was given"
ec DSC_BAD_MODES,
"Invalid mode for this access control list"
end
@end example
@section The error-table compiler
The error table compiler is named @code{compile_et}. It takes one
argument, the pathname of a file (ending in @samp{.et}, e.g.,
@samp{dsc_err.et}) containing an error table source file. It parses the
error table, and generates two output files -- a C header file
(@samp{discuss_err.h}) which contains definitions of the numerical values
of the error codes defined in the error table, and a C source file which
should be compiled and linked with the executable. The header file must be
included in the source of a module which wishes to reference the error
codes defined; the object module generated from the C code may be linked in
to a program which wishes to use the printed forms of the error codes.
This translator accepts a @kbd{-language @var{lang}} argument, which
determines for which language (or language variant) the output should be
written. At the moment, @var{lang} is currently limited to @kbd{ANSI-C}
and @kbd{K&R-C}, and some abbreviated forms of each. Eventually, this will
be extended to include some support for C++. The default is currently
@kbd{K&R-C}, though the generated sources will have ANSI-C code
conditionalized on the symbol @t{__STDC__}.
@section Run-time support routines
Any source file which uses the routines supplied with or produced by the
com_err package should include the header file @file{<com_err.h>}. It
contains declarations and definitions which may be needed on some systems.
(Some functions cannot be referenced properly without the return type
declarations in this file. Some functions may work properly on most
architectures even without the header file, but relying on this is not
recommended.)
The run-time support routines and variables provided via this package
include the following:
@example
void initialize_@var{xxxx}_error_table (void);
@end example
One of these routines is built by the error compiler for each error table.
It makes the @var{xxxx} error table ``known'' to the error reporting
system. By convention, this routine should be called in the initialization
routine of the @var{xxxx} library. If the library has no initialization
routine, some combination of routines which form the core of the library
should ensure that this routine is called. It is not advised to leave it
the caller to make this call.
There is no harm in calling this routine more than once.
@example
#define ERROR_TABLE_BASE_@var{xxxx} @var{nnnnn}L
@end example
This symbol contains the value of the first error code entry in the
specified table.
This rarely needs be used by the
programmer.
@example
const char *error_message (long code);
@end example
This routine returns the character string error message associated
with @code{code}; if this is associated with an unknown error table, or
if the code is associated with a known error table but the code is not
in the table, a string of the form @samp{Unknown code @var{xxxx nn}} is
returned, where @var{xxxx} is the error table name produced by
reversing the compaction performed on the error table number implied
by that error code, and @var{nn} is the offset from that base value.
Although this routine is available for use when needed, its use should be
left to circumstances which render @code{com_err} (below) unusable.
@example
void com_err (const char *whoami, /* module reporting error */
long code, /* error code */
const char *format, /* format for additional detail */
...); /* (extra parameters) */
@end example
This routine provides an alternate way to print error messages to
standard error; it allows the error message to be passed in as a
parameter, rather than in an external variable. @emph{Provide grammatical
context for ``message.''}
If @var{format} is @code{(char *)NULL}, the formatted message will not be
printed. @var{format} may not be omitted.
@example
#include <stdarg.h>
void com_err_va (const char *whoami,
long code,
const char *format,
va_list args);
@end example
This routine provides an interface, equivalent to @code{com_err} above,
which may be used by higher-level variadic functions (functions which
accept variable numbers of arguments).
@example
#include <stdarg.h>
void (*set_com_err_hook (void (*proc) ())) ();
void (*@var{proc}) (const char *whoami, long code, va_list args);
void reset_com_err_hook ();
@end example
These two routines allow a routine to be dynamically substituted for
@samp{com_err}. After @samp{set_com_err_hook} has been called,
calls to @samp{com_err} will turn into calls to the new hook routine.
@samp{reset_com_err_hook} turns off this hook. This may intended to
be used in daemons (to use a routine which calls @var{syslog(3)}), or
in a window system application (which could pop up a dialogue box).
If a program is to be used in an environment in which simply printing
messages to the @code{stderr} stream would be inappropriate (such as in a
daemon program which runs without a terminal attached),
@code{set_com_err_hook} may be used to redirect output from @code{com_err}.
The following is an example of an error handler which uses @var{syslog(3)}
as supplied in BSD 4.3:
@example
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
/* extern openlog (const char * name, int logopt, int facility); */
/* extern syslog (int priority, char * message, ...); */
void hook (const char * whoami, long code,
const char * format, va_list args)
@{
char buffer[BUFSIZ];
static int initialized = 0;
if (!initialized) @{
openlog (whoami,
LOG_NOWAIT|LOG_CONS|LOG_PID|LOG_NDELAY,
LOG_DAEMON);
initialized = 1;
@}
vsprintf (buffer, format, args);
syslog (LOG_ERR, "%s %s", error_message (code), buffer);
@}
@end example
After making the call
@code{set_com_err_hook (hook);},
any calls to @code{com_err} will result in messages being sent to the
@var{syslogd} daemon for logging.
The name of the program, @samp{whoami}, is supplied to the
@samp{openlog()} call, and the message is formatted into a buffer and
passed to @code{syslog}.
Note that since the extra arguments to @code{com_err} are passed by
reference via the @code{va_list} value @code{args}, the hook routine may
place any form of interpretation on them, including ignoring them. For
consistency, @code{printf}-style interpretation is suggested, via
@code{vsprintf} (or @code{_doprnt} on BSD systems without full support for
the ANSI C library).
@section Coding Conventions
The following conventions are just some general stylistic conventions
to follow when writing robust libraries and programs. Conventions
similar to this are generally followed inside the UNIX kernel and most
routines in the Multics operating system. In general, a routine
either succeeds (returning a zero error code, and doing some side
effects in the process), or it fails, doing minimal side effects; in
any event, any invariant which the library assumes must be maintained.
In general, it is not in the domain of non user-interface library
routines to write error messages to the user's terminal, or halt the
process. Such forms of ``error handling'' should be reserved for
failures of internal invariants and consistancy checks only, as it
provides the user of the library no way to clean up for himself in the
event of total failure.
Library routines which can fail should be set up to return an error
code. This should usually be done as the return value of the
function; if this is not acceptable, the routine should return a
``null'' value, and put the error code into a parameter passed by
reference.
Routines which use the first style of interface can be used from
user-interface levels of a program as follows:
@example
@{
if ((code = initialize_world(getuid(), random())) != 0) @{
com_err("demo", code,
"when trying to initialize world");
exit(1);
@}
if ((database = open_database("my_secrets", &code))==NULL) @{
com_err("demo", code,
"while opening my_secrets");
exit(1);
@}
@}
@end example
A caller which fails to check the return status is in error. It is
possible to look for code which ignores error returns by using lint;
look for error messages of the form ``foobar returns value which is
sometimes ignored'' or ``foobar returns value which is always
ignored.''
Since libraries may be built out of other libraries, it is often necessary
for the success of one routine to depend on another. When a lower level
routine returns an error code, the middle level routine has a few possible
options. It can simply return the error code to its caller after doing
some form of cleanup, it can substitute one of its own, or it can take
corrective action of its own and continue normally. For instance, a
library routine which makes a ``connect'' system call to make a network
connection may reflect the system error code @code{ECONNREFUSED}
(Connection refused) to its caller, or it may return a ``server not
available, try again later,'' or it may try a different server.
Cleanup which is typically necessary may include, but not be limited
to, freeing allocated memory which will not be needed any more,
unlocking concurrancy locks, dropping reference counts, closing file
descriptors, or otherwise undoing anything which the procedure did up
to this point. When there are a lot of things which can go wrong, it
is generally good to write one block of error-handling code which is
branched to, using a goto, in the event of failure. A common source
of errors in UNIX programs is failing to close file descriptors on
error returns; this leaves a number of ``zombied'' file descriptors
open, which eventually causes the process to run out of file
descriptors and fall over.
@example
@{
FILE *f1=NULL, *f2=NULL, *f3=NULL;
int status = 0;
if ( (f1 = fopen(FILE1, "r")) == NULL) @{
status = errno;
goto error;
@}
/*
* Crunch for a while
*/
if ( (f2 = fopen(FILE2, "w")) == NULL) @{
status = errno;
goto error;
@}
if ( (f3 = fopen(FILE3, "a+")) == NULL) @{
status = errno;
goto error;
@}
/*
* Do more processing.
*/
fclose(f1);
fclose(f2);
fclose(f3);
return 0;
error:
if (f1) fclose(f1);
if (f2) fclose(f2);
if (f3) fclose(f3);
return status;
@}
@end example
@section Building and Installation
The distribution of this package will probably be done as a compressed
``tar''-format file available via anonymous FTP from SIPB.MIT.EDU.
Retrieve @samp{pub/com_err.tar.Z} and extract the contents. A subdirectory
@t{profiled} should be created to hold objects compiled for profiling.
Running ``make all'' should then be sufficient to build the library and
error-table compiler. The files @samp{libcom_err.a},
@samp{libcom_err_p.a}, @samp{com_err.h}, and @samp{compile_et} should be
installed for use; @samp{com_err.3} and @samp{compile_et.1} can also be
installed as manual pages.
Potential problems:
@itemize @bullet
@item Use of @code{strcasecmp}, a routine provided in BSD for
case-insensitive string comparisons. If an equivalent routine is
available, you can modify @code{CFLAGS} in the makefile to define
@code{strcasecmp} to the name of that routine.
@item Compilers that defined @code{__STDC__} without providing the header
file @code{<stdarg.h>}. One such example is Metaware's High ``C''
compiler, as provided at Project Athena on the IBM RT/PC workstation; if
@code{__HIGHC__} is defined, it is assumed that @code{<stdarg.h>} is not
available, and therefore @code{<varargs.h>} must be used. If the symbol
@code{VARARGS} is defined (e.g., in the makefile), @code{<varargs.h>} will
be used.
@item If your linker rejects symbols that are simultaneously defined in two
library files, edit @samp{Makefile} to remove @samp{perror.c} from the
library. This file contains a version of @var{perror(3)} which calls
@code{com_err} instead of calling @code{write} directly.
@end itemize
As I do not have access to non-BSD systems, there are probably
bugs present that may interfere with building or using this package on
other systems. If they are reported to me, they can probably be fixed for
the next version.
@section Bug Reports
Please send any comments or bug reports to the principal author: Ken
Raeburn, @t{Raeburn@@Athena.MIT.EDU}.
@section Acknowledgements
I would like to thank: Bill Sommerfeld, for his help with some of this
documentation, and catching some of the bugs the first time around;
Honeywell Information Systems, for not killing off the @emph{Multics}
operating system before I had an opportunity to use it; Honeywell's
customers, who persuaded them not to do so, for a while; Ted Anderson of
CMU, for catching some problems before version 1.2 left the nest; Stan
Zanarotti and several others of MIT's Student Information Processing Board,
for getting us started with ``discuss,'' for which this package was
originally written; and everyone I've talked into --- I mean, asked to read
this document and the ``man'' pages.
@bye

11
util/com_err/compile_et Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
#
#
AWK=/usr/bin/awk
DIR=com_err/
ROOT=`echo $1 | sed -e s/.et$//`
BASE=`basename $ROOT`
$AWK -f ${DIR}/et_h.awk outfile=${BASE}.h $ROOT.et
$AWK -f ${DIR}/et_c.awk outfile=${BASE}.c $ROOT.et

79
util/com_err/compile_et.1 Normal file
View File

@@ -0,0 +1,79 @@
.\" Copyright (c) 1988 Massachusetts Institute of Technology,
.\" Student Information Processing Board. All rights reserved.
.\"
.\" $Header: /mit/krb5/.cvsroot/src/util/et/compile_et.1,v 1.1 1993/06/03 12:29:46 tytso Exp $
.\"
.TH COMPILE_ET 1 "22 Nov 1988" SIPB
.SH NAME
compile_et \- error table compiler
.SH SYNOPSIS
.B compile_et
file
.SH DESCRIPTION
.B Compile_et
converts a table listing error-code names and associated messages into
a C source file suitable for use with the
.IR com_err (3)
library.
The source file name must end with a suffix of ``.et''; the file
consists of a declaration supplying the name (up to four characters
long) of the error-code table:
.B error_table
.I name
followed by up to 256 entries of the form:
.B error_code
.I name,
"
.I string
"
and a final
.B end
to indicate the end of the table.
The name of the table is used to construct the name of a subroutine
.I initialize_XXXX_error_table
which must be called in order for the
.I com_err
library to recognize the error table.
The various error codes defined are assigned sequentially increasing
numbers (starting with a large number computed as a hash function of
the name of the table); thus for compatibility it is suggested that
new codes be added only to the end of an existing table, and that no
codes be removed from tables.
The names defined in the table are placed into a C header file with
preprocessor directives defining them as integer constants of up to
32 bits in magnitude.
A C source file is also generated which should be compiled and linked
with the object files which reference these error codes; it contains
the text of the messages and the initialization subroutine. Both C
files have names derived from that of the original source file, with
the ``.et'' suffix replaced by ``.c'' and ``.h''.
A ``#'' in the source file is treated as a comment character, and all
remaining text to the end of the source line will be ignored.
.SH BUGS
Since
.B compile_et
uses a very simple parser based on
.IR yacc (1),
its error recovery leaves much to be desired.
.\" .IR for manual entries
.\" .PP for paragraph breaks
.SH "SEE ALSO"
com_err (3).
Ken Raeburn, "A Common Error Description Library for UNIX".

View File

@@ -0,0 +1,82 @@
/*
* $Header: /mit/krb5/.cvsroot/src/util/et/error_message.c,v 5.0 1993/04/13 19:56:17 tytso Exp $
* $Source: /mit/krb5/.cvsroot/src/util/et/error_message.c,v $
* $Locker: $
*
* Copyright 1987 by the Student Information Processing Board
* of the Massachusetts Institute of Technology
*
* For copyright info, see "mit-sipb-copyright.h".
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "com_err.h"
#include "error_table.h"
#include "mit-sipb-copyright.h"
#include "internal.h"
static char buffer[25];
struct et_list * _et_list = (struct et_list *) NULL;
#ifdef __STDC__
const char * error_message (errcode_t code)
#else
const char * error_message (code)
errcode_t code;
#endif
{
int offset;
struct et_list *et;
int table_num;
int started = 0;
char *cp;
offset = code & ((1<<ERRCODE_RANGE)-1);
table_num = code - offset;
if (!table_num) {
#ifdef HAS_SYS_ERRLIST
if (offset < sys_nerr)
return(sys_errlist[offset]);
else
goto oops;
#else
cp = strerror(offset);
if (cp)
return(cp);
else
goto oops;
#endif
}
for (et = _et_list; et; et = et->next) {
if (et->table->base == table_num) {
/* This is the right table */
if (et->table->n_msgs <= offset)
goto oops;
return(et->table->msgs[offset]);
}
}
oops:
strcpy (buffer, "Unknown code ");
if (table_num) {
strcat (buffer, error_table_name (table_num));
strcat (buffer, " ");
}
for (cp = buffer; *cp; cp++)
;
if (offset >= 100) {
*cp++ = '0' + offset / 100;
offset %= 100;
started++;
}
if (started || offset >= 10) {
*cp++ = '0' + offset / 10;
offset %= 10;
}
*cp++ = '0' + offset;
*cp = '\0';
return(buffer);
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 1988 by the Student Information Processing Board of the
* Massachusetts Institute of Technology.
*
* For copyright info, see mit-sipb-copyright.h.
*/
#ifndef _ET_H
/* Are we using ANSI C? */
#ifndef __STDC__
#define const
#endif
struct error_table {
char const * const * msgs;
long base;
int n_msgs;
};
struct et_list {
struct et_list *next;
const struct error_table *table;
};
extern struct et_list * _et_list;
#define ERRCODE_RANGE 8 /* # of bits to shift table number */
#define BITS_PER_CHAR 6 /* # bits to shift per character in name */
#ifdef __STDC__
extern const char *error_table_name(int num);
#else
extern const char *error_table_name();
#endif
#define _ET_H
#endif

185
util/com_err/et_c.awk Normal file
View File

@@ -0,0 +1,185 @@
BEGIN {
char_shift=64
## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
c2n["A"]=1
c2n["B"]=2
c2n["C"]=3
c2n["D"]=4
c2n["E"]=5
c2n["F"]=6
c2n["G"]=7
c2n["H"]=8
c2n["I"]=9
c2n["J"]=10
c2n["K"]=11
c2n["L"]=12
c2n["M"]=13
c2n["N"]=14
c2n["O"]=15
c2n["P"]=16
c2n["Q"]=17
c2n["R"]=18
c2n["S"]=19
c2n["T"]=20
c2n["U"]=21
c2n["V"]=22
c2n["W"]=23
c2n["X"]=24
c2n["Y"]=25
c2n["Z"]=26
c2n["a"]=27
c2n["b"]=28
c2n["c"]=29
c2n["d"]=30
c2n["e"]=31
c2n["f"]=32
c2n["g"]=33
c2n["h"]=34
c2n["i"]=35
c2n["j"]=36
c2n["k"]=37
c2n["l"]=38
c2n["m"]=39
c2n["n"]=40
c2n["o"]=41
c2n["p"]=42
c2n["q"]=43
c2n["r"]=44
c2n["s"]=45
c2n["t"]=46
c2n["u"]=47
c2n["v"]=48
c2n["w"]=49
c2n["x"]=50
c2n["y"]=51
c2n["z"]=52
c2n["0"]=53
c2n["1"]=54
c2n["2"]=55
c2n["3"]=56
c2n["4"]=57
c2n["5"]=58
c2n["6"]=59
c2n["7"]=60
c2n["8"]=61
c2n["9"]=62
c2n["_"]=63
}
/^#/ { next }
/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ {
table_number = 0
table_name = $2
mod_base = 1000000
for(i=1; i<=length(table_name); i++) {
table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)]
}
# We start playing *_high, *low games here because the some
# awk programs do not have the necessary precision (sigh)
tab_base_low = table_number % mod_base
tab_base_high = int(table_number / mod_base)
tab_base_sign = 1;
# figure out: table_number_base=table_number*256
tab_base_low = tab_base_low * 256
tab_base_high = (tab_base_high * 256) + \
int(tab_base_low / mod_base)
tab_base_low = tab_base_low % mod_base
if (table_number > 128*256*256) {
# figure out: table_number_base -= 256*256*256*256
# sub_high, sub_low is 256*256*256*256
sub_low = 256*256*256 % mod_base
sub_high = int(256*256*256 / mod_base)
sub_low = sub_low * 256
sub_high = (sub_high * 256) + int(sub_low / mod_base)
sub_low = sub_low % mod_base
tab_base_low = sub_low - tab_base_low;
tab_base_high = sub_high - tab_base_high;
tab_base_sign = -1;
if (tab_base_low < 0) {
tab_base_low = tab_base_low + mod_base
tab_base_high--
}
}
print "/*" > outfile
print " * " outfile ":" > outfile
print " * This file is automatically generated; please do not edit it." > outfile
print " */" > outfile
print "#ifdef __STDC__" > outfile
print "#define NOARGS void" > outfile
print "#else" > outfile
print "#define NOARGS" > outfile
print "#define const" > outfile
print "#endif" > outfile
print "" > outfile
print "static const char * const text[] = {" > outfile
table_item_count = 0
}
/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*$/ {
skipone=1
next
}
/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*"[ \t]*$/ {
text=""
for (i=3; i<=NF; i++) {
text = text FS $i
}
text=substr(text,2,length(text)-1);
printf "\t%s,\n", text > outfile
table_item_count++
}
{
if (skipone) {
printf "\t%s,\n", $0 > outfile
table_item_count++
}
skipone=0
}
END {
print " 0" > outfile
print "};" > outfile
print "" > outfile
print "struct error_table {" > outfile
print " char const * const * msgs;" > outfile
print " long base;" > outfile
print " int n_msgs;" > outfile
print "};" > outfile
print "struct et_list {" > outfile
print " struct et_list *next;" > outfile
print " const struct error_table * table;" > outfile
print "};" > outfile
print "extern struct et_list *_et_list;" > outfile
print "" > outfile
if (tab_base_high == 0) {
print "static const struct error_table et = { text, " \
sprintf("%dL, %d };", tab_base_sign*tab_base_low, \
table_item_count) > outfile
} else {
print "static const struct error_table et = { text, " \
sprintf("%d%06dL, %d };", tab_base_sign*tab_base_high, \
tab_base_low, table_item_count) > outfile
}
print "" > outfile
print "static struct et_list link = { 0, 0 };" > outfile
print "" > outfile
print "void initialize_" table_name "_error_table (NOARGS);" > outfile
print "" > outfile
print "void initialize_" table_name "_error_table (NOARGS) {" > outfile
print " if (!link.table) {" > outfile
print " link.next = _et_list;" > outfile
print " link.table = &et;" > outfile
print " _et_list = &link;" > outfile
print " }" > outfile
print "}" > outfile
}

157
util/com_err/et_h.awk Normal file
View File

@@ -0,0 +1,157 @@
BEGIN {
char_shift=64
## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
c2n["A"]=1
c2n["B"]=2
c2n["C"]=3
c2n["D"]=4
c2n["E"]=5
c2n["F"]=6
c2n["G"]=7
c2n["H"]=8
c2n["I"]=9
c2n["J"]=10
c2n["K"]=11
c2n["L"]=12
c2n["M"]=13
c2n["N"]=14
c2n["O"]=15
c2n["P"]=16
c2n["Q"]=17
c2n["R"]=18
c2n["S"]=19
c2n["T"]=20
c2n["U"]=21
c2n["V"]=22
c2n["W"]=23
c2n["X"]=24
c2n["Y"]=25
c2n["Z"]=26
c2n["a"]=27
c2n["b"]=28
c2n["c"]=29
c2n["d"]=30
c2n["e"]=31
c2n["f"]=32
c2n["g"]=33
c2n["h"]=34
c2n["i"]=35
c2n["j"]=36
c2n["k"]=37
c2n["l"]=38
c2n["m"]=39
c2n["n"]=40
c2n["o"]=41
c2n["p"]=42
c2n["q"]=43
c2n["r"]=44
c2n["s"]=45
c2n["t"]=46
c2n["u"]=47
c2n["v"]=48
c2n["w"]=49
c2n["x"]=50
c2n["y"]=51
c2n["z"]=52
c2n["0"]=53
c2n["1"]=54
c2n["2"]=55
c2n["3"]=56
c2n["4"]=57
c2n["5"]=58
c2n["6"]=59
c2n["7"]=60
c2n["8"]=61
c2n["9"]=62
c2n["_"]=63
}
/^#/ { next }
/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ {
table_number = 0
table_name = $2
mod_base = 1000000
for(i=1; i<=length(table_name); i++) {
table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)]
}
# We start playing *_high, *low games here because the some
# awk programs do not have the necessary precision (sigh)
tab_base_low = table_number % mod_base
tab_base_high = int(table_number / mod_base)
tab_base_sign = 1;
# figure out: table_number_base=table_number*256
tab_base_low = tab_base_low * 256
tab_base_high = (tab_base_high * 256) + \
int(tab_base_low / mod_base)
tab_base_low = tab_base_low % mod_base
if (table_number > 128*256*256) {
# figure out: table_number_base -= 256*256*256*256
# sub_high, sub_low is 256*256*256*256
sub_low = 256*256*256 % mod_base
sub_high = int(256*256*256 / mod_base)
sub_low = sub_low * 256
sub_high = (sub_high * 256) + int(sub_low / mod_base)
sub_low = sub_low % mod_base
tab_base_low = sub_low - tab_base_low;
tab_base_high = sub_high - tab_base_high;
tab_base_sign = -1;
if (tab_base_low < 0) {
tab_base_low = tab_base_low + mod_base
tab_base_high--
}
}
curr_low = tab_base_low
curr_high = tab_base_high
curr_sign = tab_base_sign
print "/*" > outfile
print " * " outfile ":" > outfile
print " * This file is automatically generated; please do not edit it." > outfile
print " */" > outfile
print "#ifdef __STDC__" > outfile
print "#define NOARGS void" > outfile
print "#else" > outfile
print "#define NOARGS" > outfile
print "#define const" > outfile
print "#endif" > outfile
print "" > outfile
}
/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,/ {
tag=substr($2,1,length($2)-1)
if (curr_high == 0) {
printf "#define %-40s (%dL)\n", tag, \
curr_sign*curr_low > outfile
} else {
printf "#define %-40s (%d%06dL)\n", tag, curr_high*curr_sign, \
curr_low > outfile
}
curr_low += curr_sign;
if (curr_low >= mod_base) {
curr_low -= mod_base;
curr_high++
}
if (curr_low < 0) {
cur_low += mod_base
cur_high--
}
}
END {
print "extern void initialize_" table_name "_error_table (NOARGS);" > outfile
if (tab_base_high == 0) {
print "#define ERROR_TABLE_BASE_" table_name " (" \
sprintf("%d", tab_base_sign*tab_base_low) \
"L)" > outfile
} else {
print "#define ERROR_TABLE_BASE_" table_name " (" \
sprintf("%d%06d", tab_base_sign*tab_base_high, \
tab_base_low) "L)" > outfile
}
print "" > outfile
print "/* for compatibility with older versions... */" > outfile
print "#define init_" table_name "_err_tbl initialize_" table_name "_error_table" > outfile
print "#define " table_name "_err_base ERROR_TABLE_BASE_" table_name > outfile
}

36
util/com_err/et_name.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* Copyright 1987 by MIT Student Information Processing Board
*
* For copyright info, see mit-sipb-copyright.h.
*/
#include "error_table.h"
#include "mit-sipb-copyright.h"
#include "internal.h"
static const char char_set[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
static char buf[6];
const char * error_table_name(num)
int num;
{
int ch;
int i;
char *p;
/* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */
p = buf;
num >>= ERRCODE_RANGE;
/* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */
num &= 077777777;
/* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */
for (i = 4; i >= 0; i--) {
ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1);
if (ch != 0)
*p++ = char_set[ch-1];
}
*p = '\0';
return(buf);
}

58
util/com_err/init_et.c Normal file
View File

@@ -0,0 +1,58 @@
/*
* $Header: /mit/krb5/.cvsroot/src/util/et/init_et.c,v 5.0 1993/04/13 19:56:25 tytso Exp $
* $Source: /mit/krb5/.cvsroot/src/util/et/init_et.c,v $
* $Locker: $
*
* Copyright 1986, 1987, 1988 by MIT Information Systems and
* the MIT Student Information Processing Board.
*
* For copyright info, see mit-sipb-copyright.h.
*/
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "com_err.h"
#include "error_table.h"
#include "mit-sipb-copyright.h"
#ifndef __STDC__
#define const
#endif
struct foobar {
struct et_list etl;
struct error_table et;
};
extern struct et_list * _et_list;
#ifdef __STDC__
int init_error_table(const char * const *msgs, int base, int count)
#else
int init_error_table(msgs, base, count)
const char * const * msgs;
int base;
int count;
#endif
{
struct foobar * new_et;
if (!base || !count || !msgs)
return 0;
new_et = (struct foobar *) malloc(sizeof(struct foobar));
if (!new_et)
return ENOMEM; /* oops */
new_et->etl.table = &new_et->et;
new_et->et.msgs = msgs;
new_et->et.base = base;
new_et->et.n_msgs= count;
new_et->etl.next = _et_list;
_et_list = &new_et->etl;
return 0;
}

22
util/com_err/internal.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* internal include file for com_err package
*/
#include "mit-sipb-copyright.h"
#ifndef __STDC__
#undef const
#define const
#endif
#include <errno.h>
#ifdef NEED_SYS_ERRLIST
extern char const * const sys_errlist[];
extern const int sys_nerr;
#endif
/* AIX and Ultrix have standard conforming header files. */
#if !defined(ultrix) && !defined(_AIX)
#ifdef __STDC__
void perror (const char *);
#endif
#endif

View File

@@ -0,0 +1,19 @@
/*
Copyright 1987, 1988 by the Student Information Processing Board
of the Massachusetts Institute of Technology
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is
hereby granted, provided that the above copyright notice
appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation,
and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
used in advertising or publicity pertaining to distribution
of the software without specific, written prior permission.
M.I.T. and the M.I.T. S.I.P.B. make no representations about
the suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
*/

View File

@@ -1,78 +0,0 @@
/*
* fsinfo.c
*
* Print the info strings of a server, maybe sometime more.
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include <stdio.h>
#include <unistd.h>
#include "ncplib.h"
int
main(int argc, char **argv)
{
struct ncp_conn conn;
int opt;
if (ncp_initialize(&conn, &argc, argv, 0) != 0)
{
perror("Could not open connection");
return 1;
}
while ((opt = getopt(argc, argv, "dt")) != EOF)
{
switch(opt)
{
case 'd':
{
char strings[512];
char *s;
if (ncp_get_file_server_description_strings(&conn,
strings)
!= 0)
{
perror("could not get strings");
ncp_close(&conn);
return 1;
}
s = strings;
while (s < strings+512)
{
if (strlen(s) == 0)
{
break;
}
puts(s);
s += strlen(s)+1;
}
break;
}
case 't':
{
time_t t;
if (ncp_get_file_server_time(&conn, &t) != 0)
{
perror("could not get server time");
ncp_close(&conn);
return 1;
}
fputs(ctime(&t), stdout);
break;
}
default:
printf("unknown option: %c\n", opt);
break;
}
}
ncp_close(&conn);
return 0;
}

32
util/ipx_sap_types Normal file
View File

@@ -0,0 +1,32 @@
0001 User
0002 User Group
0003 Print Queue
0004 File Server
0005 Job Server
0006 Gateway
0007 Print Server
0008 Archive Server
0009 Archive Server
000A Job Queue
000B Administration
0021 NAS SNA Gateway
0024 Remote Bridge
0026 Bridge Server
0027 TCP/IP Gateway
002D Time Synchronization VAP
002E Archive Server Dynamic SAP
0047 Advertising Print Server
004B Btrieve VAP 5.0
0050 Btrieve VAP
0053 Print Queue User
007A TES NetWare for VMS
0098 NetWare Access Server
009A Named Pipe Server
009E Portable NetWare Unix
0107 NetWare 386
0111 Test Server
0133 NetWare Name Service
0166 NetWare Management
026A NetWare Management
026B Time Server (NetWare 4.0)
0278 NetWare Directory Server (NetWare 4.0)

849
util/ncopy.c Normal file
View File

@@ -0,0 +1,849 @@
/****************************************************************************
* ncopy.c
*
* Copy file on a Netware server without Network Traffic
*
* Copyright (C) 1996 by Brian Reid and Tom Henderson.
*
* Send bug reports for ncopy to "breid@tim.com"
*
* Still to do: support recursive copy with two arguments
* Both must be directories. (similar to rcp -r)
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <ctype.h>
#include <mntent.h>
#include <fcntl.h>
#include <signal.h>
#include "ncplib.h"
struct NCPMountRec
{
char *mountDir;
char *server;
struct ncp_conn *conn;
};
/****************************************************************************
* Globals:
*
*/
const char *VersionStr = "0.1";
char * ProgramName;
struct NCPMountRec *NcpMountTable = NULL;
int ncpCount = 0;
/* (initialized) command options */
int optVersion=0; /* -V TRUE if just want version */
int optVerbose=0; /* -v TRUE if want verbose output */
int optNice=0; /* -n TRUE if we are cooperative (nice) */
int optNiceFactorSel=0; /* -s TRUE if we selected a nice factor */
int optNiceFactor=10; /* -s arg, number of 100K blocks to copy
before sleeping for a second */
__u32 CopyBlockSize = 100000; /* Size of the default block copy size */
unsigned int NiceSleepTime=1; /* Number of seconds to sleep in Nice Mode */
int BlocksCopied=0; /* Number of blocks copied */
int MaxNcopyRetries=25; /* Maximum number of times to retry a failed
copy before giving up */
/* Globals needed for signal handlers */
int OutputOpen=0; /* True if the ncp output file is open */
struct ncp_conn *CurrentConn = NULL; /* Connection of output file */
struct ncp_file_info *CurrentFile = NULL; /* File info of output file */
/* Signal control structures */
static struct sigaction sHangupSig;
static struct sigaction sInterruptSig;
static struct sigaction sQuitSig;
static struct sigaction sTermSig;
/****************************************************************************
*
*/
static void usage()
{
fprintf(stderr,"usage: %s [-V]\n", ProgramName);
fprintf(stderr," %s [-vn] [-s amt] sourcefile destinationfile|directory\n", ProgramName);
fprintf(stderr," %s [-vn] [-s amt] sourcefile [...] directory\n", ProgramName);
}
/****************************************************************************
* Return pointer to last component of the path.
* Returned string may have one or more "/" left on the end.
* ("/" returns pointer to "/", null returns pointer to null)
* Return pointer to original string if no "/" in string. (except at end)
*/
static const char *myBaseName(const char *path)
{
const char *p;
for(p = &path[strlen(path)]; p != path; p--) { /* skip ENDING "/" chars */
if(*p && *p != '/') break;
}
if(p==path) return p;
for( ; p != path || *p == '/'; p--) {
if(*p == '/') return ++p;
}
return p;
}
/****************************************************************************
*
*/
static const char *notDir(const char *path)
{
struct stat buf;
static const char *notDirectory="not a directory";
if(stat(path, &buf)) return strerror(errno); /* no permission? not exist? */
if(!S_ISDIR(buf.st_mode)) return notDirectory; /* not a directory */
return (char *) 0; /* OK */
}
/****************************************************************************
*
*/
static int handleOptions(const int argc, char * const argv[])
{
int opt;
while ((opt = getopt(argc, argv, "vVns:")) != EOF)
{
switch (opt) {
case 'V': /* Version */
optVersion=1;
break;
case 'v': /* Verbose output */
optVerbose=1;
break;
case 'n': /* Nice, cooperative copy */
optNice=1;
break;
case 's': /* Nice Factor */
optNiceFactorSel=1;
optNiceFactor=atoi(optarg);
if (optNiceFactor < 1) {
fprintf(stderr,"%s: -s option requires positive numeric argument > 0\n",
ProgramName);
return 1;
}
break;
default: /* invalid options or options without required arguments */
return 1;
}
continue;
}
return 0;
}
/****************************************************************************
* TODO: if recursive flag last MUST be a directory, even if only 2 args.
*/
static int validateFileArgs(const int argc, char * const argv[])
{
const char *p;
if (argc == 0) {
fprintf(stderr,"%s: No arguments specified.\n", ProgramName);
return 1;
}
if(argc == 1) {
fprintf(stderr,"%s: No destination specified.\n", ProgramName);
return 1;
}
if((argc > 2) && (p=notDir(argv[argc-1]))) { /* last arg MUST be dir */
fprintf(stderr,"%s: %s: %s\n", ProgramName, argv[argc-1], p);
return 1;
}
return 0;
}
/****************************************************************************
* Duplicate a string.
*/
char *duplicateStr(const char *InStr)
{
char *dup;
if (!InStr) return NULL;
dup = (char*)malloc(strlen(InStr)+1);
if (dup)
strcpy(dup,InStr);
return dup;
}
/****************************************************************************
* load a table of ncpfs mount points.
*/
int loadMountTable()
{
FILE *mountedFile;
struct mntent *mountEntry = NULL;
ncpCount = 0;
if ( (mountedFile = fopen(MOUNTED,"r")) == NULL) {
fprintf(stderr,"ncopy: cannot open %s, %s\n",MOUNTED,strerror(errno));
return 1;
}
while ( (mountEntry = getmntent(mountedFile)) != NULL) {
if (!strcmp(mountEntry->mnt_type,"ncpfs"))
ncpCount++;
}
if (ncpCount) {
NcpMountTable = (struct NCPMountRec*)
malloc(ncpCount * sizeof(struct NCPMountRec));
if (!NcpMountTable) {
fprintf(stderr,"Out of memory\n");
fclose(mountedFile);
return 1;
}
fseek(mountedFile,0,SEEK_SET);
ncpCount = 0;
while ( (mountEntry = getmntent(mountedFile)) != NULL) {
if (!strcmp(mountEntry->mnt_type,"ncpfs")) {
NcpMountTable[ncpCount].mountDir = duplicateStr(mountEntry->mnt_dir);
NcpMountTable[ncpCount].server =
duplicateStr(mountEntry->mnt_fsname);
NcpMountTable[ncpCount].conn = NULL;
ncpCount++;
}
}
}
fclose(mountedFile);
return 0;
}
/****************************************************************************
* Releases the table of ncpfs mount points.
*/
void releaseMountTable()
{
int loop;
if (!ncpCount) return;
for (loop = ncpCount; loop; loop--,ncpCount--) {
if (NcpMountTable[loop-1].conn) {
ncp_close(NcpMountTable[loop-1].conn);
NcpMountTable[loop-1].conn = NULL;
}
free(NcpMountTable[loop-1].server);
free(NcpMountTable[loop-1].mountDir);
}
free(NcpMountTable);
}
/****************************************************************************
* Finds the index into the mount point table that enables ncp copy for
* the file.
* Returns -1 if the files do not reference the same server.
*/
int ncpIndex(const char *InputFile, const char *OutputFile)
{
int loop;
char *mountDir;
if (!ncpCount) return -1;
for (loop = 0; loop < ncpCount; loop++) {
mountDir = NcpMountTable[loop].mountDir;
if (!strncmp(mountDir,InputFile,strlen(mountDir)) &&
!strncmp(mountDir,OutputFile,strlen(mountDir))) return loop;
}
return -1;
}
/****************************************************************************
* Does a regular buffered file copy.
* This is used if we cannot use the Netware file copy.
*/
int normalFileCopy(const char *InputFile, const char *OutputFile,
char *Buffer,int BufferSize,
const char *paramInputFile,
const char *paramOutputFile)
{
int fdIn, fdOut;
long fileSize,totalSize;
struct stat statBuf;
fdIn = open(InputFile,O_RDONLY);
if (fdIn == -1) {
fprintf(stderr,"%s: Cannot open %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
return 1;
}
if (fstat(fdIn,&statBuf)) {
fprintf(stderr,"%s: Cannot stat %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
close(fdIn);
return 1;
}
if(S_ISDIR(statBuf.st_mode)) {
close(fdIn);
fprintf(stderr,"%s: %s: omitting directory\n",ProgramName,paramInputFile);
return 0; /* At this point, don't consider this a fatal error */
}
fdOut = open(OutputFile,O_CREAT | O_TRUNC | O_WRONLY,statBuf.st_mode);
if (fdOut == -1) {
fprintf(stderr,"%s: Cannot create %s, %s\n",ProgramName,paramOutputFile,
strerror(errno));
close(fdIn);
return 1;
}
fileSize = lseek(fdIn,0,SEEK_END);
if (fileSize < 0) {
fprintf(stderr,"%s: lseek error on %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
close(fdOut);
close(fdIn);
return 1;
}
lseek(fdIn,0,SEEK_SET);
if (optVerbose) {
printf("Normal copy: %s -> %s 0%%",paramInputFile,paramOutputFile);
fflush(stdout);
}
totalSize = fileSize;
while (fileSize) {
int currentMove;
int writeAmt;
currentMove = (fileSize > BufferSize) ? BufferSize : fileSize;
if (read(fdIn,Buffer,currentMove) != currentMove) {
fprintf(stderr,"%s: Error reading %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
close(fdIn);
close(fdOut);
return 1;
}
writeAmt = write(fdOut,Buffer,currentMove);
if (writeAmt < 0) {
fprintf(stderr,"%s: Error writing %s, %s\n",ProgramName,paramOutputFile,
strerror(errno));
close(fdIn);
close(fdOut);
return 1;
} else if (writeAmt == 0) {
fprintf(stderr,"%s: Out of space on destination device writing %s\n",
ProgramName,OutputFile);
close(fdIn);
close(fdOut);
return 1;
}
fileSize -= currentMove;
if (optVerbose) {
printf("\rNormal copy: %s -> %s %ld%%",paramInputFile,paramOutputFile,(100 - (fileSize * 100/totalSize)));
fflush(stdout);
}
}
close(fdOut);
close(fdIn);
if (optVerbose)
printf("\n");
return 0;
}
/****************************************************************************
* Converts a string to upper case.
* Netware file names need to be all upper case.
*/
char *upString(char *str)
{
char *alias = str;
while (*alias) {
*alias = toupper(*alias);
++alias;
}
return str;
}
/****************************************************************************
* Locates the first occurrance of a single character in the input string.
* returns -1 if the character is not found.
*/
int stringPosition(const char *str,char token)
{
const char *alias = str;
while (*alias) {
if (*alias == token) return alias - str;
alias++;
}
return -1;
}
/****************************************************************************
* Walks up the directory path building info structures along the way
* in order to get a dir_handle.
* This will mangle the input "FileString", leaving just the file name
* component in it when it is finished.
*/
int getDirHandle(struct ncp_conn *conn, char *FileString, __u8 *NewDirHandle)
{
struct nw_info_struct info1,info2;
int currentLevel = 0;
int k;
struct nw_info_struct *parentInfo = NULL;
struct nw_info_struct *currentInfo = NULL;
while ( (k = stringPosition(FileString,'/')) >= 0) {
FileString[k] = 0;
if (!currentLevel) {
parentInfo = NULL;
currentInfo = &info1;
} else if (currentLevel % 2) {
parentInfo = &info1;
currentInfo = &info2;
} else {
parentInfo = &info2;
currentInfo = &info1;
}
if (ncp_do_lookup(conn, parentInfo, FileString,
currentInfo) != 0) {
fprintf(stderr,"%s: Ncp lookup failed on directory %s--%s\n",
ProgramName,FileString,strerror(errno));
return 1;
}
++currentLevel;
memmove(FileString,FileString+k+1,strlen(FileString+k+1)+1);
}
if (ncp_alloc_short_dir_handle(conn, currentInfo, NCP_ALLOC_TEMPORARY,
NewDirHandle) != 0) {
fprintf(stderr,"%s: Ncp alloc dir handle failed--%s\n",
ProgramName,strerror(errno));
return 1;
}
return 0;
}
/****************************************************************************
* Interfaces with the ncplib to do the netware copy of the file.
*/
int netwareCopyFile(int ncpMountIndex, const char *sourcefile,
const char *destfile,
const char *paramInputFile,
const char *paramOutputFile)
{
__u8 source_dir_handle;
__u8 dest_dir_handle;
struct ncp_file_info source_file;
struct ncp_file_info dest_file;
__u32 amountCopied;
__u32 amtLeft;
__u32 totalSize;
__u32 sourceOff;
__u32 thisMove;
int stroffset;
int retValue;
char *sourceDup;
char *destDup;
struct ncp_conn *sourceconn;
int retryCount;
long err = 0;
/* Establish a connection to a Netware mount point if
one is not already established. */
if (!NcpMountTable[ncpMountIndex].conn) {
NcpMountTable[ncpMountIndex].conn =
ncp_open_mount(NcpMountTable[ncpMountIndex].mountDir,&err);
if (err) {
com_err(ProgramName,err,"opening ncp connection on mount point %s",
NcpMountTable[ncpMountIndex].mountDir);
return 2;
}
}
sourceconn = NcpMountTable[ncpMountIndex].conn;
/* Duplicate and upper case the file names so we do not trample
on the input strings */
stroffset = strlen(NcpMountTable[ncpMountIndex].mountDir) + 1;
sourceDup = duplicateStr(sourcefile+stroffset);
destDup = duplicateStr(destfile+stroffset);
if (!sourceDup || !destDup) {
fprintf(stderr,"%s: Malloc failed duplicating file names\n",
ProgramName);
return 2;
}
upString(sourceDup);
upString(destDup);
/* Get Handles to the input and output directories */
if (getDirHandle(sourceconn,sourceDup,&source_dir_handle) ||
getDirHandle(sourceconn,destDup,&dest_dir_handle)) {
free(sourceDup);
free(destDup);
return 1;
}
/* Open the input and output files. */
if (ncp_open_file(sourceconn, source_dir_handle, sourceDup,0,AR_READ,
&source_file) != 0) {
fprintf(stderr,"%s: Cannot open %s--%s\n",
ProgramName,paramInputFile,strerror(errno));
free(sourceDup);
free(destDup);
return 1;
}
if (ncp_create_file(sourceconn, dest_dir_handle, destDup,
source_file.file_attributes, &dest_file) != 0) {
fprintf(stderr,"%s: Cannot create %s--%s\n",ProgramName, paramOutputFile,
strerror(errno));
ncp_close_file(sourceconn,source_file.file_id);
free(sourceDup);
free(destDup);
return 1;
}
/* Set globals in case a signal happens while copying */
CurrentConn = sourceconn;
CurrentFile = &dest_file;
OutputOpen = 1;
free(sourceDup);
free(destDup);
retValue = 0;
if (optVerbose) {
printf("NetWare copy: %s -> %s 0%%",paramInputFile,paramOutputFile);
fflush(stdout);
}
/* The main copy loop. */
amtLeft = totalSize = source_file.file_length;
sourceOff = 0;
retryCount = 0;
while (amtLeft && retryCount < MaxNcopyRetries) {
int ncopyRetValue;
if (amtLeft > CopyBlockSize)
thisMove = CopyBlockSize;
else
thisMove = amtLeft;
/* If we are being nice and we've copied enough blocks, go to sleep */
if (optNice) {
if (BlocksCopied == optNiceFactor) {
sleep(NiceSleepTime);
BlocksCopied=0;
} else
++BlocksCopied;
}
ncopyRetValue = ncp_copy_file(sourceconn, source_file.file_id,
dest_file.file_id, sourceOff,sourceOff,
thisMove,&amountCopied);
if (ncopyRetValue != 0) {
/* In my testing this only happens when you run out of space
on the server.
Netware seems to wait a bit before reporting space recently
free'd. I will just wait a bit before bombin */
sleep(1); /* Sleep for a second and try again */
retryCount++;
amountCopied = thisMove = 0;
}
if (amountCopied != thisMove) {
fprintf(stderr,"%s: Warning, amountCopied (%u) != thisMove (%u)\n",
ProgramName,(unsigned int)amountCopied,(unsigned int)thisMove);
}
#ifdef NCOPY_DEBUG
fprintf(stderr,"Copied %u (actual %u)\n",(unsigned int)thisMove,
(unsigned int)amountCopied);
#endif
amtLeft -= amountCopied;
sourceOff += amountCopied;
if (optVerbose) {
printf("\rNetWare copy: %s -> %s %ld%%",paramInputFile,paramOutputFile,
(100 - (long)((float)amtLeft /(float)totalSize * 100.0)));
if (retryCount)
printf(" %d retries",retryCount);
fflush(stdout);
}
}
if (retryCount >= MaxNcopyRetries)
retValue = 1;
if (optVerbose)
printf("\n");
if (ncp_close_file(sourceconn,dest_file.file_id) != 0) {
fprintf(stderr,"%s: Close failed for %s\n",ProgramName,paramOutputFile);
retValue = 1;
}
/* Clear signal handling globals */
OutputOpen = 0;
CurrentConn = NULL;
CurrentFile = NULL;
if (ncp_close_file(sourceconn,source_file.file_id) != 0) {
fprintf(stderr,"%s: Close failed for %s\n",ProgramName,paramInputFile);
retValue = 1;
}
if (ncp_dealloc_dir_handle(sourceconn, dest_dir_handle) != 0)
{
fprintf(stderr,"%s: Dealloc dir handle error for %s\n",ProgramName,
paramOutputFile);
retValue = 1;
}
if (ncp_dealloc_dir_handle(sourceconn, source_dir_handle) != 0)
{
fprintf(stderr,"%s: Dealloc dir handle error for %s\n",ProgramName,
paramInputFile);
retValue = 1;
}
return retValue;
}
/****************************************************************************
* Decides whether to use the traditional file copy or the netware remote
* file copy.
*/
int copyFiles(const char *realsource, const char *realdestination,
const char *paraminputfile, const char *paramoutputfile)
{
int oldUMask;
char fileBuffer[24000];
int retVal = 0;
int ncpMountIndex = ncpIndex(realsource,realdestination);
#ifdef NCOPY_DEBUG
printf("Real Source '%s'\n"
"Real Dest '%s'\n"
"Param Src '%s'\n"
"Param Dest '%s'\n",realsource,realdestination,paraminputfile,
paramoutputfile);
#endif
oldUMask = umask(0);
if (ncpMountIndex < 0)
retVal = normalFileCopy(realsource,realdestination,fileBuffer,
sizeof(fileBuffer),
paraminputfile,paramoutputfile);
else
retVal = netwareCopyFile(ncpMountIndex,realsource,realdestination,
paraminputfile,paramoutputfile);
umask(oldUMask);
return retVal;
}
/****************************************************************************
*
* HERE
*
* Brian may NEED "fake" path if he prints error messages?
* or I may need a way to get his error messages so I can
* print them with the "fake" path.
* My current error messages are on the REAL path, which would be confusing...
*
* (1-source problem, 2-destination problem, 3-other fatal)
* We need to decide when to exit or continue the loop,
* and what to return when we do exit the loop.
* Is it failure if 3 files are to be copied, and 1 fails?
* If one copy fails, we stay in the loop, right?
* Is it failure if destination fails?
* Do we Stay in the loop?
*/
static int copyRealPaths(const char *source, const char *destination)
{
char realsource[MAXPATHLEN*2];
char realdestination[MAXPATHLEN*2];
char dirPart[MAXPATHLEN+1];
char filePart[MAXPATHLEN+1];
const char *p;
if(realpath(source, realsource) == 0) { /* the source must at least exist */
fprintf(stderr,"%s: %s: %s\n",
ProgramName, source, strerror(errno));
return 1; /* indicate a "source" problem */
}
if(realpath(destination, realdestination) == 0) {/* dest file missing? OK */
strncpy(dirPart, destination, MAXPATHLEN); /* but "dirpart" must work */
dirPart[MAXPATHLEN] = 0;
p=myBaseName(dirPart);
strcpy(filePart, p);
dirPart[p - dirPart] = 0; /* isolates "directory" part from "file part" */
if(realpath(dirPart, realdestination) == 0) {
fprintf(stderr,"%s: %s: %s\n",
ProgramName, dirPart, strerror(errno));
return 2; /* indicate a "destination" problem */
}
if(*realdestination != '/' || *(realdestination+1)) strcat(realdestination, "/");
strcat(realdestination, filePart);
}
/* becomes prog exit code */
/* Test Cases: (Where file/dir may or may not exist)
* "", file, file/, dir, dir/
* /, //, /dir, /dir/, /file, /file/,
* /tmp/file, /tmp/file/, tmp/file, tmp/file/,
* /tmp/dir, /tmp/dir/, tmp/dir, tmp/dir/
*/
return copyFiles(realsource, realdestination,source,destination);
}
/****************************************************************************
* guaranteed argc is at least 2 and
* if argc > 2 last parameter is a directory
* by validateFileArgs()
*/
static int handleFileArgs(int argc, char * const argv[])
{
int loop;
const char *destination;
int copyStatus;
int returnCode=0; /* default program exit code */
const char *baseNamePtr;
char destinationfile[MAXPATHLEN*2];
destination=argv[argc-1]; /* get LAST argument */
for (loop = 0; loop < (argc-1); loop++) { /* all file arguments, but last */
strncpy(destinationfile, destination, MAXPATHLEN);
destinationfile[MAXPATHLEN]=0;
if((argc > 2) || (!notDir(argv[argc-1]))) { /* destination is a dir */
if(*destinationfile != '/' || *(destinationfile+1)) strcat(destinationfile,"/");
baseNamePtr=myBaseName(argv[loop]); /* get the file name */
strcat(destinationfile,baseNamePtr); /* add it on end of directory */
}
copyStatus=copyRealPaths(argv[loop], destinationfile); /* do the copy */
if(copyStatus > 1) return copyStatus; /* fatal failure? bye */
if(copyStatus == 1) returnCode=1; /* a partial failure? we can continue */
}
return returnCode; /* return what will be the program exit code */
}
/****************************************************************************
*
*/
static void handleSignals(int sigNumber)
{
/* Ignore Signal Handling while cleaning up */
/* SIGHUP */
sHangupSig.sa_handler=SIG_IGN;
if(sigaction(SIGHUP, &sHangupSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGHUP signal failed: %s",
ProgramName, strerror(errno));
}
/* SIGINT */
sInterruptSig.sa_handler=SIG_IGN;
if(sigaction(SIGINT, &sInterruptSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGINT signal failed: %s",
ProgramName, strerror(errno));
}
/* SIGQUIT */
sQuitSig.sa_handler=SIG_IGN;
if(sigaction(SIGQUIT, &sQuitSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGQUIT signal failed: %s",
ProgramName, strerror(errno));
}
/* SIGTERM */
sTermSig.sa_handler=SIG_IGN;
if(sigaction(SIGTERM, &sTermSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGTERM signal failed: %s",
ProgramName, strerror(errno));
}
/* If we don't close the ncp output file, we have to ncpumount and
ncpmount before we can get rid of it. */
if (OutputOpen) {
/* Issue a warning if we cannot close the file */
/* If an error occurs we probably have to umount/mount to
remove the file */
if (ncp_close_file(CurrentConn,CurrentFile->file_id) != 0) {
fprintf(stderr,"%s: unclean close of output file",ProgramName);
}
OutputOpen = 0;
}
exit(128 + sigNumber);
}
/****************************************************************************
* We'll trap Hangup, Interrupt, Quit or Terminate
*/
static int trapSignals()
{
if(sigaction(SIGHUP, NULL, &sHangupSig)) { /* init structure fields */
fprintf(stderr,"%s: Get HANGUP signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sHangupSig.sa_handler = handleSignals;
if(sigaction(SIGHUP, &sHangupSig, NULL) == -1) {
fprintf(stderr,"%s: Reset HANGUP signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
if(sigaction(SIGINT, NULL, &sInterruptSig)) { /* init structure fields */
fprintf(stderr,"%s: Get INTERRUPT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sInterruptSig.sa_handler = handleSignals;
if(sigaction(SIGINT, &sInterruptSig, NULL) == -1) {
fprintf(stderr,"%s: Reset INTERRUPT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
if(sigaction(SIGQUIT, NULL, &sQuitSig)) { /* init structure fields */
fprintf(stderr,"%s: Get QUIT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sQuitSig.sa_handler = handleSignals;
if(sigaction(SIGQUIT, &sQuitSig, NULL) == -1) {
fprintf(stderr,"%s: Reset QUIT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
if(sigaction(SIGTERM, NULL, &sTermSig)) { /* init structure fields */
fprintf(stderr,"%s: Get TERMINATE signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sTermSig.sa_handler = handleSignals;
if(sigaction(SIGTERM, &sTermSig, NULL) == -1) {
fprintf(stderr,"%s: Reset TERMINATE signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
return 0;
}
/****************************************************************************
*
*/
int main(int argc, char * const argv[])
{
int returnCode;
ProgramName=argv[0];
if(handleOptions(argc, argv)) { /* bad option, missing option parameter */
usage();
return 1;
}
if(optVersion) { /* only option not requiring any arguments */
printf("%s version %s\n", ProgramName, VersionStr);
return 0;
}
if(validateFileArgs(argc - optind, argv + optind)) {
usage();
return 1;
}
if(trapSignals()) return 1;
loadMountTable();
returnCode = handleFileArgs(argc - optind, argv + optind);
releaseMountTable();
return returnCode;
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More