Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cb56005ea | ||
|
|
0520c1d2f7 | ||
|
|
d5ac4601b1 | ||
|
|
1fa124bd7c |
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.
53
Changes
53
Changes
@@ -1,5 +1,56 @@
|
||||
I only began this file with ncpfs-0.12. If you're interested in older
|
||||
versions, you can find them on linux01.gwdg.de:/pub/ncpfs/old.
|
||||
versions, you can find them on ftp.gwdg.de:/pub/linux/misc/ncpfs/old.
|
||||
|
||||
ncpfs-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 ndt1001@chu.cam.ac.uk (Neil Turton) 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
|
||||
|
||||
|
||||
41
FAQ
Normal file
41
FAQ
Normal file
@@ -0,0 +1,41 @@
|
||||
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: 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.
|
||||
13
Makefile
13
Makefile
@@ -2,10 +2,11 @@
|
||||
# Makefile for the linux ncp-filesystem routines.
|
||||
#
|
||||
|
||||
VERSION = 0.16
|
||||
VERSION = 0.20
|
||||
TOPDIR = $(shell pwd)
|
||||
|
||||
BINDIR = /usr/local/bin
|
||||
SBINDIR = /sbin
|
||||
INTERM_BINDIR = $(TOPDIR)/bin
|
||||
SUBDIRS = util ipx-1.0 man
|
||||
|
||||
@@ -15,14 +16,14 @@ SUBDIRS = util ipx-1.0 man
|
||||
# the following lines. You have to recompile your kernel
|
||||
# and say 'y' when 'make config' asks you for IPX and ncpfs.
|
||||
#
|
||||
#SUBDIRS += kernel-1.2/src
|
||||
#INCLUDES = -I$(TOPDIR)/kernel-1.2
|
||||
SUBDIRS += kernel-1.2/src
|
||||
INCLUDES = -I$(TOPDIR)/kernel-1.2
|
||||
|
||||
# If you are using kerneld to autoload ncp support,
|
||||
# uncomment this (kerneld is in linux since about 1.3.57):
|
||||
# KERNELD = -DHAVE_KERNELD
|
||||
#KERNELD = -DHAVE_KERNELD
|
||||
|
||||
export INCLUDES BINDIR INTERM_BINDIR KERNELD VERSION
|
||||
export INCLUDES BINDIR INTERM_BINDIR SBINDIR KERNELD VERSION
|
||||
|
||||
all:
|
||||
for i in $(SUBDIRS); do make -C $$i; done
|
||||
@@ -42,7 +43,7 @@ clean:
|
||||
|
||||
mrproper: clean
|
||||
rm -fr $(INTERM_BINDIR)/* ncpfs.tgz
|
||||
make -C util realclean
|
||||
make -C util mrproper
|
||||
|
||||
modules: ncpfs.o
|
||||
|
||||
|
||||
55
README
55
README
@@ -12,10 +12,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
|
||||
@@ -23,12 +22,31 @@ 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
|
||||
With Kernel 1.3.71 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.
|
||||
|
||||
|
||||
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
|
||||
|
||||
Please note that your IPX system has to be configured correctly. If
|
||||
@@ -78,6 +96,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 :-)
|
||||
|
||||
@@ -87,27 +107,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
|
||||
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>
|
||||
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;
|
||||
}
|
||||
}
|
||||
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.
|
||||
@@ -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? */
|
||||
|
||||
@@ -47,7 +47,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 +102,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 +129,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,6 +194,7 @@ 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;
|
||||
@@ -156,7 +209,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
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 +223,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 +233,11 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if (!ncp_conn_valid(server))
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (c_entry == NULL)
|
||||
{
|
||||
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
|
||||
@@ -193,8 +251,9 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -204,7 +263,8 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -212,7 +272,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
|
||||
}
|
||||
|
||||
if (inode->i_ino == c_ino)
|
||||
if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
|
||||
{
|
||||
for (i = 0; i < c_size; i++)
|
||||
{
|
||||
@@ -234,7 +294,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
{
|
||||
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);
|
||||
@@ -251,6 +311,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
c_dev = 0;
|
||||
c_ino = 0;
|
||||
return result;
|
||||
}
|
||||
@@ -258,6 +319,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
if (result > 0)
|
||||
{
|
||||
c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
|
||||
c_dev = inode->i_dev;
|
||||
c_ino = inode->i_ino;
|
||||
c_size = result;
|
||||
entry = c_entry;
|
||||
@@ -282,24 +344,35 @@ 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;
|
||||
}
|
||||
@@ -353,12 +426,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 +511,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 +592,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 +643,7 @@ 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));
|
||||
@@ -581,6 +658,25 @@ ncp_init_root(struct ncp_server *server)
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_conn_logged_in(struct ncp_server *server)
|
||||
{
|
||||
if (server->m.mounted_vol[0] == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
str_upper(server->m.mounted_vol);
|
||||
if (ncp_lookup_volume(server, server->m.mounted_vol,
|
||||
&(server->root.finfo.i)) != 0)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
str_lower(server->root.finfo.i.entryName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ncp_free_all_inodes(struct ncp_server *server)
|
||||
{
|
||||
@@ -611,7 +707,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);
|
||||
@@ -626,7 +722,13 @@ ncp_find_inode(struct inode *dir, const char *name)
|
||||
{
|
||||
if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
|
||||
&& (result->dir->finfo.i.volNumber == dir_info->volNumber)
|
||||
&& (strcmp(result->finfo.i.entryName, name) == 0))
|
||||
&& (strcmp(result->finfo.i.entryName, name) == 0)
|
||||
/* The root dir is never looked up using this
|
||||
* routine. Without the following test a root
|
||||
* directory 'sys' in a volume named 'sys' could
|
||||
* never be looked up, because
|
||||
* server->root->dir==server->root. */
|
||||
&& (result != &(server->root)))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@@ -658,9 +760,14 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
|
||||
|
||||
server = NCP_SERVER(dir);
|
||||
if (!ncp_conn_valid(server))
|
||||
{
|
||||
iput(dir);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
|
||||
|
||||
/* Fast cheat for . */
|
||||
if (len == 0 || (len == 1 && __name[0] == '.'))
|
||||
@@ -679,7 +786,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)
|
||||
{
|
||||
@@ -694,7 +801,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
memcpy(name, __name, len);
|
||||
name[len] = 0;
|
||||
|
||||
result_info = ncp_find_inode(dir, name);
|
||||
result_info = ncp_find_dir_inode(dir, name);
|
||||
|
||||
if (result_info != 0)
|
||||
{
|
||||
@@ -706,7 +813,7 @@ 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));
|
||||
iput(dir);
|
||||
|
||||
if (*result == NULL)
|
||||
@@ -722,7 +829,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
|
||||
found_in_cache = 0;
|
||||
|
||||
if (dir->i_ino == c_ino)
|
||||
if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
|
||||
{
|
||||
int first = c_last_returned_index;
|
||||
int i;
|
||||
@@ -747,15 +854,24 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
|
||||
if (found_in_cache == 0)
|
||||
{
|
||||
int res;
|
||||
str_upper(name);
|
||||
|
||||
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
|
||||
NCP_ISTRUCT(dir)->entryName, name);
|
||||
|
||||
if (ncp_do_lookup(server,
|
||||
dir->i_ino == (int)&(NCP_SERVER(dir)->root)
|
||||
? NULL : NCP_ISTRUCT(dir),
|
||||
name, &(finfo.i)) != 0)
|
||||
if (ncp_is_server_root(dir))
|
||||
{
|
||||
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)
|
||||
{
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
@@ -790,6 +906,11 @@ 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';
|
||||
@@ -806,7 +927,7 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
ncp_invalid_dir_cache(dir->i_ino);
|
||||
ncp_invalid_dir_cache(dir);
|
||||
|
||||
str_lower(finfo.i.entryName);
|
||||
finfo.access = O_RDWR;
|
||||
@@ -847,6 +968,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,
|
||||
@@ -858,7 +984,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);
|
||||
@@ -877,8 +1003,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
|
||||
@@ -892,7 +1024,7 @@ 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
|
||||
{
|
||||
@@ -915,8 +1047,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
|
||||
@@ -929,7 +1067,7 @@ 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
|
||||
{
|
||||
@@ -955,6 +1093,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");
|
||||
@@ -962,8 +1106,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;
|
||||
@@ -983,8 +1127,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
|
||||
{
|
||||
|
||||
@@ -99,6 +99,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 +182,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 +247,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;
|
||||
}
|
||||
@@ -176,7 +151,7 @@ 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);
|
||||
@@ -204,6 +179,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 +230,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 +280,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 +371,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 +463,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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -401,9 +401,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 +490,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
|
||||
|
||||
|
||||
|
||||
|
||||
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.
|
||||
@@ -34,6 +34,15 @@ ncpmount \- mount all volumes of a specified Novell fileserver.
|
||||
.B -d
|
||||
.I dir mode
|
||||
] [
|
||||
.B -V
|
||||
.I volume
|
||||
] [
|
||||
.B -t
|
||||
.I time_out
|
||||
] [
|
||||
.B -r
|
||||
.I retry_count
|
||||
] [
|
||||
.B -v
|
||||
]
|
||||
mount-point
|
||||
@@ -188,6 +197,66 @@ 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
|
||||
@@ -212,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
|
||||
|
||||
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>
|
||||
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)
|
||||
@@ -1,7 +1,7 @@
|
||||
Begin3
|
||||
Title: ncpfs
|
||||
Version: 0.16
|
||||
Entered-date: 21. February 1996
|
||||
Version: 0.20
|
||||
Entered-date: 25. March 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
|
||||
@@ -11,9 +11,9 @@ Description: With ncpfs you can mount volumes of your netware
|
||||
Keywords: filesystem ncp novell netware printing
|
||||
Author: lendecke@namu01.gwdg.de (Volker Lendecke)
|
||||
Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke)
|
||||
Primary-site: linux01.gwdg.de:/pub/ncpfs
|
||||
Primary-site: ftp.gwdg.de:/pub/linux/misc/ncpfs
|
||||
Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/
|
||||
~73k ncpfs-0.16.tgz
|
||||
~ 1k ncpfs-0.16.lsm
|
||||
~111k ncpfs-0.20.tgz
|
||||
~ 1k ncpfs-0.20.lsm
|
||||
Copying-policy: GPL
|
||||
End
|
||||
@@ -2,9 +2,12 @@
|
||||
# Makefile for the linux ncp-filesystem routines.
|
||||
#
|
||||
|
||||
UTIL_EXECS = ncpmount ncpumount nprint slist pqlist fsinfo pserver
|
||||
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
|
||||
USERUTILS = slist pqlist nwfsinfo pserver nprint nsend ncopy
|
||||
UIDUTILS = ncpmount ncpumount
|
||||
SBINUTILS = nwmsg
|
||||
|
||||
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)\"
|
||||
@@ -14,28 +17,49 @@ 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.
|
||||
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
1091
util/ncplib.c
1091
util/ncplib.c
File diff suppressed because it is too large
Load Diff
168
util/ncplib.h
168
util/ncplib.h
@@ -17,6 +17,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "ipxlib.h"
|
||||
#include "com_err.h"
|
||||
|
||||
#ifndef memzero
|
||||
#include <string.h>
|
||||
@@ -83,41 +84,37 @@ struct ncp_search_seq {
|
||||
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. */
|
||||
int
|
||||
ncp_initialize_as(struct ncp_conn *conn,
|
||||
int *argc, char **argv,
|
||||
int login_necessary, int login_type);
|
||||
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
|
||||
@@ -140,141 +137,178 @@ 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);
|
||||
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);
|
||||
|
||||
int
|
||||
ncp_get_connlist(struct ncp_conn *conn, __u32 last_id,
|
||||
long
|
||||
ncp_get_connlist(struct ncp_conn *conn,
|
||||
__u16 object_type, const char *object_name,
|
||||
int *returned_no, __u16 conn_numbers[256]);
|
||||
int *returned_no, __u8 conn_numbers[256]);
|
||||
|
||||
int
|
||||
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_scan_bindery_object(struct ncp_conn *conn,
|
||||
__u32 last_id, __u16 object_type, char *search_string,
|
||||
struct ncp_bindery_object *target);
|
||||
int
|
||||
|
||||
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_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,
|
||||
@@ -282,63 +316,63 @@ 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,
|
||||
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 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);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_attach_to_queue(struct ncp_conn *conn,
|
||||
__u32 queue_id);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_detach_from_queue(struct ncp_conn *conn,
|
||||
__u32 queue_id);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type,
|
||||
struct queue_job *job);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_finish_servicing_job(struct ncp_conn *conn, __u32 queue_id,
|
||||
__u32 job_number, __u32 charge_info);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_abort_servicing_job(struct ncp_conn *conn, __u32 queue_id,
|
||||
__u32 job_number);
|
||||
|
||||
int
|
||||
long
|
||||
ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]);
|
||||
|
||||
int
|
||||
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)
|
||||
|
||||
int
|
||||
long
|
||||
ncp_alloc_short_dir_handle(struct ncp_conn *conn,
|
||||
struct nw_info_struct *dir,
|
||||
__u16 alloc_mode,
|
||||
|
||||
21
util/ncplib_err.et
Normal file
21
util/ncplib_err.et
Normal file
@@ -0,0 +1,21 @@
|
||||
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"
|
||||
|
||||
end
|
||||
111
util/ncpmount.c
111
util/ncpmount.c
@@ -45,6 +45,7 @@ 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 usage(void);
|
||||
@@ -153,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;
|
||||
@@ -163,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;
|
||||
@@ -171,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)
|
||||
{
|
||||
@@ -192,10 +196,13 @@ main(int argc, char *argv[])
|
||||
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:nhv")) != EOF)
|
||||
while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nhvV:t:r:"))
|
||||
!= EOF)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
@@ -285,9 +292,23 @@ 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);
|
||||
@@ -300,10 +321,10 @@ main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if ((spec = ncp_find_conn_spec(server, user, password, data.uid))
|
||||
if ((spec = ncp_find_conn_spec(server, user, password, data.uid, &err))
|
||||
== NULL)
|
||||
{
|
||||
fprintf(stderr, "Could not find valid server/user\n");
|
||||
com_err(progname, err, "in find_conn_spec");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -346,6 +367,7 @@ main(int argc, char *argv[])
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -358,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);
|
||||
}
|
||||
|
||||
@@ -454,10 +472,11 @@ main(int argc, char *argv[])
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -465,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;
|
||||
@@ -535,12 +582,16 @@ 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"
|
||||
|
||||
133
util/ncptest.c
133
util/ncptest.c
@@ -38,115 +38,35 @@ extern pid_t waitpid(pid_t, int *, int);
|
||||
#include "ncplib.h"
|
||||
|
||||
|
||||
void
|
||||
test_print(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;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
test_ls(struct ncp_conn *server)
|
||||
{
|
||||
struct nw_info_struct sys;
|
||||
struct nw_info_struct public;
|
||||
struct ncp_search_seq seq;
|
||||
struct nw_info_struct found;
|
||||
int res;
|
||||
|
||||
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0)
|
||||
{
|
||||
printf("lookup error\n");
|
||||
return;
|
||||
}
|
||||
if (ncp_do_lookup(server, &sys, "PUBLIC", &public) != 0)
|
||||
{
|
||||
printf("lookup public error\n");
|
||||
return;
|
||||
}
|
||||
if (ncp_initialize_search(server, &public, 4, &seq) != 0)
|
||||
{
|
||||
printf("init error\n");
|
||||
return;
|
||||
}
|
||||
while ((res=ncp_search_for_file_or_subdir(server,&seq,&found)) == 0)
|
||||
{
|
||||
printf("found %s: %s\n",
|
||||
(found.attributes & aDIR) ? "dir " : "file",
|
||||
found.entryName);
|
||||
}
|
||||
|
||||
if (res == 0xfe)
|
||||
{
|
||||
printf("result: no more files\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("other error: %x\n", res);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
test_connlist(struct ncp_conn *conn)
|
||||
{
|
||||
__u16 conn_list[256];
|
||||
__u8 conn_list[256] = {0,};
|
||||
int no;
|
||||
|
||||
ncp_get_connlist(conn, 0, NCP_BINDERY_USER, "*", &no, conn_list);
|
||||
ncp_get_connlist(conn, NCP_BINDERY_USER, "SUPERVISOR", &no,
|
||||
conn_list);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
test_send(struct ncp_conn *conn)
|
||||
{
|
||||
__u8 conn_list[256] = {0,};
|
||||
int no;
|
||||
|
||||
if (ncp_get_connlist(conn, NCP_BINDERY_USER, "ME", &no,
|
||||
conn_list) != 0)
|
||||
{
|
||||
no = 0;
|
||||
}
|
||||
|
||||
if (no > 0)
|
||||
{
|
||||
ncp_send_broadcast(conn, no, conn_list, "Hallo");
|
||||
}
|
||||
return;
|
||||
}
|
||||
void
|
||||
test_create(struct ncp_conn *conn)
|
||||
{
|
||||
@@ -191,15 +111,16 @@ test_create(struct ncp_conn *conn)
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn *conn;
|
||||
long err;
|
||||
|
||||
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
|
||||
if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
|
||||
{
|
||||
perror("ncp_initialize");
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
return 1;
|
||||
}
|
||||
|
||||
test_create(&conn);
|
||||
ncp_close(&conn);
|
||||
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.
|
||||
*
|
||||
@@ -25,7 +25,7 @@ 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;
|
||||
@@ -42,10 +42,11 @@ 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 ( (argc == 2)
|
||||
&& (strcmp(argv[1], "-h") == 0))
|
||||
@@ -54,9 +55,9 @@ main(int argc, char *argv[])
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
|
||||
if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
|
||||
{
|
||||
perror("Could not open connection");
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ main(int argc, char *argv[])
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help();
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
case 'p':
|
||||
/* Path */
|
||||
@@ -191,6 +192,7 @@ main(int argc, char *argv[])
|
||||
{
|
||||
printf("queue name too long: %s\n",
|
||||
optarg);
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
queue = optarg;
|
||||
@@ -211,6 +213,7 @@ main(int argc, char *argv[])
|
||||
|
||||
default:
|
||||
usage();
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -218,6 +221,7 @@ main(int argc, char *argv[])
|
||||
if (optind != argc-1)
|
||||
{
|
||||
usage();
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -233,6 +237,7 @@ main(int argc, char *argv[])
|
||||
if (file < 0)
|
||||
{
|
||||
perror("could not open file");
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -264,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;
|
||||
@@ -286,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;
|
||||
@@ -297,19 +304,20 @@ 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
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* fsinfo.c
|
||||
* nwfsinfo.c
|
||||
*
|
||||
* Print the info strings of a server, maybe sometime more.
|
||||
*
|
||||
@@ -14,12 +14,13 @@
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn *conn;
|
||||
int opt;
|
||||
long err;
|
||||
|
||||
if (ncp_initialize(&conn, &argc, argv, 0) != 0)
|
||||
if ((conn = ncp_initialize(&argc, argv, 0, &err)) == NULL)
|
||||
{
|
||||
perror("Could not open connection");
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -32,12 +33,12 @@ main(int argc, char **argv)
|
||||
char strings[512];
|
||||
char *s;
|
||||
|
||||
if (ncp_get_file_server_description_strings(&conn,
|
||||
if (ncp_get_file_server_description_strings(conn,
|
||||
strings)
|
||||
!= 0)
|
||||
{
|
||||
perror("could not get strings");
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -57,10 +58,10 @@ main(int argc, char **argv)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
if (ncp_get_file_server_time(&conn, &t) != 0)
|
||||
if (ncp_get_file_server_time(conn, &t) != 0)
|
||||
{
|
||||
perror("could not get server time");
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -73,6 +74,6 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
ncp_close(&conn);
|
||||
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;
|
||||
}
|
||||
219
util/nwmsg.c
Normal file
219
util/nwmsg.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* nwmsg.c
|
||||
*
|
||||
* Fetch NetWare broadcast messages and write to the user
|
||||
*
|
||||
* Copyright (C) 1996 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <paths.h>
|
||||
#include <utmp.h>
|
||||
#include <mntent.h>
|
||||
#include "ncplib.h"
|
||||
|
||||
static int search_utmp(char *user, char *tty);
|
||||
|
||||
static char *progname;
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ncp_conn *conn;
|
||||
char message[256];
|
||||
struct ncp_fs_info info;
|
||||
struct passwd *pwd;
|
||||
char tty[256];
|
||||
char tty_path[256];
|
||||
FILE *tty_file;
|
||||
FILE *mtab;
|
||||
struct mntent *mnt;
|
||||
long err;
|
||||
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
openlog("nwmsg", LOG_PID, LOG_LPR);
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "usage: %s mount-point\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((conn = ncp_open_mount(argv[1], &err)) == NULL)
|
||||
{
|
||||
com_err(progname, err, "in ncp_open_mount");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ncp_get_broadcast_message(conn, message) != 0)
|
||||
{
|
||||
fprintf(stderr, "%s: could not get broadcast message\n",
|
||||
progname);
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strlen(message) == 0)
|
||||
{
|
||||
syslog(LOG_DEBUG, "no message");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
syslog(LOG_DEBUG, "message: %s", message);
|
||||
#endif
|
||||
|
||||
info.version = NCP_GET_FS_INFO_VERSION;
|
||||
if (ioctl(conn->mount_fid, NCP_IOC_GET_FS_INFO, &info) < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: could not ioctl on connection: %s\n",
|
||||
progname, strerror(errno));
|
||||
ncp_close(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ncp_close(conn);
|
||||
|
||||
if ((pwd = getpwuid(info.mounted_uid)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: user %d not known\n",
|
||||
progname, info.mounted_uid);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((mtab = fopen(MOUNTED, "r")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: can't open %s\n",
|
||||
progname, MOUNTED);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((mnt = getmntent(mtab)) != NULL)
|
||||
{
|
||||
if (strcmp(mnt->mnt_dir, conn->mount_point) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mnt == NULL)
|
||||
{
|
||||
syslog(LOG_DEBUG, "cannot find mtab entry\n");
|
||||
}
|
||||
|
||||
if (search_utmp(pwd->pw_name, tty) != 0)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sprintf(tty_path, "/dev/%s", tty);
|
||||
if ((tty_file = fopen(tty_path, "w")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: cannot open %s: %s\n",
|
||||
progname, tty_path, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(tty_file, "\r\n\007\007\007Message from NetWare Server: %s\n",
|
||||
mnt->mnt_fsname);
|
||||
fprintf(tty_file, "%s\n", message);
|
||||
fclose(tty_file);
|
||||
fclose(mtab);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The following routines have been taken from util-linux-2.5's write.c */
|
||||
|
||||
/*
|
||||
* term_chk - check that a terminal exists, and get the message bit
|
||||
* and the access time
|
||||
*/
|
||||
static int
|
||||
term_chk(char *tty, int *msgsokP, time_t *atimeP, int *showerror)
|
||||
{
|
||||
struct stat s;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
(void)sprintf(path, "/dev/%s", tty);
|
||||
if (stat(path, &s) < 0) {
|
||||
if (showerror)
|
||||
(void)fprintf(stderr,
|
||||
"write: %s: %s\n", path, strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
*msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
|
||||
*atimeP = s.st_atime;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* search_utmp - search utmp for the "best" terminal to write to
|
||||
*
|
||||
* Ignores terminals with messages disabled, and of the rest, returns
|
||||
* the one with the most recent access time. Returns as value the number
|
||||
* of the user's terminals with messages enabled, or -1 if the user is
|
||||
* not logged in at all.
|
||||
*
|
||||
* Special case for writing to yourself - ignore the terminal you're
|
||||
* writing from, unless that's the only terminal with messages enabled.
|
||||
*/
|
||||
static int
|
||||
search_utmp(char *user, char *tty)
|
||||
{
|
||||
struct utmp u;
|
||||
time_t bestatime, atime;
|
||||
int ufd, nloggedttys, nttys, msgsok, user_is_me;
|
||||
|
||||
char atty[sizeof(u.ut_line) + 1];
|
||||
|
||||
if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
|
||||
perror("utmp");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nloggedttys = nttys = 0;
|
||||
bestatime = 0;
|
||||
user_is_me = 0;
|
||||
while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
|
||||
if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
|
||||
++nloggedttys;
|
||||
|
||||
(void)strncpy(atty, u.ut_line, sizeof(u.ut_line));
|
||||
atty[sizeof(u.ut_line)] = '\0';
|
||||
|
||||
if (term_chk(atty, &msgsok, &atime, 0))
|
||||
continue; /* bad term? skip */
|
||||
if (!msgsok)
|
||||
continue; /* skip ttys with msgs off */
|
||||
|
||||
if (u.ut_type != USER_PROCESS)
|
||||
continue; /* it's not a valid entry */
|
||||
|
||||
++nttys;
|
||||
if (atime > bestatime) {
|
||||
bestatime = atime;
|
||||
(void)strcpy(tty, atty);
|
||||
}
|
||||
}
|
||||
|
||||
(void)close(ufd);
|
||||
if (nloggedttys == 0) {
|
||||
(void)fprintf(stderr, "write: %s is not logged in\n", user);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -15,17 +15,18 @@
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn *conn;
|
||||
struct ncp_bindery_object q;
|
||||
int found = 0;
|
||||
|
||||
char default_pattern[] = "*";
|
||||
char *pattern = default_pattern;
|
||||
char *p;
|
||||
long err;
|
||||
|
||||
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
|
||||
if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
|
||||
{
|
||||
perror("Could not open connection");
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -47,7 +48,7 @@ main(int argc, char **argv)
|
||||
|
||||
if (isatty(1))
|
||||
{
|
||||
printf("\nServer: %s\n", conn.server);
|
||||
printf("\nServer: %s\n", conn->server);
|
||||
printf("%-52s%-10s\n"
|
||||
"-----------------------------------------------"
|
||||
"-------------\n",
|
||||
@@ -57,12 +58,12 @@ main(int argc, char **argv)
|
||||
|
||||
q.object_id = 0xffffffff;
|
||||
|
||||
while (ncp_scan_bindery_object(&conn, q.object_id,
|
||||
NCP_BINDERY_PQUEUE, "*", &q) == 0)
|
||||
while (ncp_scan_bindery_object(conn, q.object_id,
|
||||
NCP_BINDERY_PQUEUE, pattern, &q) == 0)
|
||||
{
|
||||
found = 1;
|
||||
printf("%-52s", q.object_name);
|
||||
printf("%08X\n", q.object_id);
|
||||
printf("%08X\n", (unsigned int)q.object_id);
|
||||
}
|
||||
|
||||
if ((found == 0) && (isatty(1)))
|
||||
@@ -70,6 +71,6 @@ main(int argc, char **argv)
|
||||
printf("No queues found\n");
|
||||
}
|
||||
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include "ncplib.h"
|
||||
|
||||
@@ -77,37 +79,41 @@ terminate_handler()
|
||||
term_request=1;
|
||||
}
|
||||
|
||||
static void
|
||||
daemonize()
|
||||
/* Daemon_init is taken from Stevens, Adv. Unix programming */
|
||||
static int
|
||||
daemon_init(void)
|
||||
{
|
||||
int fd,c;
|
||||
|
||||
if ((c = fork()) > 0) exit(0);
|
||||
if (c < 0)
|
||||
{
|
||||
fprintf(stderr, "ipxripd: can't fork: %s\n",strerror(errno));
|
||||
exit(1);
|
||||
pid_t pid;
|
||||
|
||||
if ((pid = fork()) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (pid != 0)
|
||||
{
|
||||
exit(0); /* parent vanishes */
|
||||
}
|
||||
|
||||
/* child process */
|
||||
setsid();
|
||||
chdir("/");
|
||||
umask(0);
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
if ((fd = open("/dev/tty", O_RDWR)) >= 0)
|
||||
{
|
||||
ioctl(fd, TIOCNOTTY, NULL);
|
||||
close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn *conn;
|
||||
int poll_timeout = 30;
|
||||
int opt;
|
||||
int job_type = 0xffff;
|
||||
int debug = 0;
|
||||
int i;
|
||||
long err;
|
||||
|
||||
char *queue_name = NULL;
|
||||
|
||||
@@ -137,12 +143,14 @@ main(int argc, char *argv[])
|
||||
|
||||
if (debug == 0)
|
||||
{
|
||||
daemonize();
|
||||
daemon_init();
|
||||
openlog("pserver", LOG_PID, LOG_LPR);
|
||||
}
|
||||
|
||||
if (ncp_initialize_as(&conn, &argc, argv, 1, NCP_BINDERY_PSERVER) != 0)
|
||||
if ((conn = ncp_initialize_as(&argc, argv, 1,
|
||||
NCP_BINDERY_PSERVER, &err)) == NULL)
|
||||
{
|
||||
perror("Could not open connection");
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -187,10 +195,10 @@ main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (init_queue(&conn, queue_name, command, &q) != 0)
|
||||
if (init_queue(conn, queue_name, command, &q) != 0)
|
||||
{
|
||||
perror("Could not init queue");
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -215,9 +223,9 @@ main(int argc, char *argv[])
|
||||
sleep(poll_timeout);
|
||||
}
|
||||
|
||||
ncp_detach_from_queue(&conn, q.queue_id);
|
||||
ncp_detach_from_queue(conn, q.queue_id);
|
||||
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -268,13 +276,13 @@ poll_queue(struct nw_queue *q)
|
||||
|
||||
if (pipe(fd) < 0)
|
||||
{
|
||||
perror("pipe");
|
||||
syslog(LOG_ERR, "pipe error: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((pid = fork()) < 0)
|
||||
{
|
||||
perror("fork");
|
||||
syslog(LOG_ERR, "fork error: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -301,7 +309,7 @@ poll_queue(struct nw_queue *q)
|
||||
|
||||
if (waitpid(pid, NULL, 0) < 0)
|
||||
{
|
||||
perror("waitpid");
|
||||
syslog(LOG_ERR, "waitpid: %m\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -314,7 +322,7 @@ poll_queue(struct nw_queue *q)
|
||||
{
|
||||
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
|
||||
{
|
||||
perror("dup2");
|
||||
syslog(LOG_ERR, "dup2 error: %m\n");
|
||||
close(fd[0]);
|
||||
exit(1);
|
||||
}
|
||||
@@ -322,7 +330,7 @@ poll_queue(struct nw_queue *q)
|
||||
}
|
||||
|
||||
execl("/bin/sh", "sh", "-c", q->command, NULL);
|
||||
perror("exec");
|
||||
syslog(LOG_ERR, "exec error: %m\n");
|
||||
close(fd[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
13
util/slist.c
13
util/slist.c
@@ -17,12 +17,13 @@
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ncp_conn conn;
|
||||
struct ncp_conn *conn;
|
||||
struct ncp_bindery_object obj;
|
||||
int found = 0;
|
||||
char default_pattern[] = "*";
|
||||
char *pattern = default_pattern;
|
||||
char *p;
|
||||
long err;
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
@@ -40,9 +41,9 @@ main(int argc, char *argv[])
|
||||
*p = toupper(*p);
|
||||
}
|
||||
|
||||
if (ncp_initialize(&conn, &argc, argv, 0) != 0)
|
||||
if ((conn = ncp_initialize(&argc, argv, 0, &err)) == NULL)
|
||||
{
|
||||
perror("ncp_connect");
|
||||
com_err(argv[0], err, "in ncp_initialize");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@ main(int argc, char *argv[])
|
||||
|
||||
obj.object_id = 0xffffffff;
|
||||
|
||||
while (ncp_scan_bindery_object(&conn, obj.object_id,
|
||||
while (ncp_scan_bindery_object(conn, obj.object_id,
|
||||
NCP_BINDERY_FSERVER, pattern,
|
||||
&obj) == 0)
|
||||
{
|
||||
@@ -70,7 +71,7 @@ main(int argc, char *argv[])
|
||||
|
||||
printf("%-52s", obj.object_name);
|
||||
|
||||
if (ncp_read_property_value(&conn, NCP_BINDERY_FSERVER,
|
||||
if (ncp_read_property_value(conn, NCP_BINDERY_FSERVER,
|
||||
obj.object_name, 1, "NET_ADDRESS",
|
||||
&prop) == 0)
|
||||
{
|
||||
@@ -86,6 +87,6 @@ main(int argc, char *argv[])
|
||||
printf("No servers found\n");
|
||||
}
|
||||
|
||||
ncp_close(&conn);
|
||||
ncp_close(conn);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user