Compare commits

..

7 Commits
v0.11 ... v0.18

Author SHA1 Message Date
ncpfs archive import
d5ac4601b1 Import ncpfs 0.18 2026-04-28 20:39:57 +02:00
ncpfs archive import
1fa124bd7c Import ncpfs 0.17 2026-04-28 20:39:57 +02:00
ncpfs archive import
5753870858 Import ncpfs 0.16 2026-04-28 20:39:57 +02:00
ncpfs archive import
b8ce93c8bd Import ncpfs 0.15 2026-04-28 20:39:57 +02:00
ncpfs archive import
7bef99df0f Import ncpfs 0.14 2026-04-28 20:39:57 +02:00
ncpfs archive import
d31ec2ab61 Import ncpfs 0.13 2026-04-28 20:39:57 +02:00
ncpfs archive import
1ee60bade6 Import ncpfs 0.12 2026-04-28 20:39:57 +02:00
69 changed files with 3329 additions and 503 deletions

BIN
.downloads/ncpfs-0.12.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.13.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.14.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.15.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.16.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.17.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.18.tgz Normal file

Binary file not shown.

21
BUGS
View File

@@ -3,17 +3,20 @@ them to be bugs.
But there are really problems that might be fixed in the future.
'df' returns 0:
Free disk space is distributed among the volumes in NetWare. df is
only able to report one number per mounted filesystem. As connections
are quite expensive for NetWare (with lwared that might change ...), I
rejected the alternative to mount only a single volume for a unix
mount point. So I simply return 0.
-------------------------------------------------------------------------------
'df' returns 0: Free disk space is distributed among the volumes in
NetWare. df is only able to report one number per mounted
filesystem. As connections are quite expensive for NetWare (with
mars_nwe and lwared that might change ...), I rejected the alternative
to mount only a single volume for a unix mount point. So I simply
return 0.
In your kernel log, there will appear messages like
-------------------------------------------------------------------------------
If you use Linux 1.2.x, In your kernel log there will appear messages
like
Nov 25 16:09:08 lx01 kernel: alloc_skb called nonatomically from interrupt 0000002e
These are a bit annoying, but completely harmless. Maybe this will be
fixed in the future.
These are a bit annoying, but completely harmless.

62
Changes Normal file
View File

@@ -0,0 +1,62 @@
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.
ncpfs-0.17 -> ncpfs-0.18
- Another attempt at solving the problem that -n is not working.
- Forgot nprint in 0.17 util/Makefile.
- nprint left connections open when it fails
- added options -r and -t to ncpmount to tune ncpfs connections.
ncpfs-0.16 -> ncpfs-0.17
- Changed the name of fsinfo to nwfsinfo, to avoid a name clash with
the X windows utility. Thanks to Henning Brockfeld
<Henning.Brockfeld@lrz.uni-muenchen.de> for this hint. (still
waiting for your scripts.. :-))
- made nwmsg available. This enables you to receive NetWare user
broadcast messages. Please note that you need at least kernel 1.3.68
for this feature.
- pserver now prints debugging output via syslog().
- Included ipxdump, a nice little utility, that has helped some
people.
- And now the big one: you can re-export ncpfs-mounted directories
with nfsd! You have to mount single volumes by specifying -V volume
to ncpmount, and call nfsd and mountd with the option --re-export.
See the manual page of ncpmount for more information. Please note
that I will send Linus the required patch on 1. March 1996, so you
will have to use kernel 1.2.13 or wait at least for 1.3.70.
ncpfs-0.15 -> ncpfs-0.16
- Included ipx-1.0, made available by Greg Page <greg@caldera.com>,
Caldera
- Made -n work for password-less accounts. Thanks to Alexander Jolk
<jolk@ap-pc513b.physik.uni-karlsruhe.de>.
- Fixed the kerneld support.
- Fixed the NetWare 4.1 problem. Many thanks to
Chatchai JANTARAPRIM <chat@ratree.psu.ac.th> and
hitesh.soneji@industry.net for their patience.
ncpfs-0.14 -> ncpfs-0.15
- A bug fixed that made normal mounting impossible. It was too late
yesterday. Sorry
- Manpage for pserver.c
ncpfs-0.13 -> ncpfs-0.14
- Improvements of manual pages by B. Galliart <bgallia@luc.edu> and
Terry Dawson <terry@perf.no.itg.telecom.com.au>
- fsinfo
- pserver.c. Please see this as ALPHA software. There is no
documentation, and it is not tested enough. But it might be useful for
you.
ncpfs-0.12 -> ncpfs-0.13
- support for automatic loading of ncpfs.o by kerneld.
Thanks to Steven N. Hirsch <hirsch@emba.uvm.edu>.
- A subtle problem in the read routines has been removed by Uwe Bonnes
<bon@elektron.ikp.physik.th-darmstadt.de>. Thanks a lot.

41
FAQ Normal file
View 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.

View File

@@ -2,13 +2,13 @@
# Makefile for the linux ncp-filesystem routines.
#
# KERNEL = 1.2
VERSION = 0.18
TOPDIR = $(shell pwd)
BINDIR = /usr/local/bin
SBINDIR = /sbin
INTERM_BINDIR = $(TOPDIR)/bin
SUBDIRS = util ipx-0.75 man
SUBDIRS = util ipx-1.0 man
#
# The following 2 lines are for those who use Kernel version 1.2.x.
@@ -19,7 +19,11 @@ SUBDIRS = util ipx-0.75 man
SUBDIRS += kernel-1.2/src
INCLUDES = -I$(TOPDIR)/kernel-1.2
export INCLUDES BINDIR INTERM_BINDIR
# If you are using kerneld to autoload ncp support,
# uncomment this (kerneld is in linux since about 1.3.57):
#KERNELD = -DHAVE_KERNELD
export INCLUDES BINDIR INTERM_BINDIR SBINDIR KERNELD VERSION
all:
for i in $(SUBDIRS); do make -C $$i; done
@@ -37,7 +41,7 @@ clean:
rm -f `find . -type f -name '*.out' -print`
for i in $(SUBDIRS); do make -C $$i clean; done
realclean: clean
mrproper: clean
rm -fr $(INTERM_BINDIR)/* ncpfs.tgz
make -C util realclean
@@ -51,7 +55,7 @@ dist: tgz
make dep
make all
tgz: realclean
tgz: mrproper
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \

61
README
View File

@@ -1,11 +1,7 @@
This is version 0.11 of ncpfs, a free NetWare client filesystem for
Linux.
I would like to invite you to write documentation. As those whose
native tongue is English might have noticed, my C is better than my
English. So I doubt that everything in the man/ subdirectory is
written very well. Please feel free to send me any comments about
that.
This is ncpfs, a free NetWare client filesystem for Linux. Besides
some little utilities it also contains nprint, which enables you to
print on NetWare print queues. The opposite side, pserver, is also
provided.
INSTALLATION
@@ -16,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
@@ -27,12 +22,23 @@ 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
To get more help you can subscribe to the LinWare mailing list:
control addr: listserv@sh.cvut.cz
posting addr: linware@sh.cvut.cz
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.
USING NCPFS
Please note that your IPX system has to be configured correctly. If
@@ -74,7 +80,7 @@ I do not want to leave those unmentioned, who have helped me with
ncpfs.
The most enthusiastic user and tester is certainly Uwe Bonnes
<bon@elektron.ikp.physik.th-darmstadt.de>. Up to now he's the only one
<bon@elektron.ikp.physik.th-darmstadt.de>. So far he's the only one
who has contributed something, namely manpages and corretions to
existing manpages.
@@ -82,6 +88,8 @@ Ales Dyrak has written lwared, which was the initial start for ncpfs.
Alan Cox has found some bugs I would probably never have found.
Look at the file Changes for others.
LIMITATIONS (compare these with smbfs :-)
@@ -91,27 +99,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

9
ipx-1.0/COPYING Normal file
View File

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

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

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

View File

@@ -25,6 +25,6 @@ clean:
install: $(UTILS)
for i in $(UTILS); \
do \
install --strip $$i $(BINDIR); \
install $$i $(BINDIR); \
done

View File

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

View File

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

35
ipxdump/Makefile Normal file
View File

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

45
ipxdump/README Normal file
View File

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

247
ipxdump/ipxdump.c Normal file
View File

@@ -0,0 +1,247 @@
/* 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 (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 (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;
}
}
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)
{
printf("802.3 ");
handle_ipx(p);
return;
}
if ( (*(unsigned short *)p == htons(0xe0e0))
&& (p[2] == 0x03))
{
printf("802.2 ");
handle_ipx(p+3);
return;
}
if (memcmp(p, "\252\252\003\000\000\000\201\067", 8) == 0)
{
printf("snap ");
handle_ipx(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):
printf("EtherII ");
handle_ipx(&(buf[sizeof(struct ethhdr)]));
break;
default:
handle_other(buf, length, saddr);
break;
}
}

345
ipxdump/ipxparse.c Normal file
View File

@@ -0,0 +1,345 @@
/* 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"
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);
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;
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);
}
}
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 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;
case 22:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[2]);
switch(data[2])
{
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]);
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 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;
default:
printf("fn: %-3d\n", rq->function);
}
}
if (ntohs(rs->type) == NCP_REPLY)
{
printf("NCP respons: conn: %-5d, seq: %-3d, task: %-3d, ",
rs->conn_low + 256 * rs->conn_high,
rs->sequence, rs->task);
printf("compl: %-3d, conn_st: %-3d\n",
rs->completion_code, rs->connection_state);
data = buf + sizeof(struct ncp_reply_header);
data_length = length - sizeof(struct ncp_reply_header);
}
if (data == NULL)
{
data = buf;
data_length = length;
}
i = 0;
while (i < data_length)
{
int j;
for (j = i; j < i+16; j++)
{
if (j >= data_length)
{
printf(" ");
}
else
{
printf("%-2.2X", data[j]);
}
}
printf(" ");
for (j = i; j < i+16; j++)
{
if (j >= data_length)
{
break;
}
if (isprint(data[j]))
{
printf("%c", data[j]);
}
else
{
printf(".");
}
}
printf("\n");
i += 16;
}
printf("\n");
}
void
main (int argc, char *argv[])
{
unsigned char buf[16384];
unsigned char packet[8192];
unsigned char *b;
int len;
int i = 1;
while (fgets(buf, sizeof(buf), stdin) != NULL)
{
if (strlen(buf) == sizeof(buf)-1)
{
fprintf(stderr, "line too long\n");
exit(1);
}
b = strchr(buf, ' ');
if (b == NULL)
{
fprintf(stderr, "illegal line format\n");
exit(1);
}
*b = '\0';
b += 1;
len = 0;
while ((b[0] != '\0') && (b[1] != '\0'))
{
unsigned int value;
if (sscanf(b, "%2x", &value) != 1)
{
fprintf(stderr, "illegal packet\n");
exit(1);
}
packet[len] = value;
b += 2;
len += 1;
}
handle_ipx(packet, len, buf, i);
i += 1;
}
exit (0);
}

129
ipxdump/ipxutil.c Normal file
View File

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

65
ipxdump/ipxutil.h Normal file
View File

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

View File

@@ -1,5 +1,5 @@
/*
* ncp_fs.h
* ncp.h
*
* Copyright (C) 1995 by Volker Lendecke
*

View File

@@ -42,6 +42,7 @@ struct ncp_fs_info {
#define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *)
#define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t)
#define NCP_IOC_CONN_LOGGED_IN _IO('l', 1)
#define NCP_GET_FS_INFO_VERSION (1)
#define NCP_IOC_GET_FS_INFO _IOWR('i', 1, unsigned char *)
@@ -126,9 +127,12 @@ extern struct inode_operations ncp_dir_inode_operations;
void ncp_free_inode_info(struct ncp_inode_info *i);
void ncp_free_all_inodes(struct ncp_server *server);
void ncp_init_root(struct ncp_server *server);
int ncp_conn_logged_in(struct ncp_server *server);
int ncp_stat_root(struct ncp_server *server);
void ncp_init_dir_cache(void);
void ncp_invalid_dir_cache(unsigned long ino);
void ncp_invalid_dir_cache(struct inode *ino);
struct ncp_inode_info *ncp_find_inode(struct inode *inode);
ino_t ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info);
void ncp_invalidate_all_inodes(struct ncp_server *server);
void ncp_free_dir_cache(void);
int ncp_date_dos2unix(__u16 time, __u16 date);

View File

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

View File

@@ -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

View File

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

View File

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

View File

@@ -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,8 @@ ncp_init_root(struct ncp_server *server)
root->finfo.opened = 0;
i->attributes = aDIR;
i->dataStreamSize = 1024;
i->DosDirNum = 0;
i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
@@ -580,6 +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)
{
@@ -610,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);
@@ -624,7 +721,9 @@ ncp_find_inode(struct inode *dir, const char *name)
do
{
if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
&& (strcmp(result->finfo.i.entryName, name) == 0))
&& (result->dir->finfo.i.volNumber == dir_info->volNumber)
&& (strcmp(result->finfo.i.entryName, name) == 0)
&& (result != &(server->root)))
{
return result;
}
@@ -645,6 +744,8 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
struct ncp_inode_info *result_info;
int found_in_cache;
char name[len+1];
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode))
@@ -654,9 +755,14 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
return -ENOENT;
}
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
server = NCP_SERVER(dir);
if (!ncp_conn_valid(server))
{
iput(dir);
return -EIO;
}
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
/* Fast cheat for . */
if (len == 0 || (len == 1 && __name[0] == '.'))
@@ -675,7 +781,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
parent->state = NCP_INODE_LOOKED_UP;
}
*result = iget(dir->i_sb, (int)parent);
*result = iget(dir->i_sb, ncp_info_ino(server, parent));
iput(dir);
if (*result == 0)
{
@@ -687,7 +793,10 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
}
}
result_info = ncp_find_inode(dir, __name);
memcpy(name, __name, len);
name[len] = 0;
result_info = ncp_find_dir_inode(dir, name);
if (result_info != 0)
{
@@ -699,7 +808,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)
@@ -715,7 +824,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;
@@ -726,7 +835,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
i, c_entry[i].i.entryName);
if (strcmp(c_entry[i].i.entryName, __name) == 0)
if (strcmp(c_entry[i].i.entryName, name) == 0)
{
DPRINTK("ncp_lookup: found in cache!\n");
finfo.i = c_entry[i].i;
@@ -740,20 +849,24 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
if (found_in_cache == 0)
{
char this_name[len+1];
memcpy(this_name, __name, len);
this_name[len] = 0;
str_upper(this_name);
int res;
str_upper(name);
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
NCP_ISTRUCT(dir)->entryName, this_name);
NCP_ISTRUCT(dir)->entryName, name);
if (ncp_do_lookup(server,
dir->i_ino == (int)&(NCP_SERVER(dir)->root)
? NULL : NCP_ISTRUCT(dir),
this_name,
&(finfo.i)) != 0)
if (ncp_is_server_root(dir))
{
res = ncp_lookup_volume(server, name, &(finfo.i));
}
else
{
res = ncp_obtain_info(server,
NCP_ISTRUCT(dir)->volNumber,
NCP_ISTRUCT(dir)->DosDirNum,
name, &(finfo.i));
}
if (res != 0)
{
iput(dir);
return -ENOENT;
@@ -788,6 +901,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';
@@ -795,7 +913,8 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
OC_MODE_CREATE|OC_MODE_OPEN,
OC_MODE_CREATE|OC_MODE_OPEN|
OC_MODE_REPLACE,
0, AR_READ|AR_WRITE,
&finfo) != 0)
{
@@ -803,7 +922,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;
@@ -844,6 +963,11 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
iput(dir);
return -ENOENT;
}
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
@@ -855,7 +979,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
else
{
error = 0;
ncp_invalid_dir_cache(dir->i_ino);
ncp_invalid_dir_cache(dir);
}
iput(dir);
@@ -874,8 +998,14 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL)
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
if (ncp_find_dir_inode(dir, name) != NULL)
{
iput(dir);
error = -EBUSY;
}
else
@@ -889,11 +1019,11 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
NCP_ISTRUCT(dir),
_name)) == 0)
{
ncp_invalid_dir_cache(dir->i_ino);
ncp_invalid_dir_cache(dir);
}
else
{
error = -EINVAL;
error = -EACCES;
}
}
iput(dir);
@@ -912,8 +1042,14 @@ ncp_unlink(struct inode *dir, const char *name, int len)
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL)
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
if (ncp_find_dir_inode(dir, name) != NULL)
{
iput(dir);
error = -EBUSY;
}
else
@@ -926,11 +1062,11 @@ ncp_unlink(struct inode *dir, const char *name, int len)
NCP_ISTRUCT(dir),
_name)) == 0)
{
ncp_invalid_dir_cache(dir->i_ino);
ncp_invalid_dir_cache(dir);
}
else
{
error = -EINVAL;
error = -EACCES;
}
}
iput(dir);
@@ -952,6 +1088,12 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
goto finished;
}
if (!ncp_conn_valid(NCP_SERVER(old_dir)))
{
res = -EIO;
goto finished;
}
if (!new_dir || !S_ISDIR(new_dir->i_mode))
{
printk("ncp_rename: new inode is NULL or not a directory\n");
@@ -959,8 +1101,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
goto finished;
}
if ( (ncp_find_inode(old_dir, old_name) != NULL)
|| (ncp_find_inode(new_dir, new_name) != NULL))
if ( (ncp_find_dir_inode(old_dir, old_name) != NULL)
|| (ncp_find_dir_inode(new_dir, new_name) != NULL))
{
res = -EBUSY;
goto finished;
@@ -980,8 +1122,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
if (res == 0)
{
ncp_invalid_dir_cache(old_dir->i_ino);
ncp_invalid_dir_cache(new_dir->i_ino);
ncp_invalid_dir_cache(old_dir);
ncp_invalid_dir_cache(new_dir);
}
else
{

View File

@@ -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);

View File

@@ -61,50 +61,25 @@ ncp_read_inode(struct inode *inode)
inode->i_ino. Just to make sure everything went well, we
check it's there. */
struct ncp_inode_info *inode_info
= (struct ncp_inode_info *)(inode->i_ino);
struct ncp_inode_info *inode_info = ncp_find_inode(inode);
#if 1
struct ncp_inode_info *root = &(NCP_SERVER(inode)->root);
struct ncp_inode_info *check_info = root;
do
if (inode_info == NULL)
{
if (inode_info == check_info)
{
if (check_info->state == NCP_INODE_LOOKED_UP)
{
DDPRINTK("ncp_read_inode: found it!\n");
goto good;
}
else
{
printk("ncp_read_inode: "
"state != NCP_INODE_LOOKED_UP\n");
goto good;
}
}
check_info = check_info->next;
}
while (check_info != root);
/* Ok, now we're in trouble. The inode info is not there. What
should we do now??? */
printk("ncp_read_inode: inode info not found\n");
return;
}
/* Ok, now we're in trouble. The inode info is not there. What
should we do now??? */
printk("ncp_read_inode: inode info not found\n");
return;
good:
DDPRINTK("ncp_read_inode: read entry %s\n",
inode_info->finfo.i.entryName);
#endif
inode_info->state = NCP_INODE_VALID;
NCP_INOP(inode) = inode_info;
inode_info->inode = inode;
if (NCP_ISTRUCT(inode)->attributes & aDIR)
{
inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
/* for directories in dataStreamSize seems to be some
/* for directories dataStreamSize seems to be some
Object ID ??? */
inode->i_size = 512;
}
@@ -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;
}
@@ -510,6 +493,7 @@ init_module( void)
ncp_init_dir_cache();
register_filesystem(&ncp_fs_type);
printk("ncpfs version %s loaded\n", NCPFS_VERSION);
return 0;
}

View File

@@ -79,6 +79,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)

View File

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

View File

@@ -266,56 +266,19 @@ ncp_extract_file_info(void *structure, struct nw_info_struct *target)
target->entryName[*name_len] = '\0';
return;
}
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target)
ncp_obtain_info(struct ncp_server *server,
__u8 vol_num, __u32 dir_base,
char *path, /* At most 1 component */
struct nw_info_struct *target)
{
__u8 vol_num;
__u32 dir_base;
int result;
char *volname = NULL;
if (target == NULL)
{
return -EINVAL;
}
if (dir == NULL)
{
DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
/* Access a volume's root directory */
ncp_init_request(server);
ncp_add_byte(server, 22); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, 0, 0, 0, /* no handle */
path);
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
dir_base = ncp_reply_dword(server, 4);
vol_num = ncp_reply_byte (server, 8);
ncp_unlock_server(server);
volname = path;
path = NULL;
}
else
{
vol_num = dir->volNumber;
dir_base = dir->DosDirNum;
}
ncp_init_request(server);
ncp_add_byte(server, 6); /* subfunction */
@@ -323,8 +286,7 @@ ncp_do_lookup(struct ncp_server *server,
ncp_add_byte(server, 0); /* dos name space as dest */
ncp_add_word(server, 0xff); /* get all */
ncp_add_dword(server, RIM_ALL);
ncp_add_handle_path(server, vol_num, dir_base, 1,
path);
ncp_add_handle_path(server, vol_num, dir_base, 1, path);
if ((result = ncp_request(server, 87)) != 0)
{
@@ -333,14 +295,54 @@ ncp_do_lookup(struct ncp_server *server,
}
ncp_extract_file_info(ncp_reply_data(server, 0), target);
ncp_unlock_server(server);
return 0;
}
if (volname != NULL)
int
ncp_lookup_volume(struct ncp_server *server,
char *volname,
struct nw_info_struct *target)
{
int result;
__u8 vol_num;
__u32 dir_base;
DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
ncp_init_request(server);
ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
ncp_add_byte(server, 0); /* DOS name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* faked volume number */
ncp_add_dword(server, 0); /* faked dir_base */
ncp_add_byte(server, 0xff); /* Don't have a dir_base */
ncp_add_byte(server, 1); /* 1 path component */
ncp_add_pstring(server, volname);
if ((result = ncp_request(server, 87)) != 0)
{
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
ncp_unlock_server(server);
return result;
}
dir_base = ncp_reply_dword(server, 4);
vol_num = ncp_reply_byte(server, 8);
ncp_unlock_server(server);
if ((result = ncp_obtain_info(server, vol_num, dir_base, NULL,
target)) != 0)
{
return result;
}
DPRINTK("ncp_lookup_volume: attribs = %X\n", target->attributes);
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
return 0;
}
@@ -417,12 +419,18 @@ ncp_open_create_file_or_subdir(struct ncp_server *server,
struct nw_file_info *target)
{
int result;
__u16 search_attribs = 0x0006;
if ((create_attributes & aDIR) != 0)
{
search_attribs |= 0x8000;
}
ncp_init_request(server);
ncp_add_byte(server, 1); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, open_create_mode);
ncp_add_word(server, 0x8006);
ncp_add_word(server, search_attribs);
ncp_add_dword(server, RIM_ALL);
ncp_add_dword(server, create_attributes);
/* The desired acc rights seem to be the inherited rights mask
@@ -583,7 +591,7 @@ ncp_read(struct ncp_server *server, const char *file_id,
*bytes_read = ntohs(ncp_reply_word(server, 0));
memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read);
memcpy_tofs(target, ncp_reply_data(server, 2+(offset&1)), *bytes_read);
ncp_unlock_server(server);
return 0;

View File

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

View File

@@ -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;
}

View File

@@ -9,6 +9,9 @@ add [-p] device frame_type [network number]
del device frame_type
.LP
.B ipx_interface
delall
.LP
.B ipx_interface
check device frame_type
.LP
.B ipx_interface
@@ -45,6 +48,9 @@ network.
.I del
This option is used to delete an IPX interface.
.TP
.I delall
This option is used to delete all IPX interfaces.
.TP
.I check
This option is used to display the device, frame type, and network number
of an IPX interface.

View File

@@ -1,27 +1,27 @@
.TH NCPMOUNT 8 12/27/1995 ncpmount ncpmount
.SH NAME
ncpmount \- mount program for ncpfs
ncpmount \- mount all volumes of a specified Novell fileserver.
.SH SYNOPSIS
.B ncpmount
[
.B -h
] [
.B -S
.I server
] [
.B -h
] [
.B -n
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -c
.I client name
] [
.B -U
.I user name
] [
.B -u
.I uid
] [
@@ -33,14 +33,26 @@ ncpmount \- mount program for ncpfs
] [
.B -d
.I dir mode
]
] [
.B -V
.I volume
] [
.B -t
.I time_out
] [
.B -r
.I retry_count
] [
.B -v
]
mount-point
.SH DESCRIPTION
This program is an interface to the NCP filesystem.
This program is used to mount all volumes of the specified NetWare Fileserver
under the specified mount point.
.B ncpfs
is a filesystem which understands the NCP protocol. This is the
is a linux filesystem which understands the NCP protocol. This is the
protocol Novell NetWare clients use to talk to NetWare servers. ncpfs
was inspired by
.B lwared,
@@ -48,18 +60,23 @@ a free NetWare emulator for Linux written by Ales Dryak. See
ftp://klokan.sh.cvut.cz/pub/linux for this very intersting program.
.B ncpmount
looks up the file
when invoked with all appropriate arguments attaches, logs in and
mounts all of the volumes associated with the specified fileserver that are
readable by the user id under the specified mount point.
.B ncpmount
when invoked without any arguments specifying the fileserver, user id and
password checks the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of .nwclient MUST be 600, for security reasons.
to find a file server, a user name and possibly a password to use for the
specified mount point. See nwclient(5) for more information. Please note
that the access permissions of .nwclient MUST be 600, for security reasons.
.SH OPTIONS
.B mount-point
.RS 3
.B mount-point
is the directory you want to mount the filesystem over. It's the same
as in the normal mount command.
is the directory you want to mount the filesystem over. Its function is the
the same as for a normal mount command.
If the real uid of the caller is not root,
.B ncpmount
@@ -87,42 +104,40 @@ is used to print out a short help text.
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
By default passwords are converted to uppercase before they are sent
to the server because most servers require this. This option disables this
feature ensuring that passwords are sent without any case conversion.
.RE
.B -n
.RS 3
.B -n
should be given to mount shares which do not require a password to log in.
must be specified for logins that do not have a password configured.
.RE
.B -P
.I password
.RS 3
You may want to give the password required by the server on the
command line. You should be careful to use passwords in scripts.
specifies the password to use for the Netware user id.
If neither
.B -n
nor
nor the
.B -P
are given, ncpmount prompts for a password. This makes it difficult to
use in scripts such as /etc/rc. But that's not ncpmount's fault, but a
general problem with the fact that you need a password on every
login. If anybody has a satisfying solution to this problem, please
tell me.
arguments are specified ncpmount will prompt for a password. This
makes it difficult to use in scripts such as /etc/rc. If you want to
have ncpmount work automatically from a script you must include the
appropriate option and be very careful to ensure that appopriate file
permissions are set for the script that includes your password to
ensure that others can not read it.
.RE
.B -U
.I user name
.RS 3
If the user name your NetWare administrator gave to you differs
from your unix user-id, you should use
.B -U
to tell the server about you NetWare user name.
Specifies the Netware user id to use when logging in to the fileserver. If
this option is not specified then ncpmount will attempt to login to the
fileserver using the Linux login id of the user invoking ncpmount.
.RE
.B -u
@@ -130,9 +145,9 @@ to tell the server about you NetWare user name.
.B -g
.I gid
.RS 3
Currently I did not implement a mapping from NetWare users/groups to
unix users/groups. Unix requires that each file has an owner
and a group it belongs to. With
ncpmount does not yet implement a scheme for mapping NetWare users/groups
to Linux users/groups. Linux requires that each file has an owner and group id.
With
.B -u
and
.B -g
@@ -145,19 +160,20 @@ The defaults for these values are the current uid and gid.
.B -c
.I user name
.RS 3
This option is only makes sense if root mounts the directory. root can
mount directories on behalf of other users.
.B -c
names the user who is the
.I owner
of the connection, where owner is not meant in the unix sense (that
"owner" is set by -u), but as the one who has mounted the directory.
This way it could be possible to mount a public read-only directory,
of the connection, where owner does not refer to file ownership (that
"owner" is set by the -u argument), but the owner of the mount, ie: who
is allowed to call ncpumount on this mount. The default owner of the
connection and the mount is the user who called ncpmount. This option
allows you to specify that some other user should be set as the owner.
In this this way it is possible to mount a public read-only directory,
but to allow the lp daemon to print on NetWare queues. This is
possible, because only users who have write permissions on a directory
may issue ncp requests over a connection. An exception is the owner
(in the sense mentioned above), who is also given 'request
permission'.
possible because only users who have write permissions on a directory
may issue ncp requests over a connection. The exception to this rule
is the 'mount owner', who is also granted 'request permission'.
.RE
.B -f
@@ -169,14 +185,11 @@ Like
.B -u
and
.B -g,
these options are also used to cover deficiencies in the
implementation of ncpfs. I did not implement a scheme to map NetWare
permissions to unix permissions. So ncpmount has to be told which
permissions it should assign to the mounted files and directories. The
values have to be given as octal numbers. The default values are taken
from the current umask, where the file mode is the current umask, and
the dir mode adds execute permissions where the file mode gives read
permissions.
these options are used to determine what permissions should be assigned
files and directories of the mounted volumes. The values must be specified
as octal numbers. The default values are taken from the current umask, where
the file mode is the current umask, and the dir mode adds execute permissions
where the file mode gives read permissions.
Note that these permissions can differ from the rights the server
gives to us. If you do not have write permissions on the server, you
@@ -184,8 +197,75 @@ can very well choose a file mode that tells that you have. This
certainly cannot override the restrictions imposed by the server.
.RE
.B -V
.I volume
.RS 3
There are 2 general ways you can mount a NetWare server's disk space:
Either you can mount all volumes under one directory, or you can mount
only a single volume.
When you choose to mount the complete disk space at once, you have the
advantage that only one Linux mount point and only one
NetWare connection is used for all the volumes of this server. Both of
these are limited resources. (Although raising the number of Linux
mount points is significantly cheaper than raising the number of
available NetWare connections ;-))
When you specify to mount a single volume by using the option
.B -V
.I volume,
you have the big advantage that nfsd is able to re-export this mounted
directory. You must invoke
.B nfsd
and
.B mountd
with the option
.I --re-export
to make nfsd re-export ncpfs mounted directories. This uses one Linux
mount point and one NetWare connection per mounted volume. Maybe
sometime in the future I will make it possible to mount all volumes on
different mount points, using only one connection.
.RE
.B -t
.I time_out
.RS 3
With
.B -t
you can adjust the time ncpfs waits for the server to answer a request
it sent. Use the option to raise the timeout value when your ncpfs
connections seem to be unstable although your servers are well
up. This can happen when you have very busy servers, or servers that
are very far away.
.I time_out
is specified in 1/100s, the current default value is 60.
.RE
.B -r
.I retry_count
.RS 3
As
.B -t, -r
can be used to tune the ncpfs connection to the server. With
retry_count you can specify how many times ncpfs will attempt to send
a packet to the server before it decides the connection is dead. The
current default value is 5.
Currently ncpfs is not too clever when trying to find out that
connections are dead. If anybody knows how to do that correctly, as it
is done by commercial workstations, please tell me.
.RE
.B -v
.RS 3
Print ncpfs version number
.RE
.SH NOTES
If you have difficulties in mounting, please make sure that you have configured your ipx subsystem correctly. It is especially important that there is a route to the internal network of your server.
You must configure the IPX subsystem before ncpmount will work.
It is especially important that there is a route to the internal network
of your server.
.SH ENVIRONMENT VARIABLES
.B USER / LOGNAME
@@ -201,7 +281,7 @@ Most diagnostics issued by ncpfs are logged by syslogd. Normally
nothing is printed, only error situations are logged there.
.SH SEE ALSO
.B syslogd(8), ncpumount(8)
.B syslogd(8), ncpumount(8), nfsd(8), mountd(8)
.SH CREDITS
ncpfs would not have been possible without lwared, written by Ales

View File

@@ -1,13 +1,14 @@
.TH NCPUMOUNT 8 12/27/1995 ncpumount ncpumount
.SH NAME
ncpumount \- umount for normal users
ncpumount \- unmount a NetWare filesystem mounted with ncpmount.
.SH SYNOPSIS
.B ncpumount
.B mount-point
.SH DESCRIPTION
With this program, normal users can unmount ncp-filesystems, provided
that it is suid root.
This utility unmounts a NetWare filesystem that was previously mounted
with the ncpmount utility. If the this utility is made suid root then
non-root users will also be able to make use of it.
.B ncpumount
has been written to give normal linux-users more control over their

View File

@@ -9,18 +9,16 @@ nprint \- NetWare print client
] [
.B -h
] [
.B -n
] [
.B -C
] [
.B -U
.I user name
] [
.B -P
.I password
] [
|
.B -n
] [
.B -C
] [
.B -q
.I queue name
] [
@@ -65,6 +63,13 @@ you can print files on print queues of a NetWare file server.
There are a lot of options, so you should probably wrap some default
configurations into some shell scripts.
.B nprint
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of .nwclient MUST be 600, for security reasons.
.SH OPTIONS
.B file
.RS 3
@@ -73,6 +78,12 @@ is the name of the file you want to print. If file is '-', or no
filename is given, standard input is used.
.RE
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
@@ -105,12 +116,20 @@ prompts for a password.
should be given if no password is required for the print request.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -q
.I queue name
.RS 3
.B queue name
is the name of the print queue to use at the print server. At
present, you must give it in upper case characters.
present, you must specify it in upper case characters.
.RE
.B -d
@@ -161,6 +180,13 @@ is the number of lines to put on one page. Default: 66
is the number of rows to put on one page. Default: 80
.RE
.B -c
.I copies
.RS 3
.B copies
tells the print server to the specified number of copies. Default: 1
.RE
.B -t
.I tabs
.RS 3
@@ -189,4 +215,8 @@ different from the one currently in the printer, your job is only
printed if a printer operator has put in the correct form.
.RE
.SH SEE ALSO
.B nwclient(5), slist(1), pqlist(1), ncpmount(8), ncpumount(8)
.SH CREDITS
nprint was written by Volker Lendecke (lendecke@namu01.gwdg.de)

View File

@@ -13,8 +13,8 @@ connection. Lines beginning with # and empty lines are ignored as
comments.
Because you can store passwords in .nwclient, the user programs will
only scan .nwclient if ONLY the file owner has any access rights to
the file.
only scan .nwclient when only the file owner has access rights to
the file. The file must be have permissions 0600.
To specify a NWClient connection, the name of the file server, the
user name to be used and a password is necessary. The server name and
@@ -40,3 +40,16 @@ the the file server FS311 with user name ME on /mnt after asking the
user for a password.
\'nwmount -S cd-serv /cd' will silently mount the server cd-serv on /cd.
.B nprint
,
.B pqlist
and other user programs that require a valid login also look up
.I $HOME/.nwclient
to find a file server, a user name and possibly a password.
Please note that the access permissions of .nwclient MUST be 600, for
security reasons.
.SH SEE ALSO
.B ncpmount(8), ncpumount(8), slist(1), pqlist(1), nprint(1)

33
man/nwmsg.8 Normal file
View File

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

View File

@@ -4,25 +4,40 @@ pqlist \- List available NetWare print queues
.SH SYNOPSIS
.B pqlist
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -n
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.I pattern
]
.SH DESCRIPTION
With
.B pqlist,
you can list the NetWare print queues available to you on some
server. If you are already connected to some server, this one is
used.
.B pqlist
lists all the NetWare print queues available to you on some server.
If you are already connected to some server, this one is used.
If pqlist does not print to a tty, the decorative header line is
not printed, so that you can count the printing queue available
on your server by doing
pqlist -S server | wc -l
.B pqlist
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of .nwclient MUST be 600, for security reasons.
.SH OPTIONS
@@ -34,6 +49,57 @@ pattern, but you have to be careful to prevent shell interpretation of
wildcards like '*'.
.RE
See ncpmount(8) for an explanation of the other options. They are
necessary because you might have to login into a server before it
tells you where you may print.
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user name
.RS 3
If the user name your NetWare administrator gave to you differs
from your unix user-id, you should use
.B -U
to tell the server about you NetWare user name.
.RE
.B -P
.I password
.RS 3
You may want to give the password required by the server on the
command line. You should be careful to use passwords in scripts.
.RE
.B -n
.RS 3
.B -n
should be given to mount shares which do not require a password to log in.
If neither
.B -n
nor
.B -P
are given, pqlist prompts for a password.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.SH SEE ALSO
.B nwclient(5), nprint(1), slist(1), ncpmount(8), ncpumount(8)
.SH CREDITS
pqlist was written by Volker Lendecke (lendecke@namu01.gwdg.de)

142
man/pserver.1 Normal file
View File

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

View File

@@ -1,16 +1,16 @@
.TH SLIST 1 01/07/1996 slist slist
.SH NAME
slist \- List available NetWare Servers
slist \- Lists available NetWare Servers
.SH SYNOPSIS
.B slist
[
.I pattern
]
.SH DESCRIPTION
With
.B slist,
you can get a list of NetWare Servers available in your network. If
slist does not print to a tty, the decorative header line is not
.B slist
lists all NetWare Servers available in your network.
If slist does not print to a tty, the decorative header line is not
printed, so that you can count the servers on your network by doing
slist | wc -l
@@ -20,10 +20,10 @@ slist | wc -l
.B pattern
.RS 3
.B pattern
is used to list only selected servers. For a server to be listed, the
pattern must match the full server name. You can use wildcards for the
pattern, but you must protect these wildcards from any command line
expansion by quoting. Case doesn't matter.
is used to list only servers whose names match the specified pattern. For a
server to be listed, the pattern must match the full server name. You can use
wildcards for the pattern, but you must protect these wildcards from any
command line expansion by quoting. Case doesn't matter.
.RE
.SH EXAMPLE
@@ -34,3 +34,10 @@ or
.TP
slist "i*"
List all available Netware servers on your Network, that begin with an "I".
.SH SEE ALSO
.B ncpmount(8), ncpumount(8), pqlist(1), nprint(1)
.SH CREDITS
slist was written by Volker Lendecke (lendecke@namu01.gwdg.de)

View File

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

19
ncpfs-0.18.lsm Normal file
View File

@@ -0,0 +1,19 @@
Begin3
Title: ncpfs
Version: 0.18
Entered-date: 09. 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
Linux printing system. You need kernel 1.2.x or
1.3.54 and above. ncpfs does NOT work with any 1.3.x
kernel below 1.3.54.
Keywords: filesystem 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
Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/
~83k ncpfs-0.18.tgz
~ 1k ncpfs-0.18.lsm
Copying-policy: GPL
End

View File

@@ -2,19 +2,26 @@
# Makefile for the linux ncp-filesystem routines.
#
UTIL_EXECS = ncpmount ncpumount nprint slist pqlist
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
USERUTILS = slist pqlist nwfsinfo pserver nprint
UIDUTILS = ncpmount ncpumount
SBINUTILS = nwmsg
CFLAGS = -Wall $(INCLUDES) -O2
UTIL_EXECS = $(USERUTILS) $(UIDUTILS) $(SBINUTILS)
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
#CFLAGS = -Wall $(INCLUDES) $(KERNELD) -g -DNCPFS_VERSION=\"$(VERSION)\"
CFLAGS = -Wall $(INCLUDES) $(KERNELD) -O2 -DNCPFS_VERSION=\"$(VERSION)\"
CC = gcc
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

View File

@@ -1,46 +0,0 @@
/*
* fsinfo.c
*
* Print the info strings of a server, maybe sometime more.
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include <stdio.h>
#include "ncplib.h"
int
main(int argc, char **argv)
{
struct ncp_conn conn;
char strings[512];
char *s;
if (ncp_initialize(&conn, &argc, argv, 0) != 0)
{
perror("Could not open connection");
return 1;
}
if (ncp_get_file_server_description_strings(&conn, strings) != 0)
{
perror("could not get strings");
ncp_close(&conn);
return 1;
}
s = strings;
while (s < strings+512)
{
if (strlen(s) == 0)
{
break;
}
puts(s);
s += strlen(s)+1;
}
ncp_close(&conn);
return 0;
}

View File

@@ -34,8 +34,13 @@ extern pid_t wait(int *);
static int
ncp_negotiate_buffersize(struct ncp_conn *conn,
int size, int *target);
static int
ncp_login_object(struct ncp_conn *conn,
const unsigned char *username,
int login_type,
const unsigned char *password);
static void
void
str_upper(char *name)
{
while (*name) {
@@ -837,7 +842,8 @@ ncp_open_temporary(struct ncp_conn *conn,
if (strlen(spec->user) != 0)
{
if (ncp_login_user(conn, spec->user, spec->password) != 0)
if (ncp_login_object(conn, spec->user, spec->login_type,
spec->password) != 0)
{
ncp_close(conn);
errno = EACCES;
@@ -1195,6 +1201,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password,
str_upper(spec.server);
str_upper(spec.user);
spec.login_type = NCP_BINDERY_USER;
if (ncp_open_permanent(&conn, &spec) == 0)
{
@@ -1230,35 +1237,35 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password,
}
fclose(nwc);
}
}
if (strlen(spec.user) == 0)
if (strlen(spec.user) == 0)
{
return &spec;
}
if ((strlen(spec.password) == 0) && (password == NULL))
{
char *password;
if (!(isatty(0) && isatty(1)))
{
return &spec;
return NULL;
}
printf("Logging into %s as %s\n",
spec.server, spec.user);
if (strlen(spec.password) == 0)
password = getpass("Password: ");
if (strlen(password) > sizeof(spec.password))
{
char *password;
if (!(isatty(0) && isatty(1)))
{
return NULL;
}
printf("Logging into %s as %s\n",
spec.server, spec.user);
password = getpass("Password: ");
if (strlen(password) > sizeof(spec.password))
{
return NULL;
}
strcpy(spec.password, password);
return NULL;
}
else
strcpy(spec.password, password);
}
else
{
if (strcmp(spec.password, NWC_NOPASSWORD) == 0)
{
if (strcmp(spec.password, NWC_NOPASSWORD) == 0)
{
*spec.password = '\0';
}
*spec.password = '\0';
}
}
@@ -1269,9 +1276,9 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password,
}
int
ncp_initialize(struct ncp_conn *conn,
int *argc, char **argv,
int login_necessary)
ncp_initialize_as(struct ncp_conn *conn,
int *argc, char **argv,
int login_necessary, int login_type)
{
char *server = NULL;
char *user = NULL;
@@ -1306,6 +1313,7 @@ ncp_initialize(struct ncp_conn *conn,
}
errno = EINVAL;
memzero(*conn);
while (i < *argc)
{
@@ -1341,6 +1349,7 @@ ncp_initialize(struct ncp_conn *conn,
{
return -1;
}
password = NWC_NOPASSWORD;
continue;
}
i += 1;
@@ -1360,9 +1369,20 @@ ncp_initialize(struct ncp_conn *conn,
errno = 0;
spec->login_type = login_type;
return ncp_open(conn, spec);
}
int
ncp_initialize(struct ncp_conn *conn,
int *argc, char **argv,
int login_necessary)
{
return ncp_initialize_as(conn, argc, argv, login_necessary,
NCP_BINDERY_USER);
}
static int
ncp_request(struct ncp_conn *conn, int function)
{
@@ -1376,12 +1396,49 @@ ncp_request(struct ncp_conn *conn, int function)
return -ENOTCONN;
}
/****************************************************************************/
/* */
/* Helper functions */
/* */
/****************************************************************************/
static inline int
min(int a, int b)
{
return (a<b) ? a : b;
}
struct nw_time_buffer {
__u8 year __attribute__ ((packed));
__u8 month __attribute__ ((packed));
__u8 day __attribute__ ((packed));
__u8 hour __attribute__ ((packed));
__u8 minute __attribute__ ((packed));
__u8 second __attribute__ ((packed));
__u8 wday __attribute__ ((packed));
};
static time_t
nw_to_ctime(struct nw_time_buffer *source)
{
struct tm u_time;
memzero(u_time);
u_time.tm_sec = source->second;
u_time.tm_min = source->minute;
u_time.tm_hour = source->hour;
u_time.tm_mday = source->day;
u_time.tm_mon = source->month - 1;
u_time.tm_year = source->year;
if (u_time.tm_year < 80)
{
u_time.tm_year += 100;
}
return mktime(&u_time);
}
static void
assert_conn_locked(struct ncp_conn *conn)
{
@@ -1527,6 +1584,50 @@ ncp_get_file_server_description_strings(struct ncp_conn *conn,
return 0;
}
int
ncp_get_file_server_time(struct ncp_conn *conn, time_t *target)
{
int result;
ncp_init_request(conn);
if ((result = ncp_request(conn, 20)) != 0)
{
ncp_unlock_conn(conn);
return result;
}
*target= nw_to_ctime((struct nw_time_buffer *)ncp_reply_data(conn, 0));
ncp_unlock_conn(conn);
return 0;
}
int
ncp_get_connlist(struct ncp_conn *conn, __u32 last_id,
__u16 object_type, const char *object_name,
int *returned_no, __u16 conn_numbers[256])
{
int result;
ncp_init_request_s(conn, 27);
ncp_add_dword(conn, htonl(last_id));
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
if ((result = ncp_request(conn, 23)) != 0)
{
ncp_unlock_conn(conn);
return result;
}
*returned_no = ncp_reply_byte(conn, 0);
memcpy(conn_numbers, ncp_reply_data(conn, 1),
sizeof(__u16) * (*returned_no));
return 0;
}
/*
* result is a 8-byte buffer
*/
@@ -1671,6 +1772,15 @@ int
ncp_login_user(struct ncp_conn *conn,
const unsigned char *username,
const unsigned char *password)
{
return ncp_login_object(conn, username, NCP_BINDERY_USER, password);
}
static int
ncp_login_object(struct ncp_conn *conn,
const unsigned char *username,
int login_type,
const unsigned char *password)
{
int result;
unsigned char ncp_key[8];
@@ -1680,7 +1790,7 @@ ncp_login_user(struct ncp_conn *conn,
return result;
}
if ((result = ncp_get_bindery_object_id(conn, NCP_BINDERY_USER,
if ((result = ncp_get_bindery_object_id(conn, login_type,
username, &user)) != 0) {
return result;
}
@@ -2272,14 +2382,22 @@ ncp_open_create_file_or_subdir(struct ncp_conn *conn,
int
ncp_initialize_search(struct ncp_conn *conn,
struct nw_info_struct *dir,
struct nw_search_sequence *target)
const struct nw_info_struct *dir,
int namespace,
struct ncp_search_seq *target)
{
int result;
if ((namespace < 0) || (namespace > 255))
{
return EINVAL;
}
memzero(*target);
ncp_init_request(conn);
ncp_add_byte(conn, 2); /* subfunction */
ncp_add_byte(conn, 0); /* dos name space */
ncp_add_byte(conn, namespace);
ncp_add_byte(conn, 0); /* reserved */
ncp_add_handle_path(conn, dir->volNumber,
dir->DosDirNum, 1, NULL);
@@ -2289,7 +2407,8 @@ ncp_initialize_search(struct ncp_conn *conn,
return result;
}
memcpy(target, ncp_reply_data(conn, 0), sizeof(*target));
memcpy(&(target->s), ncp_reply_data(conn, 0), sizeof(target->s));
target->namespace = namespace;
ncp_unlock_conn(conn);
return 0;
@@ -2298,18 +2417,18 @@ ncp_initialize_search(struct ncp_conn *conn,
/* Search for everything */
int
ncp_search_for_file_or_subdir(struct ncp_conn *conn,
struct nw_search_sequence *seq,
struct ncp_search_seq *seq,
struct nw_info_struct *target)
{
int result;
ncp_init_request(conn);
ncp_add_byte(conn, 3); /* subfunction */
ncp_add_byte(conn, 0); /* dos name space */
ncp_add_byte(conn, seq->namespace);
ncp_add_byte(conn, 0); /* data stream (???) */
ncp_add_word(conn, 0xffff); /* Search attribs */
ncp_add_dword(conn, RIM_ALL); /* return info mask */
ncp_add_mem(conn, seq, 9);
ncp_add_mem(conn, &(seq->s), 9);
ncp_add_byte(conn, 2); /* 2 byte pattern */
ncp_add_byte(conn, 0xff); /* following is a wildcard */
ncp_add_byte(conn, '*');
@@ -2384,7 +2503,6 @@ ncp_create_queue_job_and_file(struct ncp_conn *conn,
}
memcpy(&(job->j), ncp_reply_data(conn, 0), 78);
ConvertToNWfromDWORD(job->j.JobFileHandle, job->file_handle);
ncp_unlock_conn(conn);
@@ -2409,7 +2527,106 @@ ncp_close_file_and_start_job(struct ncp_conn *conn,
ncp_unlock_conn(conn);
return 0;
}
}
int
ncp_attach_to_queue(struct ncp_conn *conn,
__u32 queue_id)
{
int result;
ncp_init_request_s(conn, 111);
ncp_add_dword(conn, htonl(queue_id));
if ((result = ncp_request(conn, 23)) != 0) {
ncp_unlock_conn(conn);
return result;
}
ncp_unlock_conn(conn);
return 0;
}
int
ncp_detach_from_queue(struct ncp_conn *conn,
__u32 queue_id)
{
int result;
ncp_init_request_s(conn, 112);
ncp_add_dword(conn, htonl(queue_id));
if ((result = ncp_request(conn, 23)) != 0) {
ncp_unlock_conn(conn);
return result;
}
ncp_unlock_conn(conn);
return 0;
}
int
ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type,
struct queue_job *job)
{
int result;
ncp_init_request_s(conn, 124);
ncp_add_dword(conn, htonl(queue_id));
ncp_add_word(conn, htons(job_type));
if ((result = ncp_request(conn, 23)) != 0) {
ncp_unlock_conn(conn);
return result;
}
memcpy(&(job->j), ncp_reply_data(conn, 0), 78);
ConvertToNWfromDWORD(job->j.JobFileHandle, job->file_handle);
ncp_unlock_conn(conn);
return 0;
}
int
ncp_finish_servicing_job(struct ncp_conn *conn, __u32 queue_id,
__u32 job_number, __u32 charge_info)
{
int result;
ncp_init_request_s(conn, 131);
ncp_add_dword(conn, htonl(queue_id));
ncp_add_dword(conn, job_number);
ncp_add_dword(conn, htonl(charge_info));
if ((result = ncp_request(conn, 23)) != 0) {
ncp_unlock_conn(conn);
return result;
}
ncp_unlock_conn(conn);
return 0;
}
int
ncp_abort_servicing_job(struct ncp_conn *conn, __u32 queue_id,
__u32 job_number)
{
int result;
ncp_init_request_s(conn, 132);
ncp_add_dword(conn, htonl(queue_id));
ncp_add_dword(conn, job_number);
if ((result = ncp_request(conn, 23)) != 0) {
ncp_unlock_conn(conn);
return result;
}
ncp_unlock_conn(conn);
return 0;
}
static int
ncp_do_read(struct ncp_conn *conn, const char *file_id,
@@ -2523,3 +2740,99 @@ ncp_write(struct ncp_conn *conn, const char *file_id,
}
return already_written;
}
int
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)
{
int result;
ncp_init_request(conn);
ncp_add_byte(conn, 0); /* reserved */
ncp_add_mem(conn, source_file, 6);
ncp_add_mem(conn, target_file, 6);
ncp_add_dword(conn, source_offset);
ncp_add_dword(conn, target_offset);
ncp_add_dword(conn, count);
if ((result = ncp_request(conn, 74)) != 0)
{
ncp_unlock_conn(conn);
return result;
}
*copied_count = ncp_reply_dword(conn, 0);
ncp_unlock_conn(conn);
return 0;
}
int
ncp_get_broadcast_message(struct ncp_conn *conn, char message[256])
{
int result;
int length;
ncp_init_request_s(conn, 1);
if ((result = ncp_request(conn, 21)) != 0)
{
ncp_unlock_conn(conn);
return result;
}
length = ncp_reply_byte(conn, 0);
message[length] = 0;
memcpy(message, ncp_reply_data(conn, 1), length);
ncp_unlock_conn(conn);
return 0;
}
int
ncp_dealloc_dir_handle(struct ncp_conn *conn, __u8 dir_handle)
{
int result;
ncp_init_request_s(conn, 20);
ncp_add_byte(conn, dir_handle);
if ((result = ncp_request(conn, 22)) != 0)
{
ncp_unlock_conn(conn);
return result;
}
ncp_unlock_conn(conn);
return 0;
}
int
ncp_alloc_short_dir_handle(struct ncp_conn *conn,
struct nw_info_struct *dir,
word alloc_mode,
byte *target)
{
int result;
ncp_init_request(conn);
ncp_add_byte(conn, 12); /* subfunction */
ncp_add_byte(conn, 0); /* dos name space */
ncp_add_byte(conn, 0); /* reserved */
ncp_add_word(conn, htons(alloc_mode));
ncp_add_handle_path(conn, dir->volNumber, dir->DosDirNum,
1, NULL);
if ((result = ncp_request(conn, 87)) != 0)
{
ncp_unlock_conn(conn);
return result;
}
*target = ncp_reply_byte(conn, 0);
ncp_unlock_conn(conn);
return result;
}

View File

@@ -14,13 +14,18 @@
#include <linux/ipx.h>
#include <sys/param.h>
#include <stdio.h>
#include <time.h>
#include "ipxlib.h"
#ifndef memzero
#include <string.h>
#define memzero(object) memset(&(object), 0, sizeof(object))
#endif
void
str_upper(char *name);
enum connect_state {
NOT_CONNECTED = 0,
CONN_PERMANENT,
@@ -64,9 +69,15 @@ struct ncp_conn_spec {
char server[NCP_BINDERY_NAME_LEN];
char user[NCP_BINDERY_NAME_LEN];
uid_t uid;
int login_type; /* NCP_BINDERY_USER / NCP_BINDERY_PSERVER */
char password[NCP_BINDERY_NAME_LEN];
};
struct ncp_search_seq {
struct nw_search_sequence s;
int namespace;
};
/* ncp_initialize is the main entry point for user programs which want
to connect to a NetWare Server. It looks for -S, -U, -P and -n in
the argument list, opens the connection and removes the arguments
@@ -77,6 +88,14 @@ ncp_initialize(struct ncp_conn *conn,
int *argc, char **argv,
int login_necessary);
/* 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);
/* Open an existing permanent connection */
int
ncp_open(struct ncp_conn *conn,
@@ -127,6 +146,14 @@ int
ncp_get_file_server_description_strings(struct ncp_conn *conn,
char target[512]);
int
ncp_get_file_server_time(struct ncp_conn *conn, time_t *target);
int
ncp_get_connlist(struct ncp_conn *conn, __u32 last_id,
__u16 object_type, const char *object_name,
int *returned_no, __u16 conn_numbers[256]);
int
ncp_get_encryption_key(struct ncp_conn *conn,
char *target);
@@ -230,6 +257,15 @@ int
ncp_write(struct ncp_conn *conn, const char *file_id,
off_t offset, size_t count, const char *source);
int
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);
int
ncp_do_lookup(struct ncp_conn *conn,
struct nw_info_struct *dir,
@@ -257,12 +293,13 @@ ncp_open_create_file_or_subdir(struct ncp_conn *conn,
int
ncp_initialize_search(struct ncp_conn *conn,
struct nw_info_struct *dir,
struct nw_search_sequence *target);
const struct nw_info_struct *dir,
int namespace,
struct ncp_search_seq *target);
int
ncp_search_for_file_or_subdir(struct ncp_conn *conn,
struct nw_search_sequence *seq,
struct ncp_search_seq *seq,
struct nw_info_struct *target);
int
@@ -280,4 +317,40 @@ ncp_close_file_and_start_job(struct ncp_conn *conn,
__u32 queue_id,
struct queue_job *job);
int
ncp_attach_to_queue(struct ncp_conn *conn,
__u32 queue_id);
int
ncp_detach_from_queue(struct ncp_conn *conn,
__u32 queue_id);
int
ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type,
struct queue_job *job);
int
ncp_finish_servicing_job(struct ncp_conn *conn, __u32 queue_id,
__u32 job_number, __u32 charge_info);
int
ncp_abort_servicing_job(struct ncp_conn *conn, __u32 queue_id,
__u32 job_number);
int
ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]);
int
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
ncp_alloc_short_dir_handle(struct ncp_conn *conn,
struct nw_info_struct *dir,
__u16 alloc_mode,
__u8 *target);
#endif /* _NCPLIB_H */

View File

@@ -3,6 +3,16 @@
*
* Copyright (C) 1995 by Volker Lendecke
*
* 1/20/96 - Steven N. Hirsch (hirsch@emba.uvm.edu)
*
* If the ncpfs support is not loaded and we are using kerneld to
* autoload modules, then we don't want to do it here. I added
* a conditional which leaves out the test and load code.
*
* Even if we _do_ want ncpmount to load the module, passing a
* fully-qualified pathname to insmod causes it to bypass a
* path search. This may lead to ncpfs.o not being found on
* some systems.
*/
#include <stdio.h>
@@ -37,18 +47,18 @@ extern pid_t waitpid(pid_t, int *, int);
#include "ncplib.h"
static char *progname;
static void str_upper(char *name);
static void usage(void);
static void help(void);
#ifndef HAVE_KERNELD
/* Returns 0 if the filesystem is in the kernel after this routine
completes */
static int
load_ncpfs(void)
{
FILE *fver, *ffs;
FILE *ffs;
char s[1024];
char modname[1024];
char *p, *p1;
pid_t pid;
int status;
@@ -81,33 +91,6 @@ load_ncpfs(void)
{
return 0;
}
fver = fopen("/proc/version", "r");
if (fver == NULL)
{
perror("Error: \"/proc/version\" could not be read:");
return -1;
}
fgets(s, 1024, fver);
fclose(fver);
p = strstr(s, "version ");
if (p == NULL)
{
version_error:
fprintf(stderr, "Error: Unable to determine the Linux version"
"from \"/proc/version\n");
return -1;
}
p = strchr(p, ' ') + 1;
p1 = strchr(p, ' ');
if (p1 == NULL)
{
goto version_error;
}
strcpy(modname, "/lib/modules/");
strncat(modname, p, p1 - p);
strcat(modname, "/ncpfs.o");
/* system() function without signal handling, from Stevens */
@@ -118,7 +101,7 @@ load_ncpfs(void)
else if (pid == 0)
{
/* child */
execl("/sbin/insmod", "insmod", modname, NULL);
execl("/sbin/insmod", "insmod", "ncpfs", NULL);
_exit(127); /* execl error */
}
else
@@ -136,6 +119,8 @@ load_ncpfs(void)
return status;
}
#endif /* HAVE_KERNELD */
/* Check whether user is allowed to mount on the specified mount point */
static int
mount_ok(struct stat *st)
@@ -206,10 +191,14 @@ main(int argc, char *argv[])
umask(um);
data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
data.dir_mode = 0;
data.flags |= NCP_MOUNT_SOFT;
data.time_out = 60;
data.retry_count = 5;
upcase_password = 1;
while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nh")) != EOF)
while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nhvV:t:r:"))
!= EOF)
{
switch (opt)
{
@@ -299,12 +288,29 @@ main(int argc, char *argv[])
}
password = optarg;
break;
case 'V':
if (strlen(optarg) >= sizeof(data.mounted_vol))
{
printf("Volume too long: %s\n", optarg);
exit(1);
}
strcpy(data.mounted_vol, optarg);
break;
case 'n':
password = "";
break;
case 't':
data.time_out = atoi(optarg);
break;
case 'r':
data.retry_count = atoi(optarg);
break;
case 'h':
help();
exit(1);
case 'v':
fprintf(stderr, "ncpfs version %s\n", NCPFS_VERSION);
exit(1);
default:
usage();
return -1;
@@ -345,6 +351,7 @@ main(int argc, char *argv[])
exit(1);
}
#ifndef HAVE_KERNELD
/* Check if the ncpfs filesystem is in the kernel. If not, attempt
* to load the ncpfs module */
if (load_ncpfs() != 0)
@@ -352,9 +359,11 @@ main(int argc, char *argv[])
fprintf(stderr, "Error: Unable to load ncpfs, exiting...\n");
exit(1);
}
#endif
data.version = NCP_MOUNT_VERSION;
data.mounted_uid = conn_uid;
memcpy(data.server_name, spec->server, sizeof(data.server_name));
if (data.dir_mode == 0)
{
@@ -436,10 +445,32 @@ main(int argc, char *argv[])
exit(1);
}
flags = MS_MGC_VAL;
#if NCP_MOUNT_VERSION>1
data.time_out = 20;
data.retry_count = 2;
data.message_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (data.message_fd == -1)
{
fprintf(stderr, "could not open message socket: %s\n",
strerror(errno));
exit(1);
}
addr.sipx_port = htons(ntohs(addr.sipx_port) + 1);
if (bind(data.message_fd, (struct sockaddr *)&addr,sizeof(addr)) == -1)
{
fprintf(stderr, "bind(message_sock, ): %s\n",
strerror(errno));
exit(1);
}
if (strlen(mount_point) < sizeof(data.mount_point))
{
strcpy(data.mount_point, mount_point);
}
#endif
flags = MS_MGC_VAL;
result = mount(NULL, mount_point, "ncpfs", flags, (char *)&data);
@@ -450,7 +481,8 @@ main(int argc, char *argv[])
}
if ( (ncp_open_mount(&conn, mount_point) != 0)
|| (ncp_login_user(&conn, spec->user, spec->password) != 0))
|| (ncp_login_user(&conn, spec->user, spec->password) != 0)
|| (ioctl(conn.mount_fid, NCP_IOC_CONN_LOGGED_IN, NULL) != 0))
{
fprintf(stderr, "%s: login failed\n", strerror(errno));
ncp_close(&conn);
@@ -504,15 +536,6 @@ main(int argc, char *argv[])
return 0;
}
static void
str_upper(char *name)
{
while (*name) {
*name = toupper(*name);
name = name + 1;
}
}
static void
usage(void)
{
@@ -528,17 +551,22 @@ help(void)
printf("\n"
"-S server Server name to be used\n"
"-U username Username sent to server\n"
"-V volume Volume to mount, for NFS re-export\n"
"-u uid uid the mounted files get\n"
"-g gid gid the mounted files get\n"
"-f mode permission the files get (octal notation)\n"
"-d mode permission the dirs get (octal notation)\n"
"-c uid uid to identify the connection to mount on\n"
" Only makes sense for root\n"
"-t time_out Waiting time (in 1/100s) to wait for\n"
" an answer from the server. Default: 60\n"
"-r retry_count Number of retry attempts. Default: 5\n"
"-C Don't convert password to uppercase\n"
"-P password Use this password\n"
"-n Do not use any password\n"
" If neither -P nor -n are given, you are\n"
" asked for a password.\n"
"-h print this help text\n"
"-v print ncpfs version number\n"
"\n");
}

View File

@@ -96,24 +96,110 @@ test_print(struct ncp_conn *conn)
}
void
main(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];
int no;
ncp_get_connlist(conn, 0, NCP_BINDERY_USER, "*", &no, conn_list);
return;
}
void
test_create(struct ncp_conn *conn)
{
struct nw_info_struct sys;
struct nw_info_struct me;
__u8 dir_handle;
struct ncp_file_info new_file;
if (ncp_do_lookup(conn, NULL, "SYS", &sys) != 0)
{
printf("lookup error\n");
return;
}
if (ncp_do_lookup(conn, &sys, "ME", &me) != 0)
{
printf("lookup public error\n");
return;
}
if (ncp_alloc_short_dir_handle(conn, &me, NCP_ALLOC_TEMPORARY,
&dir_handle) != 0)
{
printf("alloc_dir_handle error\n");
return;
}
if (ncp_create_file(conn, dir_handle, "BLUB.TXT", 0,
&new_file) != 0)
{
printf("create error\n");
return;
}
if (ncp_dealloc_dir_handle(conn, dir_handle) != 0)
{
printf("dealloc error\n");
return;
}
}
int
main(int argc, char *argv[])
{
struct ncp_conn conn;
struct ncp_conn_spec *spec;
if ((spec = ncp_find_conn_spec("NW311", "me", "", 0)) == NULL)
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
{
perror("could not find spec");
exit(1);
perror("ncp_initialize");
return 1;
}
if (ncp_open(&conn, NULL) != 0)
{
perror("ncp_open");
exit(1);
}
test_print(&conn);
test_create(&conn);
ncp_close(&conn);
return 0;
}

View File

@@ -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:
*/

View File

@@ -1,5 +1,5 @@
/*
* nwprint.c
* nprint.c
*
* Send data to a NetWare print queue.
*
@@ -20,8 +20,7 @@
static char *progname;
static void
usage(void);
static void
str_upper(char *name);
static void help(void);
void
main(int argc, char *argv[])
@@ -48,6 +47,13 @@ main(int argc, char *argv[])
memzero(j); memzero(pj); memzero(q); memzero(conn);
if ( (argc == 2)
&& (strcmp(argv[1], "-h") == 0))
{
help();
exit(0);
}
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
{
perror("Could not open connection");
@@ -71,9 +77,13 @@ main(int argc, char *argv[])
pj.Rows = htons(80);
strcpy(pj.FnameHeader, "stdin");
while ((opt = getopt(argc, argv, "q:d:p:b:f:l:r:c:t:F:TN"))!=EOF)
while ((opt = getopt(argc, argv, "hq:d:p:b:f:l:r:c:t:F:TN"))!=EOF)
{
switch (opt) {
case 'h':
help();
ncp_close(&conn);
exit(1);
case 'p':
/* Path */
pj.CtrlFlags |= PRINT_BANNER;
@@ -181,6 +191,7 @@ main(int argc, char *argv[])
{
printf("queue name too long: %s\n",
optarg);
ncp_close(&conn);
exit(1);
}
queue = optarg;
@@ -201,6 +212,7 @@ main(int argc, char *argv[])
default:
usage();
ncp_close(&conn);
exit(1);
}
}
@@ -208,6 +220,7 @@ main(int argc, char *argv[])
if (optind != argc-1)
{
usage();
ncp_close(&conn);
exit(1);
}
@@ -223,6 +236,7 @@ main(int argc, char *argv[])
if (file < 0)
{
perror("could not open file");
ncp_close(&conn);
exit(1);
}
@@ -258,13 +272,15 @@ main(int argc, char *argv[])
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)
{
printf("create error\n");
return;
ncp_close(&conn);
exit(1);
}
written = 0;
@@ -289,24 +305,42 @@ main(int argc, char *argv[])
if (ncp_close_file_and_start_job(&conn, q.object_id, &j) != 0) {
printf("close error\n");
ncp_close(&conn);
return;
}
}
ncp_close(&conn);
return;
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [options] file\n", progname);
exit(1);
}
static void
str_upper(char *name)
help(void)
{
while (*name) {
*name = toupper(*name);
name = name + 1;
}
printf("\n");
printf("usage: %s [options] file\n", progname);
printf("\n"
"-S server Server name to be used\n"
"-U username Username sent to server\n"
"-P password Use this password\n"
"-n Do not use any password\n"
"-C Don't convert password to uppercase\n"
"-q queue name Name of the printing queue to use\n"
"-d job desc Job description\n"
"-p path name Path name to appear on banner\n"
"-b bannername Banner name (up to 12 chars)\n"
"-f filename Filename to appear on banner\n"
"-l lines Number of lines per page\n"
"-r rows Number of rows per page\n"
"-t tab Number of spaces per tab\n"
"-T Print server tab expantion\n"
"-N Surpress print server form feeds\n"
"-F form # Form number to print on\n"
"-h print this help text\n"
"\n");
}

78
util/nwfsinfo.c Normal file
View File

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

219
util/nwmsg.c Normal file
View 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;
progname = argv[0];
openlog("nwmsg", LOG_PID, LOG_LPR);
if (argc != 2)
{
fprintf(stderr, "usage: %s mount-point\n",
progname);
exit(1);
}
if (ncp_open_mount(&conn, argv[1]) != 0)
{
fprintf(stderr, "%s: could not open connection %s\n",
progname, argv[1]);
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;
}

View File

@@ -62,7 +62,7 @@ main(int argc, char **argv)
{
found = 1;
printf("%-52s", q.object_name);
printf("%08lx\n", q.object_id);
printf("%08X\n", (unsigned int)q.object_id);
}
if ((found == 0) && (isatty(1)))

344
util/pserver.c Normal file
View File

@@ -0,0 +1,344 @@
/*
* pserver.c
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#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"
struct nw_queue {
struct ncp_conn *conn;
char queue_name[NCP_BINDERY_NAME_LEN];
__u32 queue_id;
__u16 job_type;
char *command;
};
static struct nw_queue q;
static int term_request;
static char *progname;
static int
init_queue(struct ncp_conn *conn, char *queue_name,
char *command, struct nw_queue *q);
static int
poll_queue(struct nw_queue *q);
static void
usage(void)
{
fprintf(stderr, "usage: %s [options] file\n", progname);
exit(1);
}
static void
help(void)
{
printf("\n");
printf("usage: %s [options]\n", progname);
printf("\n"
"-S server Server name to be used\n"
"-U username Print Server name sent to server\n"
"-P password Use this password\n"
"-n Do not use any password\n"
"-C Don't convert password to uppercase\n"
"-q queue name Name of the printing queue to use\n"
"-c command Name of print command, default: 'lpr'\n"
"-j job type Type of job (Form number) to service\n"
"-t timeout Polling interval, default: 30 sec\n"
"-d Debug: don't daemonize\n"
"-h print this help text\n"
"\n");
}
#ifndef NCP_BINDERY_PSERVER
#define NCP_BINDERY_PSERVER (0x0007)
#endif
static void
terminate_handler()
{
signal(SIGTERM,terminate_handler);
signal(SIGINT, terminate_handler);
term_request=1;
}
/* Daemon_init is taken from Stevens, Adv. Unix programming */
static int
daemon_init(void)
{
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);
return 0;
}
int
main(int argc, char *argv[])
{
struct ncp_conn conn;
int poll_timeout = 30;
int opt;
int job_type = 0xffff;
int debug = 0;
int i;
char *queue_name = NULL;
char default_command[] = "lpr";
char *command = default_command;
progname = argv[0];
for (i = 1; i < argc; i += 1)
{
if ( (strcmp(argv[i], "-h") == 0)
|| (strcmp(argv[i], "-?") == 0))
{
help();
exit(0);
}
}
for (i = 1; i < argc; i += 1)
{
if (strcmp(argv[i], "-d") == 0)
{
debug = 1;
break;
}
}
if (debug == 0)
{
daemon_init();
openlog("pserver", LOG_PID, LOG_LPR);
}
if (ncp_initialize_as(&conn, &argc, argv, 1, NCP_BINDERY_PSERVER) != 0)
{
perror("Could not open connection");
return 1;
}
while ((opt = getopt(argc, argv, "q:c:j:t:dh")) != EOF)
{
switch (opt)
{
case 'q':
queue_name = optarg;
break;
case 'c':
command = optarg;
break;
case 'j':
job_type = atoi(optarg);
break;
case 't':
poll_timeout = atoi(optarg);
break;
case 'd':
debug = 1;
break;
case 'h':
break;
default:
usage();
return -1;
}
}
if (argc != optind)
{
usage();
return -1;
}
memzero(q);
if (queue_name == NULL)
{
fprintf(stderr, "You must specify a queue\n");
return 1;
}
if (init_queue(&conn, queue_name, command, &q) != 0)
{
perror("Could not init queue");
ncp_close(&conn);
return 1;
}
q.job_type = job_type;
term_request = 0;
signal(SIGTERM,terminate_handler);
signal(SIGINT, terminate_handler);
while (1)
{
if ( (poll_queue(&q) != 0)
&& (term_request == 0))
{
continue;
}
if (term_request != 0)
{
break;
}
sleep(poll_timeout);
}
ncp_detach_from_queue(&conn, q.queue_id);
ncp_close(&conn);
return 0;
}
static int
init_queue(struct ncp_conn *conn, char *queue_name, char *command,
struct nw_queue *q)
{
struct ncp_bindery_object obj;
str_upper(queue_name);
q->conn = conn;
q->command = command;
if (ncp_get_bindery_object_id(conn, NCP_BINDERY_PQUEUE,
queue_name, &obj) != 0)
{
fprintf(stderr, "Queue %s not found\n", queue_name);
return -1;
}
q->queue_id = obj.object_id;
memcpy(q->queue_name, obj.object_name, sizeof(q->queue_name));
if (ncp_attach_to_queue(conn, q->queue_id) != 0)
{
fprintf(stderr, "Could not attach to queue %s\n",
queue_name);
return -1;
}
return 0;
}
static int
poll_queue(struct nw_queue *q)
{
struct queue_job job;
int fd[2];
int pid;
if (ncp_service_queue_job(q->conn, q->queue_id, q->job_type,
&job) != 0)
{
/* No job for us */
return 0;
}
if (pipe(fd) < 0)
{
syslog(LOG_ERR, "pipe error: %m");
goto fail;
}
if ((pid = fork()) < 0)
{
syslog(LOG_ERR, "fork error: %m");
goto fail;
}
if (pid > 0)
{
/* parent */
char buf[1024];
size_t result;
off_t offset = 0;
close(fd[0]); /* close read end */
while ((result = ncp_read(q->conn, job.file_handle, offset,
sizeof(buf), buf)) > 0)
{
offset += result;
if (write(fd[1], buf, result) != result)
{
goto fail;
}
}
close(fd[1]); /* and close write end */
if (waitpid(pid, NULL, 0) < 0)
{
syslog(LOG_ERR, "waitpid: %m\n");
}
}
else
{
/* child */
close(fd[1]); /* close write end */
if (fd[0] != STDIN_FILENO)
{
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
{
syslog(LOG_ERR, "dup2 error: %m\n");
close(fd[0]);
exit(1);
}
close(fd[0]);
}
execl("/bin/sh", "sh", "-c", q->command, NULL);
syslog(LOG_ERR, "exec error: %m\n");
close(fd[0]);
exit(1);
}
ncp_finish_servicing_job(q->conn, q->queue_id, job.j.JobNumber,0);
return 1;
fail:
ncp_abort_servicing_job(q->conn, q->queue_id, job.j.JobNumber);
/* We tell that we did not have a job to avoid overloading
when something's wrong */
return 0;
}