Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d0e3d011b | ||
|
|
84cb1f167d | ||
|
|
64f006632a | ||
|
|
92f749a943 | ||
|
|
6cb56005ea | ||
|
|
0520c1d2f7 | ||
|
|
d5ac4601b1 | ||
|
|
1fa124bd7c | ||
|
|
5753870858 | ||
|
|
b8ce93c8bd | ||
|
|
7bef99df0f | ||
|
|
d31ec2ab61 | ||
|
|
1ee60bade6 |
BIN
.downloads/ncpfs-0.12.tgz
Normal file
BIN
.downloads/ncpfs-0.12.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.13.tgz
Normal file
BIN
.downloads/ncpfs-0.13.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.14.tgz
Normal file
BIN
.downloads/ncpfs-0.14.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.15.tgz
Normal file
BIN
.downloads/ncpfs-0.15.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.16.tgz
Normal file
BIN
.downloads/ncpfs-0.16.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.17.tgz
Normal file
BIN
.downloads/ncpfs-0.17.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.18.tgz
Normal file
BIN
.downloads/ncpfs-0.18.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.19.tgz
Normal file
BIN
.downloads/ncpfs-0.19.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.20.tgz
Normal file
BIN
.downloads/ncpfs-0.20.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.21.tgz
Normal file
BIN
.downloads/ncpfs-0.21.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.22.tgz
Normal file
BIN
.downloads/ncpfs-0.22.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.23.tgz
Normal file
BIN
.downloads/ncpfs-0.23.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.24.tgz
Normal file
BIN
.downloads/ncpfs-0.24.tgz
Normal file
Binary file not shown.
21
BUGS
21
BUGS
@@ -3,17 +3,20 @@ them to be bugs.
|
||||
|
||||
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.
|
||||
|
||||
In your kernel log, there will appear messages like
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
If you use Linux 1.2.x, In your kernel log there will appear messages
|
||||
like
|
||||
|
||||
Nov 25 16:09:08 lx01 kernel: alloc_skb called nonatomically from interrupt 0000002e
|
||||
|
||||
These are a bit annoying, but completely harmless. Maybe this will be
|
||||
fixed in the future.
|
||||
These are a bit annoying, but completely harmless.
|
||||
|
||||
113
Changes
Normal file
113
Changes
Normal file
@@ -0,0 +1,113 @@
|
||||
I only began this file with ncpfs-0.12. If you're interested in older
|
||||
versions, you can find them on ftp.gwdg.de:/pub/linux/misc/ncpfs/old.
|
||||
|
||||
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
|
||||
|
||||
- Improvements of manual pages by B. Galliart <bgallia@luc.edu> and
|
||||
Terry Dawson <terry@perf.no.itg.telecom.com.au>
|
||||
- fsinfo
|
||||
- pserver.c. Please see this as ALPHA software. There is no
|
||||
documentation, and it is not tested enough. But it might be useful for
|
||||
you.
|
||||
|
||||
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.
|
||||
74
FAQ
Normal file
74
FAQ
Normal file
@@ -0,0 +1,74 @@
|
||||
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: Does ncpfs support long file names, using the OS/2 namespace?
|
||||
|
||||
No. Not yet. I still have to sort out how that really works. But it should
|
||||
certainly be possible.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
39
Makefile
39
Makefile
@@ -2,27 +2,29 @@
|
||||
# Makefile for the linux ncp-filesystem routines.
|
||||
#
|
||||
|
||||
# KERNEL = 1.2
|
||||
VERSION = 0.24
|
||||
|
||||
# If you are using kerneld to autoload ncp support,
|
||||
# uncomment this (kerneld is in linux since about 1.3.57):
|
||||
#KERNELD = -DHAVE_KERNELD
|
||||
|
||||
TOPDIR = $(shell pwd)
|
||||
|
||||
BINDIR = /usr/local/bin
|
||||
SBINDIR = /sbin
|
||||
INTERM_BINDIR = $(TOPDIR)/bin
|
||||
SUBDIRS = util ipx-0.75 man
|
||||
SUBDIRS = util ipx-1.0 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.
|
||||
#
|
||||
KVERSION=$(shell uname -r | cut -b3)
|
||||
|
||||
ifeq ($(KVERSION),2)
|
||||
SUBDIRS += kernel-1.2/src
|
||||
INCLUDES = -I$(TOPDIR)/kernel-1.2
|
||||
endif
|
||||
|
||||
export INCLUDES BINDIR INTERM_BINDIR
|
||||
export INCLUDES BINDIR INTERM_BINDIR SBINDIR KERNELD VERSION
|
||||
|
||||
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
|
||||
@@ -37,9 +39,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
|
||||
(cd daemon; make clean)
|
||||
|
||||
modules: ncpfs.o
|
||||
|
||||
@@ -47,11 +50,17 @@ SRCPATH=$(shell pwd)
|
||||
SRCDIR=$(shell basename $(SRCPATH))
|
||||
DISTFILE=$(SRCDIR).tgz
|
||||
|
||||
dist: tgz
|
||||
dist: mrproper
|
||||
mv daemon ..
|
||||
(cd ..; \
|
||||
tar cvf - $(SRCDIR) | \
|
||||
gzip -9 > $(DISTFILE); \
|
||||
mv $(DISTFILE) $(SRCDIR))
|
||||
mv ../daemon .
|
||||
make dep
|
||||
make all
|
||||
|
||||
tgz: realclean
|
||||
tgz: mrproper
|
||||
(cd ..; \
|
||||
tar cvf - $(SRCDIR) | \
|
||||
gzip -9 > $(DISTFILE); \
|
||||
|
||||
80
README
80
README
@@ -1,14 +1,18 @@
|
||||
This is version 0.11 of ncpfs, a free NetWare client filesystem for
|
||||
Linux.
|
||||
|
||||
I would like to invite you to write documentation. As those whose
|
||||
native tongue is English might have noticed, my C is better than my
|
||||
English. So I doubt that everything in the man/ subdirectory is
|
||||
written very well. Please feel free to send me any comments about
|
||||
that.
|
||||
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. The opposite side, pserver, is also
|
||||
provided.
|
||||
|
||||
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
|
||||
@@ -16,10 +20,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
|
||||
@@ -27,10 +30,26 @@ 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.
|
||||
|
||||
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
|
||||
@@ -74,7 +93,7 @@ I do not want to leave those unmentioned, who have helped me with
|
||||
ncpfs.
|
||||
|
||||
The most enthusiastic user and tester is certainly Uwe Bonnes
|
||||
<bon@elektron.ikp.physik.th-darmstadt.de>. Up to now he's the only one
|
||||
<bon@elektron.ikp.physik.th-darmstadt.de>. So far he's the only one
|
||||
who has contributed something, namely manpages and corretions to
|
||||
existing manpages.
|
||||
|
||||
@@ -82,6 +101,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 :-)
|
||||
|
||||
@@ -91,27 +112,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
|
||||
|
||||
20
TODO
Normal file
20
TODO
Normal file
@@ -0,0 +1,20 @@
|
||||
Here's a list of things I want to do. Feel free to send suggestions,
|
||||
or even help me ;-).
|
||||
|
||||
- little utilities for bindery access, such as nwlsobj, nwlsprop,
|
||||
nwcreateobj and so on.
|
||||
|
||||
- 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.
|
||||
|
||||
- long file names
|
||||
|
||||
- Do some kind of mapping of NCP uid's to unix uid's
|
||||
9
ipx-1.0/COPYING
Normal file
9
ipx-1.0/COPYING
Normal 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
24
ipx-1.0/Gregs.Makefile
Normal 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
|
||||
|
||||
@@ -25,6 +25,6 @@ clean:
|
||||
install: $(UTILS)
|
||||
for i in $(UTILS); \
|
||||
do \
|
||||
install --strip $$i $(BINDIR); \
|
||||
install $$i $(BINDIR); \
|
||||
done
|
||||
|
||||
@@ -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
|
||||
@@ -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
7
ipx-1.0/config.ipx
Normal 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
41
ipx-1.0/init.ipx
Normal 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
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -19,7 +24,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 +34,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}
|
||||
@@ -162,6 +171,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 +255,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 +369,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];
|
||||
@@ -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>
|
||||
@@ -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
35
ipxdump/Makefile
Normal 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
45
ipxdump/README
Normal 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>
|
||||
BIN
ipxdump/ipxdump
Executable file
BIN
ipxdump/ipxdump
Executable file
Binary file not shown.
245
ipxdump/ipxdump.c
Normal file
245
ipxdump/ipxdump.c
Normal 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;
|
||||
}
|
||||
}
|
||||
BIN
ipxdump/ipxparse
Executable file
BIN
ipxdump/ipxparse
Executable file
Binary file not shown.
538
ipxdump/ipxparse.c
Normal file
538
ipxdump/ipxparse.c
Normal file
@@ -0,0 +1,538 @@
|
||||
/* 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));
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
#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 ( (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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 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 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;
|
||||
}
|
||||
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 23:
|
||||
printf("Get Crypt Key\n");
|
||||
break;
|
||||
case 24:
|
||||
printf("Encrypted Login\n");
|
||||
break;
|
||||
case 28:
|
||||
printf("Get Connection Information\n");
|
||||
break;
|
||||
case 53:
|
||||
printf("Get Bindery Object ID\n");
|
||||
break;
|
||||
case 55:
|
||||
printf("Scan Bindery Object\n");
|
||||
break;
|
||||
case 61:
|
||||
printf("Read Property Value\n");
|
||||
break;
|
||||
case 62:
|
||||
printf("Write Property Value\n");
|
||||
break;
|
||||
case 70:
|
||||
printf("Get Bindery Access Level\n");
|
||||
break;
|
||||
}
|
||||
|
||||
data += 3;
|
||||
data_length -= 3;
|
||||
break;
|
||||
case 24:
|
||||
printf("fn: %-3d\n", rq->function);
|
||||
printf("End of Job\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 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 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;
|
||||
}
|
||||
data += 1;
|
||||
data_length -= 1;
|
||||
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
129
ipxdump/ipxutil.c
Normal 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
65
ipxdump/ipxutil.h
Normal 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
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ncp_fs.h
|
||||
* ncp.h
|
||||
*
|
||||
* Copyright (C) 1995 by Volker Lendecke
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ struct ncp_server {
|
||||
it completely. */
|
||||
|
||||
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 +34,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 +56,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
|
||||
|
||||
@@ -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? */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -102,7 +103,7 @@ static struct file_operations ncp_dir_operations = {
|
||||
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 +130,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 DosDirNum 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.DosDirNum : (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 +195,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 +242,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 +252,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 +265,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,40 +309,44 @@ 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;
|
||||
@@ -274,7 +361,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 +369,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.DosDirNum);
|
||||
}
|
||||
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 +435,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 +454,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 +539,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 +620,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 +671,8 @@ ncp_init_root(struct ncp_server *server)
|
||||
root->finfo.opened = 0;
|
||||
i->attributes = aDIR;
|
||||
i->dataStreamSize = 1024;
|
||||
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));
|
||||
ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
|
||||
@@ -580,6 +686,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)
|
||||
{
|
||||
@@ -610,7 +735,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,7 +749,14 @@ ncp_find_inode(struct inode *dir, const char *name)
|
||||
do
|
||||
{
|
||||
if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
|
||||
&& (strcmp(result->finfo.i.entryName, name) == 0))
|
||||
&& (result->dir->finfo.i.volNumber == dir_info->volNumber)
|
||||
&& (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;
|
||||
}
|
||||
@@ -645,6 +777,8 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
struct ncp_inode_info *result_info;
|
||||
int found_in_cache;
|
||||
|
||||
char name[len+1];
|
||||
|
||||
*result = NULL;
|
||||
|
||||
if (!dir || !S_ISDIR(dir->i_mode))
|
||||
@@ -654,9 +788,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] == '.'))
|
||||
@@ -675,7 +814,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)
|
||||
{
|
||||
@@ -687,7 +826,10 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
}
|
||||
}
|
||||
|
||||
result_info = ncp_find_inode(dir, __name);
|
||||
memcpy(name, __name, len);
|
||||
name[len] = 0;
|
||||
lock_super(dir->i_sb);
|
||||
result_info = ncp_find_dir_inode(dir, name);
|
||||
|
||||
if (result_info != 0)
|
||||
{
|
||||
@@ -699,7 +841,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)
|
||||
@@ -714,8 +857,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;
|
||||
@@ -726,7 +871,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
|
||||
i, c_entry[i].i.entryName);
|
||||
|
||||
if (strcmp(c_entry[i].i.entryName, __name) == 0)
|
||||
if (strcmp(c_entry[i].i.entryName, name) == 0)
|
||||
{
|
||||
DPRINTK("ncp_lookup: found in cache!\n");
|
||||
finfo.i = c_entry[i].i;
|
||||
@@ -737,24 +882,30 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
}
|
||||
while (i != first);
|
||||
}
|
||||
ncp_unlock_dircache();
|
||||
|
||||
if (found_in_cache == 0)
|
||||
{
|
||||
char this_name[len+1];
|
||||
|
||||
memcpy(this_name, __name, len);
|
||||
this_name[len] = 0;
|
||||
str_upper(this_name);
|
||||
int res;
|
||||
str_upper(name);
|
||||
|
||||
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
|
||||
NCP_ISTRUCT(dir)->entryName, this_name);
|
||||
NCP_ISTRUCT(dir)->entryName, name);
|
||||
|
||||
if (ncp_do_lookup(server,
|
||||
dir->i_ino == (int)&(NCP_SERVER(dir)->root)
|
||||
? NULL : NCP_ISTRUCT(dir),
|
||||
this_name,
|
||||
&(finfo.i)) != 0)
|
||||
if (ncp_is_server_root(dir))
|
||||
{
|
||||
res = ncp_lookup_volume(server, name, &(finfo.i));
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ncp_obtain_info(server,
|
||||
NCP_ISTRUCT(dir)->volNumber,
|
||||
NCP_ISTRUCT(dir)->DosDirNum,
|
||||
name, &(finfo.i));
|
||||
}
|
||||
if (res != 0)
|
||||
{
|
||||
unlock_super(dir->i_sb);
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
@@ -765,10 +916,12 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
|
||||
if (!(*result = ncp_iget(dir, &finfo)))
|
||||
{
|
||||
unlock_super(dir->i_sb);
|
||||
iput(dir);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
unlock_super(dir->i_sb);
|
||||
iput(dir);
|
||||
return 0;
|
||||
}
|
||||
@@ -788,22 +941,30 @@ 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);
|
||||
|
||||
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);
|
||||
|
||||
str_lower(finfo.i.entryName);
|
||||
finfo.access = O_RDWR;
|
||||
@@ -811,10 +972,12 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
|
||||
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;
|
||||
}
|
||||
@@ -831,6 +994,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
|
||||
|| ( (len == 2)
|
||||
&& (name[1] == '.'))))
|
||||
{
|
||||
iput(dir);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
@@ -844,6 +1008,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,
|
||||
@@ -855,7 +1024,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);
|
||||
@@ -874,8 +1043,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
|
||||
@@ -889,11 +1064,11 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
|
||||
NCP_ISTRUCT(dir),
|
||||
_name)) == 0)
|
||||
{
|
||||
ncp_invalid_dir_cache(dir->i_ino);
|
||||
ncp_invalid_dir_cache(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = -EINVAL;
|
||||
error = -EACCES;
|
||||
}
|
||||
}
|
||||
iput(dir);
|
||||
@@ -912,8 +1087,14 @@ 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
|
||||
@@ -926,11 +1107,11 @@ ncp_unlink(struct inode *dir, const char *name, int len)
|
||||
NCP_ISTRUCT(dir),
|
||||
_name)) == 0)
|
||||
{
|
||||
ncp_invalid_dir_cache(dir->i_ino);
|
||||
ncp_invalid_dir_cache(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = -EINVAL;
|
||||
error = -EACCES;
|
||||
}
|
||||
}
|
||||
iput(dir);
|
||||
@@ -952,6 +1133,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");
|
||||
@@ -959,8 +1146,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;
|
||||
@@ -980,8 +1167,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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -266,56 +266,19 @@ 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 */
|
||||
@@ -323,8 +286,7 @@ ncp_do_lookup(struct ncp_server *server,
|
||||
ncp_add_byte(server, 0); /* dos name space as dest */
|
||||
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,14 +295,54 @@ 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)
|
||||
int
|
||||
ncp_lookup_volume(struct ncp_server *server,
|
||||
char *volname,
|
||||
struct nw_info_struct *target)
|
||||
{
|
||||
int result;
|
||||
__u8 vol_num;
|
||||
__u32 dir_base;
|
||||
|
||||
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 name space */
|
||||
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)
|
||||
{
|
||||
target->nameLen = strlen(volname);
|
||||
strcpy(target->entryName, volname);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
dir_base = ncp_reply_dword(server, 4);
|
||||
vol_num = ncp_reply_byte(server, 8);
|
||||
ncp_unlock_server(server);
|
||||
|
||||
if ((result = ncp_obtain_info(server, vol_num, dir_base, NULL,
|
||||
target)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
DPRINTK("ncp_lookup_volume: attribs = %X\n", target->attributes);
|
||||
|
||||
target->nameLen = strlen(volname);
|
||||
strcpy(target->entryName, volname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -417,12 +419,18 @@ ncp_open_create_file_or_subdir(struct ncp_server *server,
|
||||
struct nw_file_info *target)
|
||||
{
|
||||
int result;
|
||||
__u16 search_attribs = 0x0006;
|
||||
|
||||
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, 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
|
||||
@@ -583,7 +591,7 @@ ncp_read(struct ncp_server *server, const char *file_id,
|
||||
|
||||
*bytes_read = ntohs(ncp_reply_word(server, 0));
|
||||
|
||||
memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read);
|
||||
memcpy_tofs(target, ncp_reply_data(server, 2+(offset&1)), *bytes_read);
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
MAN1= slist nprint pqlist
|
||||
MAN1= slist nprint pqlist nsend pserver ncopy
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ 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
|
||||
@@ -45,6 +48,9 @@ network.
|
||||
.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 device, frame type, and network number
|
||||
of an IPX interface.
|
||||
|
||||
96
man/ncopy.1
Normal file
96
man/ncopy.1
Normal 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.
|
||||
190
man/ncpmount.8
190
man/ncpmount.8
@@ -1,27 +1,27 @@
|
||||
.TH NCPMOUNT 8 12/27/1995 ncpmount ncpmount
|
||||
.SH NAME
|
||||
ncpmount \- mount program for ncpfs
|
||||
ncpmount \- mount all volumes of a specified Novell fileserver.
|
||||
.SH SYNOPSIS
|
||||
.B ncpmount
|
||||
[
|
||||
.B -h
|
||||
] [
|
||||
.B -S
|
||||
.I server
|
||||
] [
|
||||
.B -h
|
||||
] [
|
||||
.B -n
|
||||
.B -U
|
||||
.I user name
|
||||
] [
|
||||
.B -P
|
||||
.I password
|
||||
|
|
||||
.B -n
|
||||
] [
|
||||
.B -C
|
||||
] [
|
||||
.B -c
|
||||
.I client name
|
||||
] [
|
||||
.B -U
|
||||
.I user name
|
||||
] [
|
||||
.B -u
|
||||
.I uid
|
||||
] [
|
||||
@@ -33,14 +33,26 @@ ncpmount \- mount program for ncpfs
|
||||
] [
|
||||
.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
|
||||
This program is an interface to the NCP filesystem.
|
||||
This program is used to mount all volumes of the specified NetWare Fileserver
|
||||
under the specified mount point.
|
||||
|
||||
.B ncpfs
|
||||
is a filesystem which understands the NCP protocol. This is the
|
||||
is a linux filesystem which understands the NCP protocol. This is the
|
||||
protocol Novell NetWare clients use to talk to NetWare servers. ncpfs
|
||||
was inspired by
|
||||
.B lwared,
|
||||
@@ -48,18 +60,23 @@ a free NetWare emulator for Linux written by Ales Dryak. See
|
||||
ftp://klokan.sh.cvut.cz/pub/linux for this very intersting program.
|
||||
|
||||
.B ncpmount
|
||||
looks up the file
|
||||
when invoked with all appropriate arguments attaches, logs in and
|
||||
mounts all of the volumes associated with the specified fileserver that are
|
||||
readable by the user id under the specified mount point.
|
||||
.B ncpmount
|
||||
when invoked without any arguments specifying the fileserver, user id and
|
||||
password checks 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.
|
||||
to find a file server, a user name and possibly a password to use for the
|
||||
specified mount point. See nwclient(5) for more information. Please note
|
||||
that the access permissions of .nwclient MUST be 600, for security reasons.
|
||||
|
||||
.SH OPTIONS
|
||||
.B mount-point
|
||||
.RS 3
|
||||
.B mount-point
|
||||
is the directory you want to mount the filesystem over. It's the same
|
||||
as in the normal mount command.
|
||||
is the directory you want to mount the filesystem over. Its function is the
|
||||
the same as for a normal mount command.
|
||||
|
||||
If the real uid of the caller is not root,
|
||||
.B ncpmount
|
||||
@@ -87,42 +104,40 @@ is used to print out a short help text.
|
||||
|
||||
.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.
|
||||
By default passwords are converted to uppercase before they are sent
|
||||
to the server because most servers require this. This option disables this
|
||||
feature ensuring that passwords are sent without any case conversion.
|
||||
.RE
|
||||
|
||||
.B -n
|
||||
.RS 3
|
||||
.B -n
|
||||
should be given to mount shares which do not require a password to log in.
|
||||
must be specified for logins that do not have a password configured.
|
||||
.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.
|
||||
specifies the password to use for the Netware user id.
|
||||
|
||||
If neither
|
||||
.B -n
|
||||
nor
|
||||
nor the
|
||||
.B -P
|
||||
are given, ncpmount prompts for a password. This makes it difficult to
|
||||
use in scripts such as /etc/rc. But that's not ncpmount's fault, but a
|
||||
general problem with the fact that you need a password on every
|
||||
login. If anybody has a satisfying solution to this problem, please
|
||||
tell me.
|
||||
arguments are specified ncpmount will prompt for a password. This
|
||||
makes it difficult to use in scripts such as /etc/rc. If you want to
|
||||
have ncpmount work automatically from a script you must include the
|
||||
appropriate option and be very careful to ensure that appopriate file
|
||||
permissions are set for the script that includes your password to
|
||||
ensure that others can not read it.
|
||||
.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.
|
||||
Specifies the Netware user id to use when logging in to the fileserver. If
|
||||
this option is not specified then ncpmount will attempt to login to the
|
||||
fileserver using the Linux login id of the user invoking ncpmount.
|
||||
.RE
|
||||
|
||||
.B -u
|
||||
@@ -130,9 +145,9 @@ to tell the server about you NetWare user name.
|
||||
.B -g
|
||||
.I gid
|
||||
.RS 3
|
||||
Currently I did not implement a mapping from NetWare users/groups to
|
||||
unix users/groups. Unix requires that each file has an owner
|
||||
and a group it belongs to. With
|
||||
ncpmount does not yet implement a scheme for mapping NetWare users/groups
|
||||
to Linux users/groups. Linux requires that each file has an owner and group id.
|
||||
With
|
||||
.B -u
|
||||
and
|
||||
.B -g
|
||||
@@ -145,19 +160,20 @@ The defaults for these values are the current uid and gid.
|
||||
.B -c
|
||||
.I user name
|
||||
.RS 3
|
||||
This option is only makes sense if root mounts the directory. root can
|
||||
mount directories on behalf of other users.
|
||||
.B -c
|
||||
names the user who is the
|
||||
.I owner
|
||||
of the connection, where owner is not meant in the unix sense (that
|
||||
"owner" is set by -u), but as the one who has mounted the directory.
|
||||
This way it could be possible to mount a public read-only directory,
|
||||
of the connection, where owner does not refer to file ownership (that
|
||||
"owner" is set by the -u argument), but the owner of the mount, ie: who
|
||||
is allowed to call ncpumount on this mount. The default owner of the
|
||||
connection and the mount is the user who called ncpmount. This option
|
||||
allows you to specify that some other user should be set as the owner.
|
||||
|
||||
In this this way it is possible to mount a public read-only directory,
|
||||
but to allow the lp daemon to print on NetWare queues. This is
|
||||
possible, because only users who have write permissions on a directory
|
||||
may issue ncp requests over a connection. An exception is the owner
|
||||
(in the sense mentioned above), who is also given 'request
|
||||
permission'.
|
||||
possible because only users who have write permissions on a directory
|
||||
may issue ncp requests over a connection. The exception to this rule
|
||||
is the 'mount owner', who is also granted 'request permission'.
|
||||
.RE
|
||||
|
||||
.B -f
|
||||
@@ -169,14 +185,11 @@ Like
|
||||
.B -u
|
||||
and
|
||||
.B -g,
|
||||
these options are also used to cover deficiencies in the
|
||||
implementation of ncpfs. I did not implement a scheme to map NetWare
|
||||
permissions to unix permissions. So ncpmount has to be told which
|
||||
permissions it should assign to the mounted files and directories. The
|
||||
values have to be given as octal numbers. The default values are taken
|
||||
from the current umask, where the file mode is the current umask, and
|
||||
the dir mode adds execute permissions where the file mode gives read
|
||||
permissions.
|
||||
these options are used to determine what permissions should be assigned
|
||||
files and directories of the mounted volumes. The values must be specified
|
||||
as octal numbers. The default values are taken from the current umask, where
|
||||
the file mode is the current umask, and the dir mode adds execute permissions
|
||||
where the file mode gives read permissions.
|
||||
|
||||
Note that these permissions can differ from the rights the server
|
||||
gives to us. If you do not have write permissions on the server, you
|
||||
@@ -184,8 +197,75 @@ 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
|
||||
If you have difficulties in mounting, please make sure that you have configured your ipx subsystem correctly. It is especially important that there is a route to the internal network of your server.
|
||||
You must configure the IPX subsystem before ncpmount will work.
|
||||
It is especially important that there is a route to the internal network
|
||||
of your server.
|
||||
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.B USER / LOGNAME
|
||||
@@ -201,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
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
.TH NCPUMOUNT 8 12/27/1995 ncpumount ncpumount
|
||||
.SH NAME
|
||||
ncpumount \- umount for normal users
|
||||
ncpumount \- unmount a NetWare filesystem mounted with ncpmount.
|
||||
.SH SYNOPSIS
|
||||
.B ncpumount
|
||||
.B mount-point
|
||||
|
||||
.SH DESCRIPTION
|
||||
With this program, normal users can unmount ncp-filesystems, provided
|
||||
that it is suid root.
|
||||
This utility unmounts a NetWare filesystem that was previously mounted
|
||||
with the ncpmount utility. If the this utility is made suid root then
|
||||
non-root users will also be able to make use of it.
|
||||
|
||||
.B ncpumount
|
||||
has been written to give normal linux-users more control over their
|
||||
|
||||
42
man/nprint.1
42
man/nprint.1
@@ -9,18 +9,16 @@ nprint \- NetWare print client
|
||||
] [
|
||||
.B -h
|
||||
] [
|
||||
.B -n
|
||||
] [
|
||||
.B -C
|
||||
] [
|
||||
.B -U
|
||||
.I user name
|
||||
] [
|
||||
.B -P
|
||||
.I password
|
||||
] [
|
||||
|
|
||||
.B -n
|
||||
] [
|
||||
.B -C
|
||||
] [
|
||||
.B -q
|
||||
.I queue name
|
||||
] [
|
||||
@@ -65,6 +63,13 @@ you can print files on print queues of a NetWare file server.
|
||||
There are a lot of options, so you should probably wrap some default
|
||||
configurations into some shell scripts.
|
||||
|
||||
.B nprint
|
||||
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 file
|
||||
.RS 3
|
||||
@@ -73,6 +78,12 @@ is the name of the file you want to print. If file is '-', or no
|
||||
filename is given, standard input is used.
|
||||
.RE
|
||||
|
||||
.B -h
|
||||
.RS 3
|
||||
.B -h
|
||||
is used to print out a short help text.
|
||||
.RE
|
||||
|
||||
.B -S
|
||||
.I server
|
||||
.RS 3
|
||||
@@ -105,12 +116,20 @@ prompts for a password.
|
||||
should be given if no password is required for the print request.
|
||||
.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 to use at the print server. At
|
||||
present, you must give it in upper case characters.
|
||||
present, you must specify it in upper case characters.
|
||||
.RE
|
||||
|
||||
.B -d
|
||||
@@ -161,6 +180,13 @@ is the number of lines to put on one page. Default: 66
|
||||
is the number of rows to put on one page. Default: 80
|
||||
.RE
|
||||
|
||||
.B -c
|
||||
.I copies
|
||||
.RS 3
|
||||
.B copies
|
||||
tells the print server to the specified number of copies. Default: 1
|
||||
.RE
|
||||
|
||||
.B -t
|
||||
.I tabs
|
||||
.RS 3
|
||||
@@ -189,4 +215,8 @@ different from the one currently in the printer, your job is only
|
||||
printed if a printer operator has put in the correct form.
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
.B nwclient(5), slist(1), pqlist(1), ncpmount(8), ncpumount(8)
|
||||
|
||||
.SH CREDITS
|
||||
nprint was written by Volker Lendecke (lendecke@namu01.gwdg.de)
|
||||
|
||||
108
man/nsend.1
Normal file
108
man/nsend.1
Normal 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>
|
||||
@@ -13,8 +13,8 @@ connection. Lines beginning with # and empty lines are ignored as
|
||||
comments.
|
||||
|
||||
Because you can store passwords in .nwclient, the user programs will
|
||||
only scan .nwclient if ONLY the file owner has any access rights to
|
||||
the file.
|
||||
only scan .nwclient when only the file owner has access rights to
|
||||
the file. The file must be have permissions 0600.
|
||||
|
||||
To specify a NWClient connection, the name of the file server, the
|
||||
user name to be used and a password is necessary. The server name and
|
||||
@@ -40,3 +40,16 @@ the the file server FS311 with user name ME on /mnt after asking the
|
||||
user for a password.
|
||||
|
||||
\'nwmount -S cd-serv /cd' will silently mount the server cd-serv on /cd.
|
||||
|
||||
.B nprint
|
||||
,
|
||||
.B pqlist
|
||||
and other user programs that require a valid login also look up
|
||||
.I $HOME/.nwclient
|
||||
to find a file server, a user name and possibly a password.
|
||||
|
||||
Please note that the access permissions of .nwclient MUST be 600, for
|
||||
security reasons.
|
||||
|
||||
.SH SEE ALSO
|
||||
.B ncpmount(8), ncpumount(8), slist(1), pqlist(1), nprint(1)
|
||||
|
||||
33
man/nwmsg.8
Normal file
33
man/nwmsg.8
Normal 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)
|
||||
86
man/pqlist.1
86
man/pqlist.1
@@ -4,25 +4,40 @@ pqlist \- List available NetWare print queues
|
||||
.SH SYNOPSIS
|
||||
.B pqlist
|
||||
[
|
||||
.B -h
|
||||
] [
|
||||
.B -S
|
||||
.I server
|
||||
] [
|
||||
.B -U
|
||||
.I user name
|
||||
] [
|
||||
.B -n
|
||||
] [
|
||||
.B -P
|
||||
.I password
|
||||
|
|
||||
.B -n
|
||||
] [
|
||||
.B -C
|
||||
] [
|
||||
.I pattern
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
With
|
||||
.B pqlist,
|
||||
you can list the NetWare print queues available to you on some
|
||||
server. If you are already connected to some server, this one is
|
||||
used.
|
||||
.B pqlist
|
||||
lists all the NetWare print queues available to you on some server.
|
||||
If you are already connected to some server, this one is used.
|
||||
|
||||
If pqlist does not print to a tty, the decorative header line is
|
||||
not printed, so that you can count the printing queue available
|
||||
on your server by doing
|
||||
|
||||
pqlist -S server | wc -l
|
||||
|
||||
.B pqlist
|
||||
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
|
||||
|
||||
@@ -34,6 +49,57 @@ pattern, but you have to be careful to prevent shell interpretation of
|
||||
wildcards like '*'.
|
||||
.RE
|
||||
|
||||
See ncpmount(8) for an explanation of the other options. They are
|
||||
necessary because you might have to login into a server before it
|
||||
tells you where you may print.
|
||||
.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 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, pqlist 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 SEE ALSO
|
||||
.B nwclient(5), nprint(1), slist(1), ncpmount(8), ncpumount(8)
|
||||
|
||||
.SH CREDITS
|
||||
pqlist was written by Volker Lendecke (lendecke@namu01.gwdg.de)
|
||||
|
||||
142
man/pserver.1
Normal file
142
man/pserver.1
Normal 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)
|
||||
25
man/slist.1
25
man/slist.1
@@ -1,16 +1,16 @@
|
||||
.TH SLIST 1 01/07/1996 slist slist
|
||||
.SH NAME
|
||||
slist \- List available NetWare Servers
|
||||
slist \- Lists available NetWare Servers
|
||||
.SH SYNOPSIS
|
||||
.B slist
|
||||
[
|
||||
.I pattern
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
With
|
||||
.B slist,
|
||||
you can get a list of NetWare Servers available in your network. If
|
||||
slist does not print to a tty, the decorative header line is not
|
||||
.B slist
|
||||
lists all NetWare Servers available in your network.
|
||||
|
||||
If slist does not print to a tty, the decorative header line is not
|
||||
printed, so that you can count the servers on your network by doing
|
||||
|
||||
slist | wc -l
|
||||
@@ -20,10 +20,10 @@ slist | wc -l
|
||||
.B pattern
|
||||
.RS 3
|
||||
.B pattern
|
||||
is used to list only selected servers. For a server to be listed, the
|
||||
pattern must match the full server name. You can use wildcards for the
|
||||
pattern, but you must protect these wildcards from any command line
|
||||
expansion by quoting. Case doesn't matter.
|
||||
is used to list only servers whose names match the specified pattern. For a
|
||||
server to be listed, the pattern must match the full server name. You can use
|
||||
wildcards for the pattern, but you must protect these wildcards from any
|
||||
command line expansion by quoting. Case doesn't matter.
|
||||
.RE
|
||||
|
||||
.SH EXAMPLE
|
||||
@@ -34,3 +34,10 @@ or
|
||||
.TP
|
||||
slist "i*"
|
||||
List all available Netware servers on your Network, that begin with an "I".
|
||||
|
||||
|
||||
.SH SEE ALSO
|
||||
.B ncpmount(8), ncpumount(8), pqlist(1), nprint(1)
|
||||
|
||||
.SH CREDITS
|
||||
slist was written by Volker Lendecke (lendecke@namu01.gwdg.de)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
Begin3
|
||||
Title: ncpfs
|
||||
Version: 0.11
|
||||
Entered-date: 10. January 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/
|
||||
~66k ncpfs-0.11.tgz
|
||||
~ 1k ncpfs-0.11.lsm
|
||||
Copying-policy: GPL
|
||||
End
|
||||
19
ncpfs-0.24.lsm
Normal file
19
ncpfs-0.24.lsm
Normal file
@@ -0,0 +1,19 @@
|
||||
Begin3
|
||||
Title: ncpfs
|
||||
Version: 0.24
|
||||
Entered-date: 02. June 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/system/Filesystems/ncpfs
|
||||
~120k ncpfs-0.24.tgz
|
||||
~ 1k ncpfs-0.24.lsm
|
||||
Copying-policy: GPL
|
||||
End
|
||||
@@ -2,39 +2,67 @@
|
||||
# Makefile for the linux ncp-filesystem routines.
|
||||
#
|
||||
|
||||
UTIL_EXECS = ncpmount ncpumount nprint slist pqlist
|
||||
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
|
||||
USERUTILS = slist pqlist nwfsinfo pserver nprint nsend ncopy
|
||||
UIDUTILS = ncpmount ncpumount
|
||||
SBINUTILS = nwmsg
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) -O2
|
||||
UTIL_EXECS = $(USERUTILS) $(UIDUTILS) $(SBINUTILS)
|
||||
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
|
||||
|
||||
#CFLAGS = -Wall $(INCLUDES) $(KERNELD) -g -DNCPFS_VERSION=\"$(VERSION)\"
|
||||
CFLAGS = -Wall $(INCLUDES) $(KERNELD) -O2 -DNCPFS_VERSION=\"$(VERSION)\"
|
||||
CC = gcc
|
||||
|
||||
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
|
||||
|
||||
$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) ncplib.o
|
||||
$(CC) -o $@ $(addsuffix .o,$(notdir $@)) ncplib.o
|
||||
$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) libncp.a
|
||||
$(CC) -o $@ $(addsuffix .o,$(notdir $@)) -L. -lncp
|
||||
|
||||
ncplib.o: ncplib.c ncplib.h
|
||||
ncplib.o: ncplib.c ncplib.h ncplib_err.h
|
||||
$(CC) $(CFLAGS) -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
|
||||
|
||||
libncp.a: ncplib.o ncplib_err.o $(COM_ERR_CFILES)
|
||||
make -C com_err
|
||||
ar r libncp.a 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
|
||||
|
||||
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 libncp.a
|
||||
$(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
|
||||
|
||||
realclean: clean
|
||||
mrproper: clean
|
||||
make -C com_err mrproper
|
||||
rm -f $(UTILS) .depend $(DISTFILE)
|
||||
|
||||
#
|
||||
|
||||
1
util/com_err.h
Symbolic link
1
util/com_err.h
Symbolic link
@@ -0,0 +1 @@
|
||||
com_err/com_err.h
|
||||
49
util/com_err/ChangeLog
Normal file
49
util/com_err/ChangeLog
Normal 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
25
util/com_err/Makefile
Normal 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
|
||||
|
||||
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
96
util/com_err/com_err.3
Normal 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
114
util/com_err/com_err.c
Normal 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
40
util/com_err/com_err.h
Normal 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) */
|
||||
554
util/com_err/com_err.texinfo
Normal file
554
util/com_err/com_err.texinfo
Normal 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
11
util/com_err/compile_et
Executable 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
79
util/com_err/compile_et.1
Normal 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".
|
||||
82
util/com_err/error_message.c
Normal file
82
util/com_err/error_message.c
Normal 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);
|
||||
}
|
||||
35
util/com_err/error_table.h
Normal file
35
util/com_err/error_table.h
Normal 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
185
util/com_err/et_c.awk
Normal 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
157
util/com_err/et_h.awk
Normal 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
36
util/com_err/et_name.c
Normal 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
58
util/com_err/init_et.c
Normal 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
22
util/com_err/internal.h
Normal 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
|
||||
19
util/com_err/mit-sipb-copyright.h
Normal file
19
util/com_err/mit-sipb-copyright.h
Normal 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.
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* fsinfo.c
|
||||
*
|
||||
* Print the info strings of a server, maybe sometime more.
|
||||
*
|
||||
* Copyright (C) 1996 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "ncplib.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
char strings[512];
|
||||
char *s;
|
||||
|
||||
if (ncp_initialize(&conn, &argc, argv, 0) != 0)
|
||||
{
|
||||
perror("Could not open connection");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ncp_close(&conn);
|
||||
return 0;
|
||||
}
|
||||
32
util/ipx_sap_types
Normal file
32
util/ipx_sap_types
Normal 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
849
util/ncopy.c
Normal 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;
|
||||
}
|
||||
1512
util/ncplib.c
1512
util/ncplib.c
File diff suppressed because it is too large
Load Diff
263
util/ncplib.h
263
util/ncplib.h
@@ -14,13 +14,19 @@
|
||||
#include <linux/ipx.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ipxlib.h"
|
||||
#include "com_err.h"
|
||||
|
||||
#ifndef memzero
|
||||
#include <string.h>
|
||||
#define memzero(object) memset(&(object), 0, sizeof(object))
|
||||
#endif
|
||||
|
||||
void
|
||||
str_upper(char *name);
|
||||
|
||||
enum connect_state {
|
||||
NOT_CONNECTED = 0,
|
||||
CONN_PERMANENT,
|
||||
@@ -64,41 +70,60 @@ struct ncp_conn_spec {
|
||||
char server[NCP_BINDERY_NAME_LEN];
|
||||
char user[NCP_BINDERY_NAME_LEN];
|
||||
uid_t uid;
|
||||
int login_type; /* NCP_BINDERY_USER / NCP_BINDERY_PSERVER */
|
||||
char password[NCP_BINDERY_NAME_LEN];
|
||||
};
|
||||
|
||||
struct ncp_search_seq {
|
||||
struct nw_search_sequence s;
|
||||
int namespace;
|
||||
};
|
||||
|
||||
struct ncp_property_info {
|
||||
__u8 property_name[16];
|
||||
__u8 property_flags;
|
||||
__u8 property_security;
|
||||
__u32 search_instance;
|
||||
__u8 value_available_flag;
|
||||
__u8 more_properties_flag;
|
||||
};
|
||||
|
||||
/* ncp_initialize is the main entry point for user programs which want
|
||||
to connect to a NetWare Server. It looks for -S, -U, -P and -n in
|
||||
the argument list, opens the connection and removes the arguments
|
||||
from the list. It was designed after the X Windows init
|
||||
functions. */
|
||||
int
|
||||
ncp_initialize(struct ncp_conn *conn,
|
||||
int *argc, char **argv,
|
||||
int login_necessary);
|
||||
struct ncp_conn *
|
||||
ncp_initialize(int *argc, char **argv,
|
||||
int login_necessary, long *err);
|
||||
|
||||
/* You can login as another object by this procedure. As a first use
|
||||
pserver comes to mind. */
|
||||
struct ncp_conn *
|
||||
ncp_initialize_as(int *argc, char **argv,
|
||||
int login_necessary, int login_type, long *err);
|
||||
|
||||
|
||||
/* Open an existing permanent connection */
|
||||
int
|
||||
ncp_open(struct ncp_conn *conn,
|
||||
const struct ncp_conn_spec *spec);
|
||||
struct ncp_conn *
|
||||
ncp_open(const struct ncp_conn_spec *spec, long *err);
|
||||
|
||||
/* Open a connection on an existing mount point */
|
||||
int
|
||||
ncp_open_mount(struct ncp_conn *conn,
|
||||
const char *mount_point);
|
||||
struct ncp_conn *
|
||||
ncp_open_mount(const char *mount_point, long *err);
|
||||
|
||||
/* Detach from and destroy a permanent connection */
|
||||
int
|
||||
ncp_destroy_permanent(struct ncp_conn *conn);
|
||||
/* Find a permanent connection that fits the spec, return NULL if
|
||||
* there is none. */
|
||||
char *
|
||||
ncp_find_permanent(const struct ncp_conn_spec *spec);
|
||||
|
||||
/* Create a temporary connection */
|
||||
int
|
||||
ncp_open_temporary(struct ncp_conn *conn,
|
||||
const struct ncp_conn_spec *spec);
|
||||
/* Find the address of a file server */
|
||||
struct sockaddr_ipx *
|
||||
ncp_find_fileserver(const char *server_name, long *err);
|
||||
|
||||
/* Detach from a permanent connection or destroy a temporary
|
||||
connection */
|
||||
int
|
||||
long
|
||||
ncp_close(struct ncp_conn *conn);
|
||||
|
||||
/* like getmntent, get_ncp_conn_ent scans /etc/mtab for usable
|
||||
@@ -121,133 +146,226 @@ ncp_get_conn_ent(FILE *filep);
|
||||
|
||||
struct ncp_conn_spec *
|
||||
ncp_find_conn_spec(const char *server, const char *user, const char *password,
|
||||
uid_t uid);
|
||||
int login_necessary, uid_t uid, long *err);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_get_file_server_description_strings(struct ncp_conn *conn,
|
||||
char target[512]);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_get_file_server_time(struct ncp_conn *conn, time_t *target);
|
||||
|
||||
long
|
||||
ncp_get_connlist(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
int *returned_no, __u8 conn_numbers[256]);
|
||||
|
||||
long
|
||||
ncp_send_broadcast(struct ncp_conn *conn,
|
||||
__u8 no_conn, const __u8 *connections,
|
||||
const char *message);
|
||||
|
||||
long
|
||||
ncp_get_encryption_key(struct ncp_conn *conn,
|
||||
char *target);
|
||||
int
|
||||
long
|
||||
ncp_get_bindery_object_id(struct ncp_conn *conn,
|
||||
__u16 object_type,
|
||||
const char *object_name,
|
||||
struct ncp_bindery_object *target);
|
||||
int
|
||||
long
|
||||
ncp_get_bindery_object_name(struct ncp_conn *conn,
|
||||
__u32 object_id,
|
||||
struct ncp_bindery_object *target);
|
||||
long
|
||||
ncp_scan_bindery_object(struct ncp_conn *conn,
|
||||
__u32 last_id, __u16 object_type, char *search_string,
|
||||
struct ncp_bindery_object *target);
|
||||
int
|
||||
long
|
||||
ncp_create_bindery_object(struct ncp_conn *conn,
|
||||
struct ncp_bindery_object *source);
|
||||
long
|
||||
ncp_delete_bindery_object(struct ncp_conn *conn,
|
||||
__u16 object_type,
|
||||
const char *object_name);
|
||||
|
||||
struct ncp_prop_login_control {
|
||||
__u8 AccountExpireDate[3] __attribute__ ((packed));
|
||||
__u8 Disabled __attribute__ ((packed));
|
||||
__u8 PasswordExpireDate[3] __attribute__ ((packed));
|
||||
__u8 GraceLogins __attribute__ ((packed));
|
||||
__u16 PasswordExpireInterval __attribute__ ((packed));
|
||||
__u8 MaxGraceLogins __attribute__ ((packed));
|
||||
__u8 MinPasswordLength __attribute__ ((packed));
|
||||
__u16 MaxConnections __attribute__ ((packed));
|
||||
__u8 ConnectionTimeMask[42] __attribute__ ((packed));
|
||||
__u8 LastLogin[6] __attribute__ ((packed));
|
||||
__u8 RestrictionMask __attribute__ ((packed));
|
||||
__u8 reserved __attribute__ ((packed));
|
||||
__u32 MaxDiskUsage __attribute__ ((packed));
|
||||
__u16 BadLoginCount __attribute__ ((packed));
|
||||
__u32 BadLoginCountDown __attribute__ ((packed));
|
||||
__u8 LastIntruder[8] __attribute__ ((packed));
|
||||
};
|
||||
|
||||
long
|
||||
ncp_read_property_value(struct ncp_conn *conn,
|
||||
int object_type, const char *object_name,
|
||||
int segment, const char *prop_name,
|
||||
struct nw_property *target);
|
||||
int
|
||||
long
|
||||
ncp_scan_property(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
__u32 last_id, char *search_string,
|
||||
struct ncp_property_info *property_info);
|
||||
long
|
||||
ncp_add_object_to_set(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
const char *property_name,
|
||||
__u16 member_type,
|
||||
const char *member_name);
|
||||
long
|
||||
ncp_change_property_security(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
const char *property_name,
|
||||
__u8 property_security);
|
||||
long
|
||||
ncp_create_property(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
const char *property_name,
|
||||
__u8 property_flags, __u8 property_security);
|
||||
long
|
||||
ncp_delete_object_from_set(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
const char *property_name,
|
||||
__u16 member_type,
|
||||
const char *member_name);
|
||||
long
|
||||
ncp_delete_property(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
const char *property_name);
|
||||
long
|
||||
ncp_write_property_value(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
const char *property_name,
|
||||
__u8 segment,
|
||||
struct nw_property *property_value);
|
||||
long
|
||||
ncp_login_encrypted(struct ncp_conn *conn,
|
||||
const struct ncp_bindery_object *object,
|
||||
const unsigned char *key,
|
||||
const unsigned char *passwd);
|
||||
int
|
||||
|
||||
#define NCP_GRACE_PERIOD (0xdf)
|
||||
|
||||
long
|
||||
ncp_login_user(struct ncp_conn *conn,
|
||||
const unsigned char *username,
|
||||
const unsigned char *password);
|
||||
int
|
||||
long
|
||||
ncp_get_volume_info_with_number(struct ncp_conn *conn, int n,
|
||||
struct ncp_volume_info *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_get_volume_number(struct ncp_conn *conn, const char *name,
|
||||
int *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_file_search_init(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path,
|
||||
struct ncp_filesearch_info *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_file_search_continue(struct ncp_conn *conn,
|
||||
struct ncp_filesearch_info *fsinfo,
|
||||
int attributes, const char *path,
|
||||
struct ncp_file_info *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_get_finfo(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path, const char *name,
|
||||
struct ncp_file_info *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_open_file(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path,
|
||||
int attr, int access,
|
||||
struct ncp_file_info *target);
|
||||
int
|
||||
long
|
||||
ncp_close_file(struct ncp_conn *conn, const char *file_id);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_create_newfile(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path,
|
||||
int attr,
|
||||
struct ncp_file_info *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_create_file(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path,
|
||||
int attr,
|
||||
struct ncp_file_info *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_erase_file(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path,
|
||||
int attr);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_rename_file(struct ncp_conn *conn,
|
||||
int old_handle, const char *old_path,
|
||||
int attr,
|
||||
int new_handle, const char *new_path);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_create_directory(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path,
|
||||
int inherit_mask);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_delete_directory(struct ncp_conn *conn,
|
||||
int dir_handle, const char *path);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_rename_directory(struct ncp_conn *conn,
|
||||
int dir_handle,
|
||||
const char *old_path, const char *new_path);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_read(struct ncp_conn *conn, const char *file_id,
|
||||
off_t offset, size_t count, char *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_write(struct ncp_conn *conn, const char *file_id,
|
||||
off_t offset, size_t count, const char *source);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_copy_file(struct ncp_conn *conn,
|
||||
const char source_file[6],
|
||||
const char target_file[6],
|
||||
__u32 source_offset,
|
||||
__u32 target_offset,
|
||||
__u32 count,
|
||||
__u32 *copied_count);
|
||||
|
||||
long
|
||||
ncp_do_lookup(struct ncp_conn *conn,
|
||||
struct nw_info_struct *dir,
|
||||
char *path, /* may only be one component */
|
||||
struct nw_info_struct *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_modify_file_or_subdir_dos_info(struct ncp_conn *conn,
|
||||
struct nw_info_struct *file,
|
||||
__u32 info_mask,
|
||||
struct nw_modify_dos_info *info);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_del_file_or_subdir(struct ncp_conn *conn,
|
||||
struct nw_info_struct *dir, char *name);
|
||||
|
||||
|
||||
int
|
||||
long
|
||||
ncp_open_create_file_or_subdir(struct ncp_conn *conn,
|
||||
struct nw_info_struct *dir, char *name,
|
||||
int open_create_mode,
|
||||
@@ -255,29 +373,66 @@ ncp_open_create_file_or_subdir(struct ncp_conn *conn,
|
||||
int desired_acc_rights,
|
||||
struct nw_file_info *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_initialize_search(struct ncp_conn *conn,
|
||||
struct nw_info_struct *dir,
|
||||
struct nw_search_sequence *target);
|
||||
const struct nw_info_struct *dir,
|
||||
int namespace,
|
||||
struct ncp_search_seq *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_search_for_file_or_subdir(struct ncp_conn *conn,
|
||||
struct nw_search_sequence *seq,
|
||||
struct ncp_search_seq *seq,
|
||||
struct nw_info_struct *target);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_ren_or_mov_file_or_subdir(struct ncp_conn *conn,
|
||||
struct nw_info_struct *old_dir, char *old_name,
|
||||
struct nw_info_struct *new_dir, char *new_name);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_create_queue_job_and_file(struct ncp_conn *conn,
|
||||
__u32 queue_id,
|
||||
struct queue_job *job);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_close_file_and_start_job(struct ncp_conn *conn,
|
||||
__u32 queue_id,
|
||||
struct queue_job *job);
|
||||
|
||||
long
|
||||
ncp_attach_to_queue(struct ncp_conn *conn,
|
||||
__u32 queue_id);
|
||||
|
||||
long
|
||||
ncp_detach_from_queue(struct ncp_conn *conn,
|
||||
__u32 queue_id);
|
||||
|
||||
long
|
||||
ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type,
|
||||
struct queue_job *job);
|
||||
|
||||
long
|
||||
ncp_finish_servicing_job(struct ncp_conn *conn, __u32 queue_id,
|
||||
__u32 job_number, __u32 charge_info);
|
||||
|
||||
long
|
||||
ncp_abort_servicing_job(struct ncp_conn *conn, __u32 queue_id,
|
||||
__u32 job_number);
|
||||
|
||||
long
|
||||
ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]);
|
||||
|
||||
long
|
||||
ncp_dealloc_dir_handle(struct ncp_conn *conn, __u8 dir_handle);
|
||||
|
||||
#define NCP_ALLOC_PERMANENT (0x0000)
|
||||
#define NCP_ALLOC_TEMPORARY (0x0001)
|
||||
#define NCP_ALLOC_SPECIAL (0x0002)
|
||||
|
||||
long
|
||||
ncp_alloc_short_dir_handle(struct ncp_conn *conn,
|
||||
struct nw_info_struct *dir,
|
||||
__u16 alloc_mode,
|
||||
__u8 *target);
|
||||
|
||||
#endif /* _NCPLIB_H */
|
||||
|
||||
36
util/ncplib_err.et
Normal file
36
util/ncplib_err.et
Normal file
@@ -0,0 +1,36 @@
|
||||
error_table NCPL
|
||||
|
||||
ec NCPL_ET_NO_SERVER,
|
||||
"No server found"
|
||||
|
||||
ec NCPL_ET_HOST_UNKNOWN,
|
||||
"Server Unknown"
|
||||
|
||||
ec NCPL_ET_REQUEST_ERROR,
|
||||
"NCP Request returned error code"
|
||||
|
||||
ec NCPL_ET_NAMETOOLONG,
|
||||
"Name too long"
|
||||
|
||||
ec NCPL_ET_MSG_TOO_LONG,
|
||||
"Message too long"
|
||||
|
||||
ec NCPL_ET_NO_SPEC,
|
||||
"Could not find valid connection spec"
|
||||
|
||||
ec NCPL_ET_INVALID_MODE,
|
||||
"$HOME/.nwclient has invalid mode"
|
||||
|
||||
ec NCPL_ET_LOGIN_DENIED,
|
||||
"Login denied"
|
||||
|
||||
ec NCPL_ET_NO_INTERFACE,
|
||||
"No primary IPX interface found"
|
||||
|
||||
ec NCPL_ET_NO_PASSWORD,
|
||||
"Could not get password"
|
||||
|
||||
ec NCPL_ET_PWD_TOO_LONG,
|
||||
"Password too long"
|
||||
|
||||
end
|
||||
199
util/ncpmount.c
199
util/ncpmount.c
@@ -3,6 +3,16 @@
|
||||
*
|
||||
* Copyright (C) 1995 by Volker Lendecke
|
||||
*
|
||||
* 1/20/96 - Steven N. Hirsch (hirsch@emba.uvm.edu)
|
||||
*
|
||||
* If the ncpfs support is not loaded and we are using kerneld to
|
||||
* autoload modules, then we don't want to do it here. I added
|
||||
* a conditional which leaves out the test and load code.
|
||||
*
|
||||
* Even if we _do_ want ncpmount to load the module, passing a
|
||||
* fully-qualified pathname to modprobe causes it to bypass a
|
||||
* path search. This may lead to ncpfs.o not being found on
|
||||
* some systems.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -35,20 +45,21 @@ extern pid_t waitpid(pid_t, int *, int);
|
||||
#include <linux/ncp_fs.h>
|
||||
#include <linux/ncp_mount.h>
|
||||
#include "ncplib.h"
|
||||
#include "com_err.h"
|
||||
|
||||
static char *progname;
|
||||
static void str_upper(char *name);
|
||||
static void usage(void);
|
||||
static void help(void);
|
||||
|
||||
#ifndef HAVE_KERNELD
|
||||
|
||||
/* Returns 0 if the filesystem is in the kernel after this routine
|
||||
completes */
|
||||
static int
|
||||
load_ncpfs(void)
|
||||
{
|
||||
FILE *fver, *ffs;
|
||||
FILE *ffs;
|
||||
char s[1024];
|
||||
char modname[1024];
|
||||
char *p, *p1;
|
||||
pid_t pid;
|
||||
int status;
|
||||
@@ -81,33 +92,6 @@ load_ncpfs(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
fver = fopen("/proc/version", "r");
|
||||
if (fver == NULL)
|
||||
{
|
||||
perror("Error: \"/proc/version\" could not be read:");
|
||||
return -1;
|
||||
}
|
||||
fgets(s, 1024, fver);
|
||||
fclose(fver);
|
||||
p = strstr(s, "version ");
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
version_error:
|
||||
fprintf(stderr, "Error: Unable to determine the Linux version"
|
||||
"from \"/proc/version\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = strchr(p, ' ') + 1;
|
||||
p1 = strchr(p, ' ');
|
||||
if (p1 == NULL)
|
||||
{
|
||||
goto version_error;
|
||||
}
|
||||
strcpy(modname, "/lib/modules/");
|
||||
strncat(modname, p, p1 - p);
|
||||
strcat(modname, "/ncpfs.o");
|
||||
|
||||
/* system() function without signal handling, from Stevens */
|
||||
|
||||
@@ -118,7 +102,7 @@ load_ncpfs(void)
|
||||
else if (pid == 0)
|
||||
{
|
||||
/* child */
|
||||
execl("/sbin/insmod", "insmod", modname, NULL);
|
||||
execl("/sbin/modprobe", "modprobe", "ncpfs", NULL);
|
||||
_exit(127); /* execl error */
|
||||
}
|
||||
else
|
||||
@@ -136,6 +120,8 @@ load_ncpfs(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* HAVE_KERNELD */
|
||||
|
||||
/* Check whether user is allowed to mount on the specified mount point */
|
||||
static int
|
||||
mount_ok(struct stat *st)
|
||||
@@ -168,9 +154,11 @@ main(int argc, char *argv[])
|
||||
|
||||
int fd, result;
|
||||
struct sockaddr_ipx addr;
|
||||
struct sockaddr_ipx *server_addr;
|
||||
int addrlen;
|
||||
|
||||
int upcase_password;
|
||||
long err;
|
||||
|
||||
int um;
|
||||
unsigned int flags;
|
||||
@@ -178,6 +166,7 @@ main(int argc, char *argv[])
|
||||
char mount_point[MAXPATHLEN];
|
||||
struct mntent ment;
|
||||
FILE *mtab;
|
||||
char *tmp_mount;
|
||||
|
||||
char *server = NULL;
|
||||
char *user = NULL;
|
||||
@@ -186,13 +175,13 @@ main(int argc, char *argv[])
|
||||
|
||||
uid_t conn_uid = getuid();
|
||||
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn *conn;
|
||||
|
||||
int opt;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
memzero(data); memzero(spec); memzero(conn);
|
||||
memzero(data); memzero(spec);
|
||||
|
||||
if (geteuid() != 0)
|
||||
{
|
||||
@@ -206,10 +195,14 @@ main(int argc, char *argv[])
|
||||
umask(um);
|
||||
data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
|
||||
data.dir_mode = 0;
|
||||
data.flags |= NCP_MOUNT_SOFT;
|
||||
data.time_out = 60;
|
||||
data.retry_count = 5;
|
||||
|
||||
upcase_password = 1;
|
||||
|
||||
while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nh")) != EOF)
|
||||
while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nhvV:t:r:"))
|
||||
!= EOF)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
@@ -299,22 +292,39 @@ main(int argc, char *argv[])
|
||||
}
|
||||
password = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
if (strlen(optarg) >= sizeof(data.mounted_vol))
|
||||
{
|
||||
printf("Volume too long: %s\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(data.mounted_vol, optarg);
|
||||
break;
|
||||
case 'n':
|
||||
password = "";
|
||||
break;
|
||||
case 't':
|
||||
data.time_out = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
data.retry_count = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
help();
|
||||
exit(1);
|
||||
case 'v':
|
||||
fprintf(stderr, "ncpfs version %s\n", NCPFS_VERSION);
|
||||
exit(1);
|
||||
default:
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((spec = ncp_find_conn_spec(server, user, password, data.uid))
|
||||
if ((spec = ncp_find_conn_spec(server,user,password,1, data.uid, &err))
|
||||
== NULL)
|
||||
{
|
||||
fprintf(stderr, "Could not find valid server/user\n");
|
||||
com_err(progname, err, "in find_conn_spec");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -345,6 +355,7 @@ main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef HAVE_KERNELD
|
||||
/* Check if the ncpfs filesystem is in the kernel. If not, attempt
|
||||
* to load the ncpfs module */
|
||||
if (load_ncpfs() != 0)
|
||||
@@ -352,9 +363,11 @@ main(int argc, char *argv[])
|
||||
fprintf(stderr, "Error: Unable to load ncpfs, exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
data.version = NCP_MOUNT_VERSION;
|
||||
data.mounted_uid = conn_uid;
|
||||
memcpy(data.server_name, spec->server, sizeof(data.server_name));
|
||||
|
||||
if (data.dir_mode == 0)
|
||||
{
|
||||
@@ -367,32 +380,28 @@ main(int argc, char *argv[])
|
||||
data.dir_mode |= S_IXOTH;
|
||||
}
|
||||
|
||||
if (ncp_open(&conn, spec) != 0)
|
||||
if ((tmp_mount = ncp_find_permanent(spec)) != NULL)
|
||||
{
|
||||
fprintf(stderr, "could not connect to server %s: %s\n",
|
||||
server, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (conn.is_connected == CONN_PERMANENT)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"You already have mounted server %s\nas user "
|
||||
"%s\non mount point %s\n", spec->server, spec->user,
|
||||
conn.mount_point);
|
||||
ncp_close(&conn);
|
||||
tmp_mount);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
data.serv_addr = conn.i.addr;
|
||||
|
||||
ncp_close(&conn);
|
||||
if ((server_addr = ncp_find_fileserver(spec->server, &err)) == NULL)
|
||||
{
|
||||
com_err("ncpmount", err, "when trying to find %s",
|
||||
spec->server);
|
||||
exit(1);
|
||||
}
|
||||
data.serv_addr = *server_addr;
|
||||
|
||||
data.ncp_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
|
||||
if (data.ncp_fd == -1)
|
||||
{
|
||||
fprintf(stderr, "could not open ncp socket: %s\n",
|
||||
strerror(errno));
|
||||
com_err("ncpmount", err, "opening ncp_socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -436,12 +445,38 @@ main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if NCP_MOUNT_VERSION>1
|
||||
|
||||
data.message_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
|
||||
if (data.message_fd == -1)
|
||||
{
|
||||
fprintf(stderr, "could not open message socket: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
addr.sipx_port = htons(ntohs(addr.sipx_port) + 1);
|
||||
|
||||
if (bind(data.message_fd, (struct sockaddr *)&addr,sizeof(addr)) == -1)
|
||||
{
|
||||
fprintf(stderr, "bind(message_sock, ): %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strlen(mount_point) < sizeof(data.mount_point))
|
||||
{
|
||||
strcpy(data.mount_point, mount_point);
|
||||
}
|
||||
#endif
|
||||
|
||||
flags = MS_MGC_VAL;
|
||||
|
||||
data.time_out = 20;
|
||||
data.retry_count = 2;
|
||||
strcpy(mount_name, spec->server);
|
||||
strcat(mount_name, "/");
|
||||
strcat(mount_name, spec->user);
|
||||
|
||||
result = mount(NULL, mount_point, "ncpfs", flags, (char *)&data);
|
||||
result = mount(mount_name, mount_point, "ncpfs", flags, (char *)&data);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
@@ -449,19 +484,47 @@ main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( (ncp_open_mount(&conn, mount_point) != 0)
|
||||
|| (ncp_login_user(&conn, spec->user, spec->password) != 0))
|
||||
if ((conn = ncp_open_mount(mount_point, &err)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: login failed\n", strerror(errno));
|
||||
ncp_close(&conn);
|
||||
com_err("ncpmount", err, "attempt to open mount point");
|
||||
umount(mount_point);
|
||||
exit(1);
|
||||
}
|
||||
ncp_close(&conn);
|
||||
|
||||
strcpy(mount_name, spec->server);
|
||||
strcat(mount_name, "/");
|
||||
strcat(mount_name, spec->user);
|
||||
if ((err = ncp_login_user(conn, spec->user, spec->password)) != 0)
|
||||
{
|
||||
struct nw_property p;
|
||||
struct ncp_prop_login_control *l
|
||||
= (struct ncp_prop_login_control *)&p;
|
||||
|
||||
if (conn->completion != NCP_GRACE_PERIOD)
|
||||
{
|
||||
com_err("ncpmount", err, "in login");
|
||||
fprintf(stderr, "Login denied\n");
|
||||
ncp_close(conn);
|
||||
umount(mount_point);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Your password has expired\n");
|
||||
|
||||
if ((err = ncp_read_property_value(conn, NCP_BINDERY_USER,
|
||||
spec->user, 1,
|
||||
"LOGIN_CONTROL", &p)) == 0)
|
||||
{
|
||||
fprintf(stderr, "You have %d login attempts left\n",
|
||||
l->GraceLogins);
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = ioctl(conn->mount_fid, NCP_IOC_CONN_LOGGED_IN, NULL)) != 0)
|
||||
{
|
||||
com_err("ncpmount", err, "in logged_indication");
|
||||
ncp_close(conn);
|
||||
umount(mount_point);
|
||||
exit(1);
|
||||
}
|
||||
ncp_close(conn);
|
||||
|
||||
ment.mnt_fsname = mount_name;
|
||||
ment.mnt_dir = mount_point;
|
||||
@@ -504,15 +567,6 @@ main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
str_upper(char *name)
|
||||
{
|
||||
while (*name) {
|
||||
*name = toupper(*name);
|
||||
name = name + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
@@ -528,17 +582,22 @@ help(void)
|
||||
printf("\n"
|
||||
"-S server Server name to be used\n"
|
||||
"-U username Username sent to server\n"
|
||||
"-V volume Volume to mount, for NFS re-export\n"
|
||||
"-u uid uid the mounted files get\n"
|
||||
"-g gid gid the mounted files get\n"
|
||||
"-f mode permission the files get (octal notation)\n"
|
||||
"-d mode permission the dirs get (octal notation)\n"
|
||||
"-c uid uid to identify the connection to mount on\n"
|
||||
" Only makes sense for root\n"
|
||||
"-t time_out Waiting time (in 1/100s) to wait for\n"
|
||||
" an answer from the server. Default: 60\n"
|
||||
"-r retry_count Number of retry attempts. Default: 5\n"
|
||||
"-C Don't convert password to uppercase\n"
|
||||
"-P password Use this password\n"
|
||||
"-n Do not use any password\n"
|
||||
" If neither -P nor -n are given, you are\n"
|
||||
" asked for a password.\n"
|
||||
"-h print this help text\n"
|
||||
"-v print ncpfs version number\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
135
util/ncptest.c
135
util/ncptest.c
@@ -39,81 +39,88 @@ extern pid_t waitpid(pid_t, int *, int);
|
||||
|
||||
|
||||
void
|
||||
test_print(struct ncp_conn *conn)
|
||||
test_connlist(struct ncp_conn *conn)
|
||||
{
|
||||
struct ncp_bindery_object q;
|
||||
struct queue_job j;
|
||||
struct print_job_record pj;
|
||||
int written;
|
||||
|
||||
if (ncp_get_bindery_object_id(conn, NCP_BINDERY_PQUEUE,
|
||||
"Q_DJ500", &q) != 0) {
|
||||
printf("get oid error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&j, 0, sizeof(j));
|
||||
|
||||
j.j.TargetServerID = 0xffffffff; /* any server */
|
||||
/* at once */
|
||||
memset(&(j.j.TargetExecTime), 0xff, sizeof(j.j.TargetExecTime));
|
||||
j.j.JobType = htons(0);
|
||||
strcpy(j.j.JobTextDescription, "Test Job");
|
||||
|
||||
memset(&pj, 0, sizeof(pj));
|
||||
|
||||
pj.Version = 0;
|
||||
pj.TabSize = 8;
|
||||
pj.Copies = htons(1);
|
||||
pj.CtrlFlags = 0;
|
||||
pj.Lines = htons(66);
|
||||
pj.Rows = htons(80);
|
||||
strcpy(pj.FormName, "test");
|
||||
strcpy(pj.BannerName, "BannerName");
|
||||
strcpy(pj.FnameBanner, "BannerFile");
|
||||
strcpy(pj.FnameHeader, "HeaderName");
|
||||
strcpy(pj.Path, "");
|
||||
|
||||
memcpy(j.j.ClientRecordArea, &pj, sizeof(pj));
|
||||
|
||||
if (ncp_create_queue_job_and_file(conn, q.object_id, &j) != 0) {
|
||||
printf("create error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((written = ncp_write(conn, j.file_handle, 0, 15,
|
||||
"hallo, wie geht's?")) < 0) {
|
||||
printf("write error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ncp_close_file_and_start_job(conn, q.object_id, &j) != 0) {
|
||||
printf("close error\n");
|
||||
return;
|
||||
}
|
||||
__u8 conn_list[256] = {0,};
|
||||
int no;
|
||||
|
||||
ncp_get_connlist(conn, NCP_BINDERY_USER, "SUPERVISOR", &no,
|
||||
conn_list);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
main(void)
|
||||
test_send(struct ncp_conn *conn)
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn_spec *spec;
|
||||
__u8 conn_list[256] = {0,};
|
||||
int no;
|
||||
|
||||
if ((spec = ncp_find_conn_spec("NW311", "me", "", 0)) == NULL)
|
||||
if (ncp_get_connlist(conn, NCP_BINDERY_USER, "ME", &no,
|
||||
conn_list) != 0)
|
||||
{
|
||||
perror("could not find spec");
|
||||
exit(1);
|
||||
no = 0;
|
||||
}
|
||||
|
||||
if (ncp_open(&conn, NULL) != 0)
|
||||
if (no > 0)
|
||||
{
|
||||
perror("ncp_open");
|
||||
exit(1);
|
||||
ncp_send_broadcast(conn, no, conn_list, "Hallo");
|
||||
}
|
||||
|
||||
test_print(&conn);
|
||||
|
||||
ncp_close(&conn);
|
||||
return;
|
||||
}
|
||||
void
|
||||
test_create(struct ncp_conn *conn)
|
||||
{
|
||||
struct nw_info_struct sys;
|
||||
struct nw_info_struct me;
|
||||
__u8 dir_handle;
|
||||
struct ncp_file_info new_file;
|
||||
|
||||
if (ncp_do_lookup(conn, NULL, "SYS", &sys) != 0)
|
||||
{
|
||||
printf("lookup error\n");
|
||||
return;
|
||||
}
|
||||
if (ncp_do_lookup(conn, &sys, "ME", &me) != 0)
|
||||
{
|
||||
printf("lookup public error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ncp_alloc_short_dir_handle(conn, &me, NCP_ALLOC_TEMPORARY,
|
||||
&dir_handle) != 0)
|
||||
{
|
||||
printf("alloc_dir_handle error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ncp_create_file(conn, dir_handle, "BLUB.TXT", 0,
|
||||
&new_file) != 0)
|
||||
{
|
||||
printf("create error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ncp_dealloc_dir_handle(conn, dir_handle) != 0)
|
||||
{
|
||||
printf("dealloc error\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ncp_conn *conn;
|
||||
long err;
|
||||
|
||||
if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
|
||||
{
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
return 1;
|
||||
}
|
||||
|
||||
test_send(conn);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -178,20 +178,3 @@ main(int argc, char *argv[])
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-brace-imaginary-offset: 0
|
||||
* c-brace-offset: -8
|
||||
* c-argdecl-indent: 8
|
||||
* c-label-offset: -8
|
||||
* c-continued-statement-offset: 8
|
||||
* c-continued-brace-offset: 0
|
||||
* End:
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* nwprint.c
|
||||
* nprint.c
|
||||
*
|
||||
* Send data to a NetWare print queue.
|
||||
*
|
||||
@@ -20,13 +20,12 @@
|
||||
static char *progname;
|
||||
static void
|
||||
usage(void);
|
||||
static void
|
||||
str_upper(char *name);
|
||||
static void help(void);
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn *conn;
|
||||
|
||||
char default_queue[] = "*";
|
||||
char *queue = default_queue;
|
||||
@@ -43,14 +42,22 @@ main(int argc, char *argv[])
|
||||
|
||||
char *file_name;
|
||||
int file;
|
||||
long err;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
memzero(j); memzero(pj); memzero(q); memzero(conn);
|
||||
memzero(j); memzero(pj); memzero(q);
|
||||
|
||||
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
|
||||
if ( (argc == 2)
|
||||
&& (strcmp(argv[1], "-h") == 0))
|
||||
{
|
||||
perror("Could not open connection");
|
||||
help();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
|
||||
{
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -71,9 +78,13 @@ main(int argc, char *argv[])
|
||||
pj.Rows = htons(80);
|
||||
strcpy(pj.FnameHeader, "stdin");
|
||||
|
||||
while ((opt = getopt(argc, argv, "q:d:p:b:f:l:r:c:t:F:TN"))!=EOF)
|
||||
while ((opt = getopt(argc, argv, "hq:d:p:b:f:l:r:c:t:F:TN"))!=EOF)
|
||||
{
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help();
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
case 'p':
|
||||
/* Path */
|
||||
pj.CtrlFlags |= PRINT_BANNER;
|
||||
@@ -181,6 +192,7 @@ main(int argc, char *argv[])
|
||||
{
|
||||
printf("queue name too long: %s\n",
|
||||
optarg);
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
queue = optarg;
|
||||
@@ -201,6 +213,7 @@ main(int argc, char *argv[])
|
||||
|
||||
default:
|
||||
usage();
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -208,6 +221,7 @@ main(int argc, char *argv[])
|
||||
if (optind != argc-1)
|
||||
{
|
||||
usage();
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -223,6 +237,7 @@ main(int argc, char *argv[])
|
||||
if (file < 0)
|
||||
{
|
||||
perror("could not open file");
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -254,17 +269,19 @@ main(int argc, char *argv[])
|
||||
|
||||
str_upper(queue);
|
||||
|
||||
if (ncp_scan_bindery_object(&conn, 0xffffffff, NCP_BINDERY_PQUEUE,
|
||||
if (ncp_scan_bindery_object(conn, 0xffffffff, NCP_BINDERY_PQUEUE,
|
||||
queue, &q) != 0)
|
||||
{
|
||||
printf("could not find queue %s\n", queue);
|
||||
return;
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ncp_create_queue_job_and_file(&conn, q.object_id, &j) != 0)
|
||||
if (ncp_create_queue_job_and_file(conn, q.object_id, &j) != 0)
|
||||
{
|
||||
printf("create error\n");
|
||||
return;
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
written = 0;
|
||||
@@ -276,7 +293,7 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
if (ncp_write(&conn, j.file_handle,
|
||||
if (ncp_write(conn, j.file_handle,
|
||||
written, read_this_time, buf) < read_this_time)
|
||||
{
|
||||
break;
|
||||
@@ -287,26 +304,44 @@ main(int argc, char *argv[])
|
||||
|
||||
close(file);
|
||||
|
||||
if (ncp_close_file_and_start_job(&conn, q.object_id, &j) != 0) {
|
||||
if (ncp_close_file_and_start_job(conn, q.object_id, &j) != 0) {
|
||||
printf("close error\n");
|
||||
ncp_close(conn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [options] file\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
str_upper(char *name)
|
||||
help(void)
|
||||
{
|
||||
while (*name) {
|
||||
*name = toupper(*name);
|
||||
name = name + 1;
|
||||
}
|
||||
printf("\n");
|
||||
printf("usage: %s [options] file\n", progname);
|
||||
printf("\n"
|
||||
"-S server Server name to be used\n"
|
||||
"-U username Username sent to server\n"
|
||||
"-P password Use this password\n"
|
||||
"-n Do not use any password\n"
|
||||
"-C Don't convert password to uppercase\n"
|
||||
"-q queue name Name of the printing queue to use\n"
|
||||
"-d job desc Job description\n"
|
||||
"-p path name Path name to appear on banner\n"
|
||||
"-b bannername Banner name (up to 12 chars)\n"
|
||||
"-f filename Filename to appear on banner\n"
|
||||
"-l lines Number of lines per page\n"
|
||||
"-r rows Number of rows per page\n"
|
||||
"-t tab Number of spaces per tab\n"
|
||||
"-T Print server tab expantion\n"
|
||||
"-N Surpress print server form feeds\n"
|
||||
"-F form # Form number to print on\n"
|
||||
"-h print this help text\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
65
util/nsend.c
Normal file
65
util/nsend.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* nsend.c
|
||||
*
|
||||
* Send Messages to users
|
||||
*
|
||||
* Copyright (C) 1996 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include "ncplib.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct ncp_conn *conn;
|
||||
__u8 conn_list[256] = {0,};
|
||||
int no_conn;
|
||||
|
||||
char *message = NULL;
|
||||
char *user = NULL;
|
||||
long err;
|
||||
|
||||
if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
|
||||
{
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [options] user message\n", argv[0]);
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
user = argv[1];
|
||||
message = argv[2];
|
||||
|
||||
if ((err = ncp_get_connlist(conn, NCP_BINDERY_USER, user, &no_conn,
|
||||
conn_list)) != 0)
|
||||
{
|
||||
com_err(argv[0], err, "in get_connlist");
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (no_conn == 0)
|
||||
{
|
||||
fprintf(stderr, "No connection found for %s\n", user);
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((err = ncp_send_broadcast(conn, no_conn, conn_list, message)) != 0)
|
||||
{
|
||||
com_err(argv[0], err, "in send_broadcast");
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
79
util/nwfsinfo.c
Normal file
79
util/nwfsinfo.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* nwfsinfo.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;
|
||||
long err;
|
||||
|
||||
if ((conn = ncp_initialize(&argc, argv, 0, &err)) == NULL)
|
||||
{
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
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;
|
||||
}
|
||||
62
util/nwlsobj.c
Normal file
62
util/nwlsobj.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* nwlsobj.c
|
||||
*
|
||||
* List bindery objects
|
||||
*
|
||||
* Copyright (C) 1996 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include "ncplib.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct ncp_conn *conn;
|
||||
struct ncp_bindery_object o;
|
||||
int found = 0;
|
||||
|
||||
char default_pattern[] = "*";
|
||||
char *pattern = default_pattern;
|
||||
char *p;
|
||||
long err;
|
||||
|
||||
if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
|
||||
{
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [options]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
pattern = argv[1];
|
||||
}
|
||||
|
||||
for (p = pattern; *p != '\0'; p++)
|
||||
{
|
||||
*p = toupper(*p);
|
||||
}
|
||||
|
||||
o.object_id = 0xffffffff;
|
||||
|
||||
while (ncp_scan_bindery_object(conn, o.object_id,
|
||||
0xffff, pattern, &o) == 0)
|
||||
{
|
||||
found = 1;
|
||||
printf("%s %08X %04X\n",
|
||||
o.object_name, (unsigned int)o.object_id,
|
||||
(unsigned int)o.object_type);
|
||||
}
|
||||
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user