diff --git a/.downloads/ncpfs-0.19.tgz b/.downloads/ncpfs-0.19.tgz new file mode 100644 index 0000000..a366ce8 Binary files /dev/null and b/.downloads/ncpfs-0.19.tgz differ diff --git a/Changes b/Changes index 47e95db..9af8080 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,16 @@ 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.18 -> ncpfs-0.19 + +- hacked around in ncplib.[ch] quite heavily. +- SAP handling in ipxparse.c. Thanks to Jeff Buhrt +- Changed error handling to use the com_err library. This should + eventually provide better error messages, because it's now much + easier to define nice messages. +- If no server is active, report this correctly +- added nsend + ncpfs-0.17 -> ncpfs-0.18 - Another attempt at solving the problem that -n is not working. diff --git a/Makefile b/Makefile index 9a15b23..bfc215e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux ncp-filesystem routines. # -VERSION = 0.18 +VERSION = 0.19 TOPDIR = $(shell pwd) BINDIR = /usr/local/bin @@ -43,7 +43,7 @@ clean: mrproper: clean rm -fr $(INTERM_BINDIR)/* ncpfs.tgz - make -C util realclean + make -C util mrproper modules: ncpfs.o diff --git a/README b/README index 9b11d71..c8eab2a 100644 --- a/README +++ b/README @@ -30,13 +30,21 @@ 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. +email address. You can mail to and/or subscribe to the LinWare mailing +list: + +Topics for the list: +- discussing LinWare server, its features, installation problems and bugs +- using IPX protocol under Linux +- IPX routing and router daemons under Linux +- mars_nwe +- ncpfs + +You can subscribe to the list by sending the command "add linware" in +the mail message body to address: "listserv@sh.cvut.cz". Your +postings should be sent to: "linware@sh.cvut.cz". USING NCPFS diff --git a/TODO b/TODO new file mode 100644 index 0000000..56c8903 --- /dev/null +++ b/TODO @@ -0,0 +1,20 @@ +Here's a list of things I want to do. Feel free to send suggestions, +or even help me ;-). + +- little utilities for bindery access, such as nwlsobj, nwlsprop, + nwcreateobj and so on. + +- Add flags to pserver's command line, so that the print command can + find out the name of user who printed the job. + +- do rtt estimation, like tcp does. + +- Do better connection management. I imagine to create a ncpd. + +- When ncp is done, one can think about mounting several volumes over + a single NCP connection. This should make the trade-off mentioned in + ncpmount.8 unnecessary. + +- long file names + +- Do some kind of mapping of NCP uid's to unix uid's diff --git a/ipxdump/ipxdump.c b/ipxdump/ipxdump.c index 6d6ff20..4fd3605 100644 --- a/ipxdump/ipxdump.c +++ b/ipxdump/ipxdump.c @@ -60,7 +60,7 @@ struct ipx_packet void handle_frame (unsigned char *buf, int length, struct sockaddr *saddr); -void handle_ipx (unsigned char *buf); +void handle_ipx(char *frame, unsigned char *buf); static int filter = 0; static IPXNode filter_node; @@ -147,7 +147,7 @@ main (int argc, char *argv[]) } void -handle_ipx (unsigned char *buf) +handle_ipx (char *frame, unsigned char *buf) { int i; struct ipx_packet *h = (struct ipx_packet *)buf; @@ -179,6 +179,8 @@ handle_ipx (unsigned char *buf) } } + printf("%s ", frame); + for (i = 0; i < length; i++) { printf("%2.2X", buf[i]); @@ -207,23 +209,20 @@ handle_other (unsigned char *buf, int length, struct sockaddr *saddr) if (*(unsigned short *)p == 0xffff) { - printf("802.3 "); - handle_ipx(p); + handle_ipx("802.3", p); return; } if ( (*(unsigned short *)p == htons(0xe0e0)) && (p[2] == 0x03)) { - printf("802.2 "); - handle_ipx(p+3); + handle_ipx("802.2", p+3); return; } if (memcmp(p, "\252\252\003\000\000\000\201\067", 8) == 0) { - printf("snap "); - handle_ipx(p+8); + handle_ipx("snap", p+8); return; } } @@ -237,8 +236,7 @@ handle_frame (unsigned char *buf, int length, struct sockaddr *saddr) switch( packet_type ) { case __constant_ntohs(ETH_P_IPX): - printf("EtherII "); - handle_ipx(&(buf[sizeof(struct ethhdr)])); + handle_ipx("EtherII ", &(buf[sizeof(struct ethhdr)])); break; default: handle_other(buf, length, saddr); diff --git a/ipxdump/ipxparse.c b/ipxdump/ipxparse.c index c6023ae..837a2a2 100644 --- a/ipxdump/ipxparse.c +++ b/ipxdump/ipxparse.c @@ -35,6 +35,8 @@ #include #include "ipxutil.h" +#define DUMPALLSAPS /* #define if you want to dump all SAP's */ + struct ipx_address { unsigned long net; @@ -92,12 +94,58 @@ void handle_ncp (struct sockaddr_ipx *source, struct sockaddr_ipx *target, unsigned char *buf, int length, int no); +#define SAP_MAX_SERVER_NAME_LENGTH 48 /* in network packets */ +#define SAP_MAX_SAPS_PER_PACKET 7 +#define SAP_SHUTDOWN 16 /* Magic "hops" value to stop SAP advertising */ + +/* SAP Query structure (returned in sap_packet as an array) + * NBO == Network Byte Order) + */ +typedef struct saps { + __u16 serverType __attribute__ ((packed)); /* NBO */ + __u8 serverName[SAP_MAX_SERVER_NAME_LENGTH] __attribute__ ((packed)); + struct ipx_address serverAddress __attribute__ ((packed)); + __u16 serverHops __attribute__ ((packed)); /* NBO */ +} SAPS; + +/* General Service/Nearest Server Response SAP packet */ +union sap_packet { + unsigned short sapOperation; + struct sap_query { + __u16 sapOperation __attribute__ ((packed)); + __u16 serverType __attribute__ ((packed)); + } query; + struct sap_response { + __u16 sapOperation __attribute__ ((packed)); + /* each SAP can has a max of SAP_MAX_SAPS_PER_PACKET packets */ + SAPS sap[SAP_MAX_SAPS_PER_PACKET] __attribute__ ((packed)); + } response; +}; + +/* print out one SAP record */ +static void +print_sap(FILE *file, SAPS *sapp) +{ + fprintf(file, " Name:%s, serverType 0x%x, ", + sapp->serverName, + ntohs(sapp->serverType)); + ipx_fprint_network(file, ntohl(sapp->serverAddress.net)); + fprintf(file, ":"); + ipx_fprint_node(file, sapp->serverAddress.node); + fprintf(file, ":"); + ipx_fprint_port(file, ntohs(sapp->serverAddress.sock)); + fprintf(file, " (Hops %d)\n", ntohs(sapp->serverHops)); +} + void handle_ipx (unsigned char *buf, int length, char *frame, int no) { struct ipx_packet *h = (struct ipx_packet *)buf; struct sockaddr_ipx s_addr; struct sockaddr_ipx d_addr; + union sap_packet *sappacket; + int hbo_dsock; /* Host Byte Order of Destination SOCKet */ + int hbo_sapop; /* Host Byte Order of SAP OPeration */ memset(&s_addr, 0, sizeof(s_addr)); memset(&d_addr, 0, sizeof(d_addr)); @@ -123,6 +171,86 @@ handle_ipx (unsigned char *buf, int length, char *frame, int no) handle_ncp(&s_addr, &d_addr, buf + sizeof(struct ipx_packet), length - sizeof(struct ipx_packet), no); } + else /* next 3 handle IPX by type vs by socket (one or other) */ + /* Note: most things use either ipx_type OR socket, not both */ + if (h->ipx_type == 0x01) + printf(" type 0x01 (RIP packet (router))\n"); + else + if (h->ipx_type == 0x05) + printf(" type 0x05 (SPX sequenced packet)\n"); + else + if (h->ipx_type == 0x14) + printf(" type 0x14 (propogated Client-NetBios)\n"); + else + { + hbo_dsock = ntohs(d_addr.sipx_port); + if (hbo_dsock == 0x452) /* SAP */ + { + sappacket = (union sap_packet *) + (buf + sizeof(struct ipx_packet)); + hbo_sapop = ntohs(sappacket->sapOperation); + if ((hbo_sapop == 0x01) || (hbo_sapop == 0x03)) + { + printf(" type 0x%x, SAP op:0x%x %s Query, " + "serverType 0x%x wanted\n", + h->ipx_type, hbo_sapop, + (hbo_sapop == 0x01)?"General Service" : + (hbo_sapop == 0x03)?"Nearest Server" : + "Error", + ntohs(sappacket->query.serverType)); + } + else + { + int hops; + + hops = ntohs(sappacket-> + response.sap[0].serverHops); + printf(" type 0x%x, SAP op:0x%x %s %s\n", + h->ipx_type, hbo_sapop, + (hbo_sapop == 0x02) + ? "General Service Response" : + (hbo_sapop == 0x04) + ? "Nearest Server Response" : + "Unknown", + (hops >= SAP_SHUTDOWN) + ? "[Shutdown]" : ""); + + /* Service ending */ + if (hops >= SAP_SHUTDOWN) + { + print_sap(stdout, + sappacket->response.sap); + } +#ifdef DUMPALLSAPS + /* If you want to dump all SAP's */ + else + { int num_saps; + SAPS *sapp; + + num_saps = (length + - sizeof(struct ipx_packet) + - 2) / sizeof(SAPS); + + sapp = sappacket->response.sap; + for(; num_saps > 0; sapp++, num_saps--) + print_sap(stdout, sapp); + } +#endif /* DUMPALLSAPS */ + } + + } + else /* Other IPX types */ + printf(" type 0x%x, Socket 0x%x (%s)\n", h->ipx_type, + hbo_dsock, + (hbo_dsock == 0x451) ? "NCP" : +/* (hbo_dsock == 0x452) ? "SAP" :*/ + (hbo_dsock == 0x453) ? "RIP" : + (hbo_dsock == 0x455) ? "Client-NetBios" : + (hbo_dsock == 0x456) ? "Diags" : + (hbo_dsock == 0x002) ? "Xecho" : + (hbo_dsock == 0x8063) ? "NVT2" : "Other"); + } + } void handle_ncp (struct sockaddr_ipx *source, @@ -183,6 +311,21 @@ void handle_ncp (struct sockaddr_ipx *source, data += 1; data_length -= 1; break; + case 21: + printf("fn: %-3d, subfn: %-3d\n", + rq->function, data[2]); + switch(data[2]) + { + case 0: + printf("Send Broadcast Message\n"); + break; + case 1: + printf("Get Broadcast Message\n"); + break; + } + data += 3; + data_length -= 3; + break; case 22: printf("fn: %-3d, subfn: %-3d\n", rq->function, data[2]); @@ -198,6 +341,19 @@ void handle_ncp (struct sockaddr_ipx *source, case 23: printf("fn: %-3d, subfn: %-3d\n", rq->function, data[2]); + switch(data[2]) + { + case 17: + printf("Get Fileserver Information\n"); + break; + case 28: + printf("Get Connection Information\n"); + break; + case 55: + printf("Scan Bindery Object\n"); + break; + } + data += 3; data_length -= 3; break; @@ -342,4 +498,3 @@ main (int argc, char *argv[]) exit (0); } - diff --git a/kernel-1.2/linux/ncp_fs.h b/kernel-1.2/linux/ncp_fs.h index 5dab842..8215817 100644 --- a/kernel-1.2/linux/ncp_fs.h +++ b/kernel-1.2/linux/ncp_fs.h @@ -34,18 +34,16 @@ struct ncp_fs_info { int buffer_size; /* The negotiated buffer size, to be used for read/write requests! */ - /* Not used yet, but here some day the namespace numbers will be - stored. */ int volume_number; __u32 directory_id; }; -#define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *) -#define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t) -#define NCP_IOC_CONN_LOGGED_IN _IO('l', 1) +#define NCP_IOC_NCPREQUEST _IOR('n', 1, struct ncp_ioctl_request) +#define NCP_IOC_GETMOUNTUID _IOW('n', 2, uid_t) +#define NCP_IOC_CONN_LOGGED_IN _IO('n', 3) #define NCP_GET_FS_INFO_VERSION (1) -#define NCP_IOC_GET_FS_INFO _IOWR('i', 1, unsigned char *) +#define NCP_IOC_GET_FS_INFO _IOWR('n', 4, struct ncp_fs_info) /* * The packet size to allocate. One page should be enough. diff --git a/kernel-1.2/src/dir.c b/kernel-1.2/src/dir.c index 8369ff8..d06318e 100644 --- a/kernel-1.2/src/dir.c +++ b/kernel-1.2/src/dir.c @@ -723,6 +723,11 @@ ncp_find_dir_inode(struct inode *dir, const char *name) if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum) && (result->dir->finfo.i.volNumber == dir_info->volNumber) && (strcmp(result->finfo.i.entryName, name) == 0) + /* The root dir is never looked up using this + * routine. Without the following test a root + * directory 'sys' in a volume named 'sys' could + * never be looked up, because + * server->root->dir==server->root. */ && (result != &(server->root))) { return result; diff --git a/kernel-1.2/src/ioctl.c b/kernel-1.2/src/ioctl.c index beb6951..f0a9d9a 100644 --- a/kernel-1.2/src/ioctl.c +++ b/kernel-1.2/src/ioctl.c @@ -29,6 +29,26 @@ ncp_ioctl (struct inode * inode, struct file * filp, struct ncp_fs_info info; struct ncp_server *server = NCP_SERVER(inode); + /* + * Binary compatible with 1.3.XX releases. + * Take this out in 2.1.0 development series. + * 12 Mar 1996 + */ + switch(cmd) { + case _IOR('n', 1, unsigned char *): + cmd = NCP_IOC_NCPREQUEST; + break; + case _IOR('u', 1, uid_t): + cmd = NCP_IOC_GETMOUNTUID; + break; + case _IO('l', 1): + cmd = NCP_IOC_CONN_LOGGED_IN; + break; + case _IOWR('i', 1, unsigned char *): + cmd = NCP_IOC_GET_FS_INFO; + break; + } + switch(cmd) { case NCP_IOC_NCPREQUEST: @@ -116,6 +136,8 @@ ncp_ioctl (struct inode * inode, struct file * filp, info.mounted_uid = server->m.mounted_uid; info.connection = server->connection; info.buffer_size = server->buffer_size; + info.volume_number = NCP_ISTRUCT(inode)->volNumber; + info.directory_id = NCP_ISTRUCT(inode)->DosDirNum; memcpy_tofs((struct ncp_fs_info *)arg, &info, sizeof(info)); return 0; diff --git a/man/Makefile b/man/Makefile index 129ba0c..10ecff5 100644 --- a/man/Makefile +++ b/man/Makefile @@ -1,6 +1,7 @@ -MAN1= slist nprint pqlist +MAN1= slist nprint pqlist nsend pserver MAN5= nwclient -MAN8= ncpmount ncpumount ipx_configure ipx_interface ipx_internal_net ipx_route +MAN8= ncpmount ncpumount ipx_configure ipx_interface ipx_internal_net \ + ipx_route nwmsg diff --git a/man/nsend.1 b/man/nsend.1 new file mode 100644 index 0000000..eafbf88 --- /dev/null +++ b/man/nsend.1 @@ -0,0 +1,108 @@ +.TH NSEND 1 03/21/1996 nsend nsend +.SH NAME +nsend \- Send messages to users +.SH SYNOPSIS +.B nsend +[ +.B -h +] [ +.B -S +.I server +] [ +.B -U +.I user name +] [ +.B -P +.I password + | +.B -n +] [ +.B -C +] +.I user message + +.SH DESCRIPTION +With +.B nsend, +you can send messages to the user's workstations. + +.B nsend +looks up the file +.I $HOME/.nwclient +to find a file server, a user name and possibly a password. See +nwclient(5) for more information. Please note that the access +permissions of .nwclient MUST be 600, for security reasons. + +.SH OPTIONS + +.B user +.RS 3 +.B user +is the NetWare User-ID of the user to receive the message. +.RE + +.B message +.RS 3 +.B message +is the message to be sent. Please note that this has to be a single +command line argument. If you want to send a message that contains +spaces, you have to quote them on the command line. For example, to +annoy your system administrator, you should try + + nsend supervisor 'I know how this works!' +.RE + +.B -S +.I server +.RS 3 +.B server +is the name of the server you want to use. +.RE + +.B -U +.I user name +.RS 3 +If the user name your NetWare administrator gave to you differs +from your unix user-id, you should use +.B -U +to tell the server about you NetWare user name. +.RE + +.B -P +.I password +.RS 3 +You may want to give the password required by the server on the +command line. You should be careful to use passwords in scripts. +.RE + +.B -n +.RS 3 +.B -n +should be given to mount shares which do not require a password to log in. + +If neither +.B -n +nor +.B -P +are given, nsend prompts for a password. +.RE + +.B -C +.RS 3 +By default, passwords are converted to uppercase before they are sent +to the server, because most servers require this. You can turn off +this conversion by +.B -C. +.RE + +.SH BUGS +nsend only supports servers with up to 255 connections. I do not know +the NCP functions for larger servers. If anybody knows them, please +tell me! + +.SH SEE ALSO +.B nwclient(5), nprint(1), slist(1), ncpmount(8), ncpumount(8) + +.SH CREDITS +nsend was written by looking at mars_nwe's message handling. Thanks to +Martin Stover diff --git a/ncpfs-0.18.lsm b/ncpfs-0.19.lsm similarity index 83% rename from ncpfs-0.18.lsm rename to ncpfs-0.19.lsm index bf39745..7917950 100644 --- a/ncpfs-0.18.lsm +++ b/ncpfs-0.19.lsm @@ -1,7 +1,7 @@ Begin3 Title: ncpfs -Version: 0.18 -Entered-date: 09. March 1996 +Version: 0.19 +Entered-date: 22. 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 @@ -13,7 +13,7 @@ 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 + ~103k ncpfs-0.19.tgz + ~ 1k ncpfs-0.19.lsm Copying-policy: GPL End diff --git a/util/Makefile b/util/Makefile index 2e87f06..1a5af00 100644 --- a/util/Makefile +++ b/util/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux ncp-filesystem routines. # -USERUTILS = slist pqlist nwfsinfo pserver nprint +USERUTILS = slist pqlist nwfsinfo pserver nprint nsend UIDUTILS = ncpmount ncpumount SBINUTILS = nwmsg @@ -23,25 +23,43 @@ install: all for i in $(SBINUTILS); \ do install $(INTERM_BINDIR)/$$i -m 755 $(SBINDIR); done -$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) ncplib.o - $(CC) -o $@ $(addsuffix .o,$(notdir $@)) ncplib.o +$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) libncp.a + $(CC) -o $@ $(addsuffix .o,$(notdir $@)) -L. -lncp -ncplib.o: ncplib.c ncplib.h +ncplib.o: ncplib.c ncplib.h ncplib_err.h $(CC) $(CFLAGS) -finline-functions -c ncplib.c +COM_ERR_CFILES = com_err/com_err.c com_err/error_message.c com_err/et_name.c \ + com_err/init_et.c + +libncp.a: ncplib.o ncplib_err.o $(COM_ERR_CFILES) + make -C com_err + ar r libncp.a ncplib.o ncplib_err.o \ + com_err/com_err.o com_err/error_message.o com_err/et_name.o \ + com_err/init_et.o + +ncplib_err.h: ncplib_err.et + com_err/compile_et ncplib_err + +ncplib_err.c: ncplib_err.et + com_err/compile_et ncplib_err + test: test.o ncplib.o $(CC) -o test test.o ncplib.o -ncptest: ncptest.o ncplib.o - $(CC) -o ncptest ncptest.o ncplib.o +ncptest: ncptest.o libncp.a + $(CC) -o ncptest ncptest.o -L. -lncp -dep: +dep: ncplib_err.h + make -C com_err dep $(CPP) -M $(INCLUDES) *.c > .depend clean: - rm -f *.o *~ slist test ncptest + make -C com_err clean + rm -f *.o *~ slist test ncptest ncplib_err.[ch] libncp.a -realclean: clean +mrproper: clean + make -C com_err mrproper rm -f $(UTILS) .depend $(DISTFILE) # diff --git a/util/com_err.h b/util/com_err.h new file mode 120000 index 0000000..2f20682 --- /dev/null +++ b/util/com_err.h @@ -0,0 +1 @@ +com_err/com_err.h \ No newline at end of file diff --git a/util/com_err/ChangeLog b/util/com_err/ChangeLog new file mode 100644 index 0000000..de96335 --- /dev/null +++ b/util/com_err/ChangeLog @@ -0,0 +1,49 @@ +Wed Jan 31 11:06:08 1996 + + * Release of E2fsprogs version 1.02 + +Mon Sep 4 21:44:47 1995 Remy Card + + * Makefile.in: Added support for BSD shared libraries. + +Sat Aug 12 03:11:28 1995 Remy Card + + * Makefile.in (install): Install static libraries in $(ulibdir) + (/usr/lib on Linux) instead of $(libdir) (/lib on Linux). + +Sat Aug 5 11:44:17 1995 Theodore Y. Ts'o + + * Makefile.in (DLL_INSTALL_DIR, ELF_INSTALL_DIR): Set the + installation directories correctly. + +Thu Jun 15 23:39:51 1995 Remy Card + + * Makefile.in: Added support for ELF shared libraries. + Fixed typos in the compilation rules. + (distclean): Added compile_et.sh. + +Sat Jun 10 19:56:13 1995 Theodore Y. Ts'o + + * compile_et.sh.in: Use ET_DIR instead of srcdir to determine the + location of the et directory. + +Thu Jun 8 12:45:41 1995 Miles Bader + + * vfprintf.c (vfprintf): Only compile this function if vfprintf + doesn't already exist and _doprnt does. + + * compile_et.sh: Moved to compile_et.sh.in. + + * Makefile.in: Rewritten to conform to GNU coding standards and + support separate compilation directories. + Don't preprocess compile_et.sh, as this is now done by configure. + +Mon Nov 7 21:17:48 1994 Remy Card + + * Makefile: Added a dummy install target in case shared libraries + are not built. + +Thu Sep 8 22:33:33 1994 (tytso@rsx-11) + + * com_err.c (default_com_err_proc): Reversed order of \n\r to make + jik happy. diff --git a/util/com_err/Makefile b/util/com_err/Makefile new file mode 100644 index 0000000..ba2f1a1 --- /dev/null +++ b/util/com_err/Makefile @@ -0,0 +1,25 @@ +# +# Makefile for the com_err library +# + +OBJECTS = com_err.o error_message.o et_name.o init_et.o +CFLAGS = -Wall -O2 + +all: $(OBJECTS) + +dep: + $(CPP) -M $(INCLUDES) *.c > .depend + +clean: + rm -f *.o + +mrproper: clean + rm -f .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/util/com_err/com_err.3 b/util/com_err/com_err.3 new file mode 100644 index 0000000..4b1f970 --- /dev/null +++ b/util/com_err/com_err.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 1988 Massachusetts Institute of Technology, +.\" Student Information Processing Board. All rights reserved. +.\" +.\" $Header: /mit/krb5/.cvsroot/src/util/et/com_err.3,v 1.1 1993/06/03 12:29:34 tytso Exp $ +.\" +.TH COM_ERR 3 "22 Nov 1988" SIPB +.SH NAME +com_err \- common error display routine +.SH SYNOPSIS +.nf + #include +.PP +void com_err (whoami, code, format, ...); + const char *whoami; + long code; + const char *format; +.PP +proc = set_com_err_hook (proc); +.fi +void (* +.I proc +) (const char *, long, const char *, va_list); +.nf +.PP +proc = reset_com_err_hook (); +.PP +void initialize_XXXX_error_table (); +.fi +.SH DESCRIPTION +.I Com_err +displays an error message on the standard error stream +.I stderr +(see +.IR stdio (3S)) +composed of the +.I whoami +string, which should specify the program name or some subportion of +a program, followed by an error message generated from the +.I code +value (derived from +.IR compile_et (1)), +and a string produced using the +.I format +string and any following arguments, in the same style as +.IR fprintf (3). + +The behavior of +.I com_err +can be modified using +.I set_com_err_hook; +this defines a procedure which is called with the arguments passed to +.I com_err, +instead of the default internal procedure which sends the formatted +text to error output. Thus the error messages from a program can all +easily be diverted to another form of diagnostic logging, such as +.IR syslog (3). +.I Reset_com_err_hook +may be used to restore the behavior of +.I com_err +to its default form. Both procedures return the previous ``hook'' +value. These ``hook'' procedures must have the declaration given for +.I proc +above in the synopsis. + +The +.I initialize_XXXX_error_table +routine is generated mechanically by +.IR compile_et (1) +from a source file containing names and associated strings. Each +table has a name of up to four characters, which is used in place of +the +.B XXXX +in the name of the routine. These routines should be called before +any of the corresponding error codes are used, so that the +.I com_err +library will recognize error codes from these tables when they are +used. + +The +.B com_err.h +header file should be included in any source file that uses routines +from the +.I com_err +library; executable files must be linked using +.I ``-lcom_err'' +in order to cause the +.I com_err +library to be included. + +.\" .IR for manual entries +.\" .PP for paragraph breaks + +.SH "SEE ALSO" +compile_et (1), syslog (3). + +Ken Raeburn, "A Common Error Description Library for UNIX". diff --git a/util/com_err/com_err.c b/util/com_err/com_err.c new file mode 100644 index 0000000..8ee332a --- /dev/null +++ b/util/com_err/com_err.c @@ -0,0 +1,114 @@ +/* + * Copyright 1987, 1988 by MIT Student Information Processing Board. + * + * For copyright info, see mit-sipb-copyright.h. + */ + +#include +#include "com_err.h" +#include "mit-sipb-copyright.h" +#include "error_table.h" +#include "internal.h" + +#if !defined(__STDC__) && !defined(STDARG_PROTOTYPES) +#include +#define VARARGS +#endif + +static void +#ifdef __STDC__ + default_com_err_proc (const char *whoami, errcode_t code, const + char *fmt, va_list args) +#else + default_com_err_proc (whoami, code, fmt, args) + const char *whoami; + errcode_t code; + const char *fmt; + va_list args; +#endif +{ + if (whoami) { + fputs(whoami, stderr); + fputs(": ", stderr); + } + if (code) { + fputs(error_message(code), stderr); + fputs(" ", stderr); + } + if (fmt) { + vfprintf (stderr, fmt, args); + } + /* should do this only on a tty in raw mode */ + putc('\r', stderr); + putc('\n', stderr); + fflush(stderr); +} + +#ifdef __STDC__ +typedef void (*errf) (const char *, errcode_t, const char *, va_list); +#else +typedef void (*errf) (); +#endif + +errf com_err_hook = default_com_err_proc; + +#ifdef __STDC__ +void com_err_va (const char *whoami, errcode_t code, const char *fmt, + va_list args) +#else +void com_err_va (whoami, code, fmt, args) + const char *whoami; + errcode_t code; + const char *fmt; + va_list args; +#endif +{ + (*com_err_hook) (whoami, code, fmt, args); +} + +#ifndef VARARGS +void com_err (const char *whoami, + errcode_t code, + const char *fmt, ...) +{ +#else +void com_err (va_alist) + va_dcl +{ + const char *whoami, *fmt; + errcode_t code; +#endif + va_list pvar; + + if (!com_err_hook) + com_err_hook = default_com_err_proc; +#ifdef VARARGS + va_start (pvar); + whoami = va_arg (pvar, const char *); + code = va_arg (pvar, errcode_t); + fmt = va_arg (pvar, const char *); +#else + va_start(pvar, fmt); +#endif + com_err_va (whoami, code, fmt, pvar); + va_end(pvar); +} + +errf set_com_err_hook (new_proc) + errf new_proc; +{ + errf x = com_err_hook; + + if (new_proc) + com_err_hook = new_proc; + else + com_err_hook = default_com_err_proc; + + return x; +} + +errf reset_com_err_hook () { + errf x = com_err_hook; + com_err_hook = default_com_err_proc; + return x; +} diff --git a/util/com_err/com_err.h b/util/com_err/com_err.h new file mode 100644 index 0000000..f28dce8 --- /dev/null +++ b/util/com_err/com_err.h @@ -0,0 +1,40 @@ +/* + * Header file for common error description library. + * + * Copyright 1988, Student Information Processing Board of the + * Massachusetts Institute of Technology. + * + * For copyright and distribution info, see the documentation supplied + * with this package. + */ + +#ifndef __COM_ERR_H + +typedef long errcode_t; + +#ifdef __STDC__ +#include + +/* ANSI C -- use prototypes etc */ +void com_err (const char *, long, const char *, ...); +void com_err_va (const char *whoami, errcode_t code, const char *fmt, + va_list args); +char const *error_message (long); +extern void (*com_err_hook) (const char *, long, const char *, va_list); +void (*set_com_err_hook (void (*) (const char *, long, const char *, va_list))) + (const char *, long, const char *, va_list); +void (*reset_com_err_hook (void)) (const char *, long, const char *, va_list); +int init_error_table(const char * const *msgs, int base, int count); +#else +/* no prototypes */ +void com_err (); +void com_err_va (); +char *error_message (); +extern void (*com_err_hook) (); +void (*set_com_err_hook ()) (); +void (*reset_com_err_hook ()) (); +int init_error_table(); +#endif + +#define __COM_ERR_H +#endif /* ! defined(__COM_ERR_H) */ diff --git a/util/com_err/com_err.texinfo b/util/com_err/com_err.texinfo new file mode 100644 index 0000000..9f103ce --- /dev/null +++ b/util/com_err/com_err.texinfo @@ -0,0 +1,554 @@ +\input texinfo @c -*-texinfo-*- + +@c $Header: /mit/krb5/.cvsroot/src/util/et/com_err.texinfo,v 1.1 1993/06/03 12:29:38 tytso Exp $ +@c $Source: /mit/krb5/.cvsroot/src/util/et/com_err.texinfo,v $ +@c $Locker: $ + +@c Note that although this source file is in texinfo format (more +@c or less), it is not yet suitable for turning into an ``info'' +@c file. Sorry, maybe next time. +@c +@c In order to produce hardcopy documentation from a texinfo file, +@c run ``tex com_err.texinfo'' which will load in texinfo.tex, +@c provided in this distribution. (texinfo.tex is from the Free +@c Software Foundation, and is under different copyright restrictions +@c from the rest of this package.) + +@ifinfo +@barfo +@end ifinfo + +@iftex +@tolerance 10000 + +@c Mutate section headers... +@begingroup + @catcode#=6 + @gdef@secheading#1#2#3{@secheadingi {#3@enspace #1}} +@endgroup +@end iftex + +@setfilename com_err +@settitle A Common Error Description Library for UNIX + +@ifinfo +This file documents the use of the Common Error Description library. + +Copyright (C) 1987, 1988 Student Information Processing Board of the +Massachusetts Institute of Technology. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B. +make no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. + +Note that the file texinfo.tex, provided with this distribution, is from +the Free Software Foundation, and is under different copyright restrictions +from the remainder of this package. + +@end ifinfo + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore + +@setchapternewpage odd + +@titlepage +@center @titlefont{A Common Error Description} +@center @titlefont{Library for UNIX} +@sp 2 +@center Ken Raeburn +@center Bill Sommerfeld +@sp 1 +@center MIT Student Information Processing Board +@sp 3 +@center last updated 1 January 1989 +@center for version 1.2 +@center ***DRAFT COPY ONLY*** + +@vskip 2in + +@center @b{Abstract} + +UNIX has always had a clean and simple system call interface, with a +standard set of error codes passed between the kernel and user +programs. Unfortunately, the same cannot be said of many of the +libraries layered on top of the primitives provided by the kernel. +Typically, each one has used a different style of indicating errors to +their callers, leading to a total hodgepodge of error handling, and +considerable amounts of work for the programmer. This paper describes +a library and associated utilities which allows a more uniform way for +libraries to return errors to their callers, and for programs to +describe errors and exceptional conditions to their users. + +@page +@vskip 0pt plus 1filll + +Copyright @copyright{} 1987, 1988 by the Student Information Processing +Board of the Massachusetts Institute of Technology. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B. +make no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. + +Note that the file texinfo.tex, provided with this distribution, is from +the Free Software Foundation, and is under different copyright restrictions +from the remainder of this package. + +@end titlepage + +@ifinfo +@c should put a menu here someday.... +@end ifinfo + +@page + +@section Why com_err? + +In building application software packages, a programmer often has to +deal with a number of libraries, each of which can use a different +error-reporting mechanism. Sometimes one of two values is returned, +indicating simply SUCCESS or FAILURE, with no description of errors +encountered. Sometimes it is an index into a table of text strings, +where the name of the table used is dependent on the library being +used when the error is generated; since each table starts numbering at +0 or 1, additional information as to the source of the error code is +needed to determine which table to look at. Sometimes no text messages are +supplied at all, and the programmer must supply them at any point at which +he may wish to report error conditions. +Often, a global variable is assigned some value describing the error, but +the programmer has to know in each case whether to look at @code{errno}, +@code{h_errno}, the return value from @code{hes_err()}, or whatever other +variables or routines are specified. +And what happens if something +in the procedure of +examining or reporting the error changes the same variable? + +The package we have developed is an attempt to present a common +error-handling mechanism to manipulate the most common form of error code +in a fashion that does not have the problems listed above. + +A list of up to 256 text messages is supplied to a translator we have +written, along with the three- to four-character ``name'' of the error +table. The library using this error table need only call a routine +generated from this error-table source to make the table ``known'' to the +com_err library, and any error code the library generates can be converted +to the corresponding error message. There is also a default format for +error codes accidentally returned before making the table known, which is +of the form @samp{unknown code foo 32}, where @samp{foo} would be the name +of the table. + +@section Error codes + +Error codes themselves are 32 bit (signed) integers, of which the high +order 24 bits are an identifier of which error table the error code is +from, and the low order 8 bits are a sequential error number within +the table. An error code may thus be easily decomposed into its component +parts. Only the lowest 32 bits of an error code are considered significant +on systems which support wider values. + +Error table 0 is defined to match the UNIX system call error table +(@code{sys_errlist}); this allows @code{errno} values to be used directly +in the library (assuming that @code{errno} is of a type with the same width +as @t{long}). Other error table numbers are formed by compacting together +the first four characters of the error table name. The mapping between +characters in the name and numeric values in the error code are defined in +a system-independent fashion, so that two systems that can pass integral +values between them can reliably pass error codes without loss of meaning; +this should work even if the character sets used are not the same. +(However, if this is to be done, error table 0 should be avoided, since the +local system call error tables may differ.) + +Any variable which is to contain an error code should be declared @t{long}. +The draft proposed American National Standard for C (as of May, 1988) +requires that @t{long} variables be at least 32 bits; any system which does +not support 32-bit @t{long} values cannot make use of this package (nor +much other software that assumes an ANSI-C environment base) without +significant effort. + +@section Error table source file + +The error table source file begins with the declaration of the table name, +as + +@example +error_table @var{tablename} +@end example + +Individual error codes are +specified with + +@example +error_code @var{ERROR_NAME}, @var{"text message"} +@end example + +where @samp{ec} can also be used as a short form of @samp{error_code}. To +indicate the end of the table, use @samp{end}. Thus, a (short) sample +error table might be: + +@example + + error_table dsc + + error_code DSC_DUP_MTG_NAME, + "Meeting already exists" + + ec DSC_BAD_PATH, + "A bad meeting pathname was given" + + ec DSC_BAD_MODES, + "Invalid mode for this access control list" + + end + +@end example + +@section The error-table compiler + +The error table compiler is named @code{compile_et}. It takes one +argument, the pathname of a file (ending in @samp{.et}, e.g., +@samp{dsc_err.et}) containing an error table source file. It parses the +error table, and generates two output files -- a C header file +(@samp{discuss_err.h}) which contains definitions of the numerical values +of the error codes defined in the error table, and a C source file which +should be compiled and linked with the executable. The header file must be +included in the source of a module which wishes to reference the error +codes defined; the object module generated from the C code may be linked in +to a program which wishes to use the printed forms of the error codes. + +This translator accepts a @kbd{-language @var{lang}} argument, which +determines for which language (or language variant) the output should be +written. At the moment, @var{lang} is currently limited to @kbd{ANSI-C} +and @kbd{K&R-C}, and some abbreviated forms of each. Eventually, this will +be extended to include some support for C++. The default is currently +@kbd{K&R-C}, though the generated sources will have ANSI-C code +conditionalized on the symbol @t{__STDC__}. + +@section Run-time support routines + +Any source file which uses the routines supplied with or produced by the +com_err package should include the header file @file{}. It +contains declarations and definitions which may be needed on some systems. +(Some functions cannot be referenced properly without the return type +declarations in this file. Some functions may work properly on most +architectures even without the header file, but relying on this is not +recommended.) + +The run-time support routines and variables provided via this package +include the following: + +@example +void initialize_@var{xxxx}_error_table (void); +@end example + +One of these routines is built by the error compiler for each error table. +It makes the @var{xxxx} error table ``known'' to the error reporting +system. By convention, this routine should be called in the initialization +routine of the @var{xxxx} library. If the library has no initialization +routine, some combination of routines which form the core of the library +should ensure that this routine is called. It is not advised to leave it +the caller to make this call. + +There is no harm in calling this routine more than once. + +@example +#define ERROR_TABLE_BASE_@var{xxxx} @var{nnnnn}L +@end example + +This symbol contains the value of the first error code entry in the +specified table. +This rarely needs be used by the +programmer. + +@example +const char *error_message (long code); +@end example + +This routine returns the character string error message associated +with @code{code}; if this is associated with an unknown error table, or +if the code is associated with a known error table but the code is not +in the table, a string of the form @samp{Unknown code @var{xxxx nn}} is +returned, where @var{xxxx} is the error table name produced by +reversing the compaction performed on the error table number implied +by that error code, and @var{nn} is the offset from that base value. + +Although this routine is available for use when needed, its use should be +left to circumstances which render @code{com_err} (below) unusable. + +@example +void com_err (const char *whoami, /* module reporting error */ + long code, /* error code */ + const char *format, /* format for additional detail */ + ...); /* (extra parameters) */ +@end example + +This routine provides an alternate way to print error messages to +standard error; it allows the error message to be passed in as a +parameter, rather than in an external variable. @emph{Provide grammatical +context for ``message.''} + +If @var{format} is @code{(char *)NULL}, the formatted message will not be +printed. @var{format} may not be omitted. + +@example +#include + +void com_err_va (const char *whoami, + long code, + const char *format, + va_list args); +@end example + +This routine provides an interface, equivalent to @code{com_err} above, +which may be used by higher-level variadic functions (functions which +accept variable numbers of arguments). + +@example +#include + +void (*set_com_err_hook (void (*proc) ())) (); + +void (*@var{proc}) (const char *whoami, long code, va_list args); + +void reset_com_err_hook (); +@end example + +These two routines allow a routine to be dynamically substituted for +@samp{com_err}. After @samp{set_com_err_hook} has been called, +calls to @samp{com_err} will turn into calls to the new hook routine. +@samp{reset_com_err_hook} turns off this hook. This may intended to +be used in daemons (to use a routine which calls @var{syslog(3)}), or +in a window system application (which could pop up a dialogue box). + +If a program is to be used in an environment in which simply printing +messages to the @code{stderr} stream would be inappropriate (such as in a +daemon program which runs without a terminal attached), +@code{set_com_err_hook} may be used to redirect output from @code{com_err}. +The following is an example of an error handler which uses @var{syslog(3)} +as supplied in BSD 4.3: + +@example +#include +#include +#include + +/* extern openlog (const char * name, int logopt, int facility); */ +/* extern syslog (int priority, char * message, ...); */ + +void hook (const char * whoami, long code, + const char * format, va_list args) +@{ + char buffer[BUFSIZ]; + static int initialized = 0; + if (!initialized) @{ + openlog (whoami, + LOG_NOWAIT|LOG_CONS|LOG_PID|LOG_NDELAY, + LOG_DAEMON); + initialized = 1; + @} + vsprintf (buffer, format, args); + syslog (LOG_ERR, "%s %s", error_message (code), buffer); +@} +@end example + +After making the call +@code{set_com_err_hook (hook);}, +any calls to @code{com_err} will result in messages being sent to the +@var{syslogd} daemon for logging. +The name of the program, @samp{whoami}, is supplied to the +@samp{openlog()} call, and the message is formatted into a buffer and +passed to @code{syslog}. + +Note that since the extra arguments to @code{com_err} are passed by +reference via the @code{va_list} value @code{args}, the hook routine may +place any form of interpretation on them, including ignoring them. For +consistency, @code{printf}-style interpretation is suggested, via +@code{vsprintf} (or @code{_doprnt} on BSD systems without full support for +the ANSI C library). + +@section Coding Conventions + +The following conventions are just some general stylistic conventions +to follow when writing robust libraries and programs. Conventions +similar to this are generally followed inside the UNIX kernel and most +routines in the Multics operating system. In general, a routine +either succeeds (returning a zero error code, and doing some side +effects in the process), or it fails, doing minimal side effects; in +any event, any invariant which the library assumes must be maintained. + +In general, it is not in the domain of non user-interface library +routines to write error messages to the user's terminal, or halt the +process. Such forms of ``error handling'' should be reserved for +failures of internal invariants and consistancy checks only, as it +provides the user of the library no way to clean up for himself in the +event of total failure. + +Library routines which can fail should be set up to return an error +code. This should usually be done as the return value of the +function; if this is not acceptable, the routine should return a +``null'' value, and put the error code into a parameter passed by +reference. + +Routines which use the first style of interface can be used from +user-interface levels of a program as follows: + +@example +@{ + if ((code = initialize_world(getuid(), random())) != 0) @{ + com_err("demo", code, + "when trying to initialize world"); + exit(1); + @} + if ((database = open_database("my_secrets", &code))==NULL) @{ + com_err("demo", code, + "while opening my_secrets"); + exit(1); + @} +@} +@end example + +A caller which fails to check the return status is in error. It is +possible to look for code which ignores error returns by using lint; +look for error messages of the form ``foobar returns value which is +sometimes ignored'' or ``foobar returns value which is always +ignored.'' + +Since libraries may be built out of other libraries, it is often necessary +for the success of one routine to depend on another. When a lower level +routine returns an error code, the middle level routine has a few possible +options. It can simply return the error code to its caller after doing +some form of cleanup, it can substitute one of its own, or it can take +corrective action of its own and continue normally. For instance, a +library routine which makes a ``connect'' system call to make a network +connection may reflect the system error code @code{ECONNREFUSED} +(Connection refused) to its caller, or it may return a ``server not +available, try again later,'' or it may try a different server. + +Cleanup which is typically necessary may include, but not be limited +to, freeing allocated memory which will not be needed any more, +unlocking concurrancy locks, dropping reference counts, closing file +descriptors, or otherwise undoing anything which the procedure did up +to this point. When there are a lot of things which can go wrong, it +is generally good to write one block of error-handling code which is +branched to, using a goto, in the event of failure. A common source +of errors in UNIX programs is failing to close file descriptors on +error returns; this leaves a number of ``zombied'' file descriptors +open, which eventually causes the process to run out of file +descriptors and fall over. + +@example +@{ + FILE *f1=NULL, *f2=NULL, *f3=NULL; + int status = 0; + + if ( (f1 = fopen(FILE1, "r")) == NULL) @{ + status = errno; + goto error; + @} + + /* + * Crunch for a while + */ + + if ( (f2 = fopen(FILE2, "w")) == NULL) @{ + status = errno; + goto error; + @} + + if ( (f3 = fopen(FILE3, "a+")) == NULL) @{ + status = errno; + goto error; + @} + + /* + * Do more processing. + */ + fclose(f1); + fclose(f2); + fclose(f3); + return 0; + +error: + if (f1) fclose(f1); + if (f2) fclose(f2); + if (f3) fclose(f3); + return status; +@} +@end example + +@section Building and Installation + +The distribution of this package will probably be done as a compressed +``tar''-format file available via anonymous FTP from SIPB.MIT.EDU. +Retrieve @samp{pub/com_err.tar.Z} and extract the contents. A subdirectory +@t{profiled} should be created to hold objects compiled for profiling. +Running ``make all'' should then be sufficient to build the library and +error-table compiler. The files @samp{libcom_err.a}, +@samp{libcom_err_p.a}, @samp{com_err.h}, and @samp{compile_et} should be +installed for use; @samp{com_err.3} and @samp{compile_et.1} can also be +installed as manual pages. + +Potential problems: + +@itemize @bullet + +@item Use of @code{strcasecmp}, a routine provided in BSD for +case-insensitive string comparisons. If an equivalent routine is +available, you can modify @code{CFLAGS} in the makefile to define +@code{strcasecmp} to the name of that routine. + +@item Compilers that defined @code{__STDC__} without providing the header +file @code{}. One such example is Metaware's High ``C'' +compiler, as provided at Project Athena on the IBM RT/PC workstation; if +@code{__HIGHC__} is defined, it is assumed that @code{} is not +available, and therefore @code{} must be used. If the symbol +@code{VARARGS} is defined (e.g., in the makefile), @code{} will +be used. + +@item If your linker rejects symbols that are simultaneously defined in two +library files, edit @samp{Makefile} to remove @samp{perror.c} from the +library. This file contains a version of @var{perror(3)} which calls +@code{com_err} instead of calling @code{write} directly. + +@end itemize + +As I do not have access to non-BSD systems, there are probably +bugs present that may interfere with building or using this package on +other systems. If they are reported to me, they can probably be fixed for +the next version. + +@section Bug Reports + +Please send any comments or bug reports to the principal author: Ken +Raeburn, @t{Raeburn@@Athena.MIT.EDU}. + +@section Acknowledgements + +I would like to thank: Bill Sommerfeld, for his help with some of this +documentation, and catching some of the bugs the first time around; +Honeywell Information Systems, for not killing off the @emph{Multics} +operating system before I had an opportunity to use it; Honeywell's +customers, who persuaded them not to do so, for a while; Ted Anderson of +CMU, for catching some problems before version 1.2 left the nest; Stan +Zanarotti and several others of MIT's Student Information Processing Board, +for getting us started with ``discuss,'' for which this package was +originally written; and everyone I've talked into --- I mean, asked to read +this document and the ``man'' pages. + +@bye diff --git a/util/com_err/compile_et b/util/com_err/compile_et new file mode 100755 index 0000000..872e147 --- /dev/null +++ b/util/com_err/compile_et @@ -0,0 +1,11 @@ +#!/bin/sh +# +# +AWK=/usr/bin/awk +DIR=com_err/ + +ROOT=`echo $1 | sed -e s/.et$//` +BASE=`basename $ROOT` + +$AWK -f ${DIR}/et_h.awk outfile=${BASE}.h $ROOT.et +$AWK -f ${DIR}/et_c.awk outfile=${BASE}.c $ROOT.et diff --git a/util/com_err/compile_et.1 b/util/com_err/compile_et.1 new file mode 100644 index 0000000..7c96da8 --- /dev/null +++ b/util/com_err/compile_et.1 @@ -0,0 +1,79 @@ +.\" Copyright (c) 1988 Massachusetts Institute of Technology, +.\" Student Information Processing Board. All rights reserved. +.\" +.\" $Header: /mit/krb5/.cvsroot/src/util/et/compile_et.1,v 1.1 1993/06/03 12:29:46 tytso Exp $ +.\" +.TH COMPILE_ET 1 "22 Nov 1988" SIPB +.SH NAME +compile_et \- error table compiler +.SH SYNOPSIS +.B compile_et +file +.SH DESCRIPTION +.B Compile_et +converts a table listing error-code names and associated messages into +a C source file suitable for use with the +.IR com_err (3) +library. + +The source file name must end with a suffix of ``.et''; the file +consists of a declaration supplying the name (up to four characters +long) of the error-code table: + +.B error_table +.I name + +followed by up to 256 entries of the form: + +.B error_code +.I name, +" +.I string +" + +and a final + +.B end + +to indicate the end of the table. + +The name of the table is used to construct the name of a subroutine +.I initialize_XXXX_error_table +which must be called in order for the +.I com_err +library to recognize the error table. + +The various error codes defined are assigned sequentially increasing +numbers (starting with a large number computed as a hash function of +the name of the table); thus for compatibility it is suggested that +new codes be added only to the end of an existing table, and that no +codes be removed from tables. + +The names defined in the table are placed into a C header file with +preprocessor directives defining them as integer constants of up to +32 bits in magnitude. + +A C source file is also generated which should be compiled and linked +with the object files which reference these error codes; it contains +the text of the messages and the initialization subroutine. Both C +files have names derived from that of the original source file, with +the ``.et'' suffix replaced by ``.c'' and ``.h''. + +A ``#'' in the source file is treated as a comment character, and all +remaining text to the end of the source line will be ignored. + +.SH BUGS + +Since +.B compile_et +uses a very simple parser based on +.IR yacc (1), +its error recovery leaves much to be desired. + +.\" .IR for manual entries +.\" .PP for paragraph breaks + +.SH "SEE ALSO" +com_err (3). + +Ken Raeburn, "A Common Error Description Library for UNIX". diff --git a/util/com_err/error_message.c b/util/com_err/error_message.c new file mode 100644 index 0000000..e1c1c3a --- /dev/null +++ b/util/com_err/error_message.c @@ -0,0 +1,82 @@ +/* + * $Header: /mit/krb5/.cvsroot/src/util/et/error_message.c,v 5.0 1993/04/13 19:56:17 tytso Exp $ + * $Source: /mit/krb5/.cvsroot/src/util/et/error_message.c,v $ + * $Locker: $ + * + * Copyright 1987 by the Student Information Processing Board + * of the Massachusetts Institute of Technology + * + * For copyright info, see "mit-sipb-copyright.h". + */ + +#include +#include +#include +#include "com_err.h" +#include "error_table.h" +#include "mit-sipb-copyright.h" +#include "internal.h" + +static char buffer[25]; + +struct et_list * _et_list = (struct et_list *) NULL; + + +#ifdef __STDC__ +const char * error_message (errcode_t code) +#else +const char * error_message (code) + errcode_t code; +#endif +{ + int offset; + struct et_list *et; + int table_num; + int started = 0; + char *cp; + + offset = code & ((1<next) { + if (et->table->base == table_num) { + /* This is the right table */ + if (et->table->n_msgs <= offset) + goto oops; + return(et->table->msgs[offset]); + } + } +oops: + strcpy (buffer, "Unknown code "); + if (table_num) { + strcat (buffer, error_table_name (table_num)); + strcat (buffer, " "); + } + for (cp = buffer; *cp; cp++) + ; + if (offset >= 100) { + *cp++ = '0' + offset / 100; + offset %= 100; + started++; + } + if (started || offset >= 10) { + *cp++ = '0' + offset / 10; + offset %= 10; + } + *cp++ = '0' + offset; + *cp = '\0'; + return(buffer); +} diff --git a/util/com_err/error_table.h b/util/com_err/error_table.h new file mode 100644 index 0000000..31971f0 --- /dev/null +++ b/util/com_err/error_table.h @@ -0,0 +1,35 @@ +/* + * Copyright 1988 by the Student Information Processing Board of the + * Massachusetts Institute of Technology. + * + * For copyright info, see mit-sipb-copyright.h. + */ + +#ifndef _ET_H +/* Are we using ANSI C? */ +#ifndef __STDC__ +#define const +#endif + +struct error_table { + char const * const * msgs; + long base; + int n_msgs; +}; +struct et_list { + struct et_list *next; + const struct error_table *table; +}; +extern struct et_list * _et_list; + +#define ERRCODE_RANGE 8 /* # of bits to shift table number */ +#define BITS_PER_CHAR 6 /* # bits to shift per character in name */ + +#ifdef __STDC__ +extern const char *error_table_name(int num); +#else +extern const char *error_table_name(); +#endif + +#define _ET_H +#endif diff --git a/util/com_err/et_c.awk b/util/com_err/et_c.awk new file mode 100644 index 0000000..e3d4c91 --- /dev/null +++ b/util/com_err/et_c.awk @@ -0,0 +1,185 @@ +BEGIN { +char_shift=64 +## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; +c2n["A"]=1 +c2n["B"]=2 +c2n["C"]=3 +c2n["D"]=4 +c2n["E"]=5 +c2n["F"]=6 +c2n["G"]=7 +c2n["H"]=8 +c2n["I"]=9 +c2n["J"]=10 +c2n["K"]=11 +c2n["L"]=12 +c2n["M"]=13 +c2n["N"]=14 +c2n["O"]=15 +c2n["P"]=16 +c2n["Q"]=17 +c2n["R"]=18 +c2n["S"]=19 +c2n["T"]=20 +c2n["U"]=21 +c2n["V"]=22 +c2n["W"]=23 +c2n["X"]=24 +c2n["Y"]=25 +c2n["Z"]=26 +c2n["a"]=27 +c2n["b"]=28 +c2n["c"]=29 +c2n["d"]=30 +c2n["e"]=31 +c2n["f"]=32 +c2n["g"]=33 +c2n["h"]=34 +c2n["i"]=35 +c2n["j"]=36 +c2n["k"]=37 +c2n["l"]=38 +c2n["m"]=39 +c2n["n"]=40 +c2n["o"]=41 +c2n["p"]=42 +c2n["q"]=43 +c2n["r"]=44 +c2n["s"]=45 +c2n["t"]=46 +c2n["u"]=47 +c2n["v"]=48 +c2n["w"]=49 +c2n["x"]=50 +c2n["y"]=51 +c2n["z"]=52 +c2n["0"]=53 +c2n["1"]=54 +c2n["2"]=55 +c2n["3"]=56 +c2n["4"]=57 +c2n["5"]=58 +c2n["6"]=59 +c2n["7"]=60 +c2n["8"]=61 +c2n["9"]=62 +c2n["_"]=63 +} +/^#/ { next } +/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ { + table_number = 0 + table_name = $2 + mod_base = 1000000 + for(i=1; i<=length(table_name); i++) { + table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)] + } + + # We start playing *_high, *low games here because the some + # awk programs do not have the necessary precision (sigh) + tab_base_low = table_number % mod_base + tab_base_high = int(table_number / mod_base) + tab_base_sign = 1; + + # figure out: table_number_base=table_number*256 + tab_base_low = tab_base_low * 256 + tab_base_high = (tab_base_high * 256) + \ + int(tab_base_low / mod_base) + tab_base_low = tab_base_low % mod_base + + if (table_number > 128*256*256) { + # figure out: table_number_base -= 256*256*256*256 + # sub_high, sub_low is 256*256*256*256 + sub_low = 256*256*256 % mod_base + sub_high = int(256*256*256 / mod_base) + + sub_low = sub_low * 256 + sub_high = (sub_high * 256) + int(sub_low / mod_base) + sub_low = sub_low % mod_base + + tab_base_low = sub_low - tab_base_low; + tab_base_high = sub_high - tab_base_high; + tab_base_sign = -1; + if (tab_base_low < 0) { + tab_base_low = tab_base_low + mod_base + tab_base_high-- + } + } + print "/*" > outfile + print " * " outfile ":" > outfile + print " * This file is automatically generated; please do not edit it." > outfile + print " */" > outfile + + print "#ifdef __STDC__" > outfile + print "#define NOARGS void" > outfile + print "#else" > outfile + print "#define NOARGS" > outfile + print "#define const" > outfile + print "#endif" > outfile + print "" > outfile + print "static const char * const text[] = {" > outfile + table_item_count = 0 +} + +/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*$/ { + skipone=1 + next +} + +/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*"[ \t]*$/ { + text="" + for (i=3; i<=NF; i++) { + text = text FS $i + } + text=substr(text,2,length(text)-1); + printf "\t%s,\n", text > outfile + table_item_count++ +} + +{ + if (skipone) { + printf "\t%s,\n", $0 > outfile + table_item_count++ + } + skipone=0 +} +END { + + + print " 0" > outfile + print "};" > outfile + print "" > outfile + print "struct error_table {" > outfile + print " char const * const * msgs;" > outfile + print " long base;" > outfile + print " int n_msgs;" > outfile + print "};" > outfile + print "struct et_list {" > outfile + print " struct et_list *next;" > outfile + print " const struct error_table * table;" > outfile + print "};" > outfile + print "extern struct et_list *_et_list;" > outfile + print "" > outfile + if (tab_base_high == 0) { + print "static const struct error_table et = { text, " \ + sprintf("%dL, %d };", tab_base_sign*tab_base_low, \ + table_item_count) > outfile + } else { + print "static const struct error_table et = { text, " \ + sprintf("%d%06dL, %d };", tab_base_sign*tab_base_high, \ + tab_base_low, table_item_count) > outfile + } + print "" > outfile + print "static struct et_list link = { 0, 0 };" > outfile + print "" > outfile + print "void initialize_" table_name "_error_table (NOARGS);" > outfile + print "" > outfile + print "void initialize_" table_name "_error_table (NOARGS) {" > outfile + print " if (!link.table) {" > outfile + print " link.next = _et_list;" > outfile + print " link.table = &et;" > outfile + print " _et_list = &link;" > outfile + print " }" > outfile + print "}" > outfile + + +} diff --git a/util/com_err/et_h.awk b/util/com_err/et_h.awk new file mode 100644 index 0000000..d7688e9 --- /dev/null +++ b/util/com_err/et_h.awk @@ -0,0 +1,157 @@ +BEGIN { +char_shift=64 +## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; +c2n["A"]=1 +c2n["B"]=2 +c2n["C"]=3 +c2n["D"]=4 +c2n["E"]=5 +c2n["F"]=6 +c2n["G"]=7 +c2n["H"]=8 +c2n["I"]=9 +c2n["J"]=10 +c2n["K"]=11 +c2n["L"]=12 +c2n["M"]=13 +c2n["N"]=14 +c2n["O"]=15 +c2n["P"]=16 +c2n["Q"]=17 +c2n["R"]=18 +c2n["S"]=19 +c2n["T"]=20 +c2n["U"]=21 +c2n["V"]=22 +c2n["W"]=23 +c2n["X"]=24 +c2n["Y"]=25 +c2n["Z"]=26 +c2n["a"]=27 +c2n["b"]=28 +c2n["c"]=29 +c2n["d"]=30 +c2n["e"]=31 +c2n["f"]=32 +c2n["g"]=33 +c2n["h"]=34 +c2n["i"]=35 +c2n["j"]=36 +c2n["k"]=37 +c2n["l"]=38 +c2n["m"]=39 +c2n["n"]=40 +c2n["o"]=41 +c2n["p"]=42 +c2n["q"]=43 +c2n["r"]=44 +c2n["s"]=45 +c2n["t"]=46 +c2n["u"]=47 +c2n["v"]=48 +c2n["w"]=49 +c2n["x"]=50 +c2n["y"]=51 +c2n["z"]=52 +c2n["0"]=53 +c2n["1"]=54 +c2n["2"]=55 +c2n["3"]=56 +c2n["4"]=57 +c2n["5"]=58 +c2n["6"]=59 +c2n["7"]=60 +c2n["8"]=61 +c2n["9"]=62 +c2n["_"]=63 +} +/^#/ { next } +/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ { + table_number = 0 + table_name = $2 + mod_base = 1000000 + for(i=1; i<=length(table_name); i++) { + table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)] + } + # We start playing *_high, *low games here because the some + # awk programs do not have the necessary precision (sigh) + tab_base_low = table_number % mod_base + tab_base_high = int(table_number / mod_base) + tab_base_sign = 1; + + # figure out: table_number_base=table_number*256 + tab_base_low = tab_base_low * 256 + tab_base_high = (tab_base_high * 256) + \ + int(tab_base_low / mod_base) + tab_base_low = tab_base_low % mod_base + + if (table_number > 128*256*256) { + # figure out: table_number_base -= 256*256*256*256 + # sub_high, sub_low is 256*256*256*256 + sub_low = 256*256*256 % mod_base + sub_high = int(256*256*256 / mod_base) + + sub_low = sub_low * 256 + sub_high = (sub_high * 256) + int(sub_low / mod_base) + sub_low = sub_low % mod_base + + tab_base_low = sub_low - tab_base_low; + tab_base_high = sub_high - tab_base_high; + tab_base_sign = -1; + if (tab_base_low < 0) { + tab_base_low = tab_base_low + mod_base + tab_base_high-- + } + } + curr_low = tab_base_low + curr_high = tab_base_high + curr_sign = tab_base_sign + print "/*" > outfile + print " * " outfile ":" > outfile + print " * This file is automatically generated; please do not edit it." > outfile + print " */" > outfile + print "#ifdef __STDC__" > outfile + print "#define NOARGS void" > outfile + print "#else" > outfile + print "#define NOARGS" > outfile + print "#define const" > outfile + print "#endif" > outfile + print "" > outfile +} + +/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,/ { + tag=substr($2,1,length($2)-1) + if (curr_high == 0) { + printf "#define %-40s (%dL)\n", tag, \ + curr_sign*curr_low > outfile + } else { + printf "#define %-40s (%d%06dL)\n", tag, curr_high*curr_sign, \ + curr_low > outfile + } + curr_low += curr_sign; + if (curr_low >= mod_base) { + curr_low -= mod_base; + curr_high++ + } + if (curr_low < 0) { + cur_low += mod_base + cur_high-- + } +} + +END { + print "extern void initialize_" table_name "_error_table (NOARGS);" > outfile + if (tab_base_high == 0) { + print "#define ERROR_TABLE_BASE_" table_name " (" \ + sprintf("%d", tab_base_sign*tab_base_low) \ + "L)" > outfile + } else { + print "#define ERROR_TABLE_BASE_" table_name " (" \ + sprintf("%d%06d", tab_base_sign*tab_base_high, \ + tab_base_low) "L)" > outfile + } + print "" > outfile + print "/* for compatibility with older versions... */" > outfile + print "#define init_" table_name "_err_tbl initialize_" table_name "_error_table" > outfile + print "#define " table_name "_err_base ERROR_TABLE_BASE_" table_name > outfile +} diff --git a/util/com_err/et_name.c b/util/com_err/et_name.c new file mode 100644 index 0000000..db4099f --- /dev/null +++ b/util/com_err/et_name.c @@ -0,0 +1,36 @@ +/* + * Copyright 1987 by MIT Student Information Processing Board + * + * For copyright info, see mit-sipb-copyright.h. + */ + +#include "error_table.h" +#include "mit-sipb-copyright.h" +#include "internal.h" + +static const char char_set[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; + +static char buf[6]; + +const char * error_table_name(num) + int num; +{ + int ch; + int i; + char *p; + + /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */ + p = buf; + num >>= ERRCODE_RANGE; + /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */ + num &= 077777777; + /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */ + for (i = 4; i >= 0; i--) { + ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1); + if (ch != 0) + *p++ = char_set[ch-1]; + } + *p = '\0'; + return(buf); +} diff --git a/util/com_err/init_et.c b/util/com_err/init_et.c new file mode 100644 index 0000000..4b3b673 --- /dev/null +++ b/util/com_err/init_et.c @@ -0,0 +1,58 @@ +/* + * $Header: /mit/krb5/.cvsroot/src/util/et/init_et.c,v 5.0 1993/04/13 19:56:25 tytso Exp $ + * $Source: /mit/krb5/.cvsroot/src/util/et/init_et.c,v $ + * $Locker: $ + * + * Copyright 1986, 1987, 1988 by MIT Information Systems and + * the MIT Student Information Processing Board. + * + * For copyright info, see mit-sipb-copyright.h. + */ + +#include +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "com_err.h" +#include "error_table.h" +#include "mit-sipb-copyright.h" + +#ifndef __STDC__ +#define const +#endif + +struct foobar { + struct et_list etl; + struct error_table et; +}; + +extern struct et_list * _et_list; + +#ifdef __STDC__ +int init_error_table(const char * const *msgs, int base, int count) +#else +int init_error_table(msgs, base, count) + const char * const * msgs; + int base; + int count; +#endif +{ + struct foobar * new_et; + + if (!base || !count || !msgs) + return 0; + + new_et = (struct foobar *) malloc(sizeof(struct foobar)); + if (!new_et) + return ENOMEM; /* oops */ + new_et->etl.table = &new_et->et; + new_et->et.msgs = msgs; + new_et->et.base = base; + new_et->et.n_msgs= count; + + new_et->etl.next = _et_list; + _et_list = &new_et->etl; + return 0; +} diff --git a/util/com_err/internal.h b/util/com_err/internal.h new file mode 100644 index 0000000..112c016 --- /dev/null +++ b/util/com_err/internal.h @@ -0,0 +1,22 @@ +/* + * internal include file for com_err package + */ +#include "mit-sipb-copyright.h" +#ifndef __STDC__ +#undef const +#define const +#endif + +#include + +#ifdef NEED_SYS_ERRLIST +extern char const * const sys_errlist[]; +extern const int sys_nerr; +#endif + +/* AIX and Ultrix have standard conforming header files. */ +#if !defined(ultrix) && !defined(_AIX) +#ifdef __STDC__ +void perror (const char *); +#endif +#endif diff --git a/util/com_err/mit-sipb-copyright.h b/util/com_err/mit-sipb-copyright.h new file mode 100644 index 0000000..2f7eb29 --- /dev/null +++ b/util/com_err/mit-sipb-copyright.h @@ -0,0 +1,19 @@ +/* + +Copyright 1987, 1988 by the Student Information Processing Board + of the Massachusetts Institute of Technology + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is +hereby granted, provided that the above copyright notice +appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, +and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. +M.I.T. and the M.I.T. S.I.P.B. make no representations about +the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + +*/ + diff --git a/util/ipx_sap_types b/util/ipx_sap_types new file mode 100644 index 0000000..f3e2d3d --- /dev/null +++ b/util/ipx_sap_types @@ -0,0 +1,32 @@ +0001 User +0002 User Group +0003 Print Queue +0004 File Server +0005 Job Server +0006 Gateway +0007 Print Server +0008 Archive Server +0009 Archive Server +000A Job Queue +000B Administration +0021 NAS SNA Gateway +0024 Remote Bridge +0026 Bridge Server +0027 TCP/IP Gateway +002D Time Synchronization VAP +002E Archive Server Dynamic SAP +0047 Advertising Print Server +004B Btrieve VAP 5.0 +0050 Btrieve VAP +0053 Print Queue User +007A TES NetWare for VMS +0098 NetWare Access Server +009A Named Pipe Server +009E Portable NetWare Unix +0107 NetWare 386 +0111 Test Server +0133 NetWare Name Service +0166 NetWare Management +026A NetWare Management +026B Time Server (NetWare 4.0) +0278 NetWare Directory Server (NetWare 4.0) diff --git a/util/ncplib.c b/util/ncplib.c index e72e01b..596eb30 100644 --- a/util/ncplib.c +++ b/util/ncplib.c @@ -6,6 +6,7 @@ */ #include "ncplib.h" +#include "ncplib_err.h" typedef __u8 byte; typedef __u16 word; @@ -30,16 +31,20 @@ extern pid_t wait(int *); #include #include #include +#include -static int +static long ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target); -static int +static long ncp_login_object(struct ncp_conn *conn, const unsigned char *username, int login_type, const unsigned char *password); +static long +ncp_do_close(struct ncp_conn *conn); + void str_upper(char *name) { @@ -49,6 +54,30 @@ str_upper(char *name) } } +#if 0 + +static int debug_level = 5; +static FILE *logfile = stderr; + +static void +dprintf(int level, char *p, ...) +{ + va_list ap; + + if (level > debug_level) + { + return; + } + + va_start(ap, p); + vfprintf(logfile, p, ap); + va_end(ap); + fprintf(logfile, "\n"); + fflush(logfile); +} + +#endif + /* I know it's terrible to include a .c file here, but I want to keep the file nwcrypt.c intact and separate for copyright reasons */ #include "nwcrypt.c" @@ -141,12 +170,13 @@ ipx_assign_node(IPXNode dest, IPXNode src) int ipx_node_equal(IPXNode n1,IPXNode n2) { - return memcmp(n1,n2,sizeof(n1))==0; + return memcmp(n1,n2, IPX_NODE_LEN)==0; } static int ipx_recvfrom(int sock, void *buf, int len, unsigned int flags, - struct sockaddr_ipx *sender, int *addrlen, int timeout) + struct sockaddr_ipx *sender, int *addrlen, int timeout, + long *err) { fd_set rd, wr, ex; struct timeval tv; @@ -160,7 +190,8 @@ ipx_recvfrom(int sock, void *buf, int len, unsigned int flags, if ((result = select(sock+1, &rd, &wr, &ex, &tv)) == -1) { - return result; + *err = errno; + return -1; } if (FD_ISSET(sock, &rd)) @@ -173,19 +204,25 @@ ipx_recvfrom(int sock, void *buf, int len, unsigned int flags, result = -1; errno = ETIMEDOUT; } + if (result < 0) + { + *err = errno; + } return result; } static int -ipx_recv(int sock, void *buf, int len, unsigned int flags, int timeout) +ipx_recv(int sock, void *buf, int len, unsigned int flags, int timeout, + long *err) { struct sockaddr_ipx sender; int addrlen = sizeof(sender); - return ipx_recvfrom(sock, buf, len, flags, &sender, &addrlen, timeout); + return ipx_recvfrom(sock, buf, len, flags, &sender, &addrlen, + timeout, err); } -static int +static long ipx_sap_find_nearest(int server_type, struct sockaddr_ipx *result, char server_name[NCP_BINDERY_NAME_LEN]) { @@ -193,17 +230,14 @@ ipx_sap_find_nearest(int server_type, struct sockaddr_ipx *result, char data[1024]; int sock; int opt; - int res = -1; - int saved_errno; int packets; int len; struct sap_server_ident *ident; - sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX); - if (sock==-1) + if ((sock = socket(AF_IPX,SOCK_DGRAM,PF_IPX)) < 0) { - return -1; + return errno; } opt=1; @@ -243,14 +277,22 @@ ipx_sap_find_nearest(int server_type, struct sockaddr_ipx *result, packets = 5; do { - len = ipx_recv(sock, data, 1024, 0, 1); + long err; + len = ipx_recv(sock, data, 1024, 0, 1, &err); if (len < 66) { packets = packets - 1; continue; } } - while (ntohs(*((__u16 *)data)) != IPX_SAP_NEAREST_RESPONSE); + while ( (ntohs(*((__u16 *)data)) != IPX_SAP_NEAREST_RESPONSE) + && (packets > 0)); + + if (packets == 0) + { + close(sock); + return NCPL_ET_NO_SERVER; + } ident = (struct sap_server_ident *)(data+2); @@ -259,15 +301,13 @@ ipx_sap_find_nearest(int server_type, struct sockaddr_ipx *result, result->sipx_port = ident->server_port; ipx_assign_node(result->sipx_node, ident->server_node); - memcpy(server_name, ident->server_name, sizeof(server_name)); + memcpy(server_name, ident->server_name, sizeof(ident->server_name)); - res = 0; + errno = 0; finished: - saved_errno = errno; close(sock); - errno = saved_errno; - return res; + return errno; } static int @@ -339,6 +379,7 @@ ipx_make_reachable(IPXNet network) packets = 3; do { + long err; int len; if (packets == 0) @@ -348,7 +389,8 @@ ipx_make_reachable(IPXNet network) addrlen = sizeof(struct sockaddr_ipx); - len = ipx_recvfrom(sock, &rip, sizeof(rip),0, sr, &addrlen, 1); + len = ipx_recvfrom(sock, &rip, sizeof(rip),0, sr, &addrlen, 1, + &err); if (len < sizeof(rip)) { @@ -413,11 +455,11 @@ install_wdog(struct ncp_conn *conn) while (1) { - + long err; /* every 120 seconds we look if our parent is still alive */ pktsize = ipx_recvfrom(sock, buf, sizeof(buf), 0, - &sender, &sizeofaddr, 120); + &sender, &sizeofaddr, 120, &err); if (getppid() != parent_pid) { @@ -467,7 +509,7 @@ ncp_unlock_conn(struct ncp_conn *conn) conn->lock = 0; } -static int +static long do_ncp_call(struct ncp_conn *conn, int request_size) { struct ncp_request_header request = @@ -476,6 +518,7 @@ do_ncp_call(struct ncp_conn *conn, int request_size) int result; int retries = 3; int len; + long err; struct ncp_reply_header *r = (struct ncp_reply_header *)&(conn->packet); @@ -490,12 +533,12 @@ do_ncp_call(struct ncp_conn *conn, int request_size) if (result < 0) { - return result; + return errno; } re_select: len = ipx_recv(conn->ncp_sock, - conn->packet, NCP_PACKET_SIZE, 0, 1); + conn->packet, NCP_PACKET_SIZE, 0, 1, &err); if ( (len == sizeof(*r)) && (r->type == NCP_POSITIVE_ACK)) @@ -512,6 +555,10 @@ do_ncp_call(struct ncp_conn *conn, int request_size) conn->reply_size = len; break; } + if (len < 0) + { + return err; + } } return 0; } @@ -546,16 +593,14 @@ ncp_mount_request(struct ncp_conn *conn, int function) conn->ncp_reply_size = result - sizeof(struct ncp_reply_header); - result = reply->completion_code; - - if ((result != 0) && (conn->verbose != 0)) + if ((reply->completion_code != 0) && (conn->verbose != 0)) { - ncp_printf("ncp_request_error: %d\n", result); + ncp_printf("ncp_request_error: %d\n", reply->completion_code); } - return result; + return reply->completion_code == 0 ? 0 : NCPL_ET_REQUEST_ERROR; } -static int +static long ncp_temp_request(struct ncp_conn *conn, int function) { struct ncp_request_header *h @@ -563,7 +608,7 @@ ncp_temp_request(struct ncp_conn *conn, int function) struct ncp_reply_header *r = (struct ncp_reply_header *)&(conn->packet); - int result; + long err; assert_conn_locked(conn); @@ -582,9 +627,9 @@ ncp_temp_request(struct ncp_conn *conn, int function) h->task = 1; h->function = function; - if (do_ncp_call(conn, conn->current_size) != 0) + if ((err = do_ncp_call(conn, conn->current_size)) != 0) { - return -1; + return err; } conn->completion = r->completion_code; @@ -592,16 +637,14 @@ ncp_temp_request(struct ncp_conn *conn, int function) conn->ncp_reply_size = conn->reply_size - sizeof(struct ncp_reply_header); - result = r->completion_code; - - if ((result != 0) && (conn->verbose != 0)) + if ((r->completion_code != 0) && (conn->verbose != 0)) { - ncp_printf("ncp_completion_code: %d\n", result); + ncp_printf("ncp_completion_code: %d\n", r->completion_code); } - return result; + return r->completion_code == 0 ? 0 : NCPL_ET_REQUEST_ERROR; } -static int +static long ncp_connect_addr(struct ncp_conn *conn, const struct sockaddr_ipx *target, int wdog_needed) { @@ -612,25 +655,19 @@ ncp_connect_addr(struct ncp_conn *conn, const struct sockaddr_ipx *target, int addrlen; int ncp_sock, wdog_sock; + long err; conn->is_connected = NOT_CONNECTED; conn->verbose = 0; - ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX); - - if (ncp_sock == -1) + if ((ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX)) == -1) { - perror("open ncp socket"); - return -1; + return errno; } - wdog_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX); - - if (wdog_sock == -1) + if ((wdog_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX)) == -1) { - perror("open wdog socket"); - close(ncp_sock); - return -1; + return errno; } addr.sipx_family = AF_IPX; @@ -644,18 +681,18 @@ ncp_connect_addr(struct ncp_conn *conn, const struct sockaddr_ipx *target, if ( (bind(ncp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) || (getsockname(ncp_sock, (struct sockaddr *)&addr, &addrlen)==-1)) { - perror("bind ncp socket"); + int saved_errno = errno; close(ncp_sock); close(wdog_sock); - return -1; + return saved_errno; } addr.sipx_port = htons(ntohs(addr.sipx_port) + 1); if (bind(wdog_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - perror("bind wdog socket"); + int saved_errno = errno; close(ncp_sock); close(wdog_sock); - return -1; + return saved_errno; } conn->ncp_sock = ncp_sock; @@ -671,17 +708,14 @@ ncp_connect_addr(struct ncp_conn *conn, const struct sockaddr_ipx *target, h->task = 1; h->function = 0; - if (do_ncp_call(conn, sizeof(*h)) != 0) + if ((err = do_ncp_call(conn, sizeof(*h))) != 0) { - if ( (errno != ENETUNREACH) + if ( (err != ENETUNREACH) || (ipx_make_reachable(htonl(target->sipx_network)) != 0) - || (do_ncp_call(conn, sizeof(*h)) != 0)) + || ((err = do_ncp_call(conn, sizeof(*h))) != 0)) { - int saved_errno = errno; - close(ncp_sock); close(wdog_sock); - errno = saved_errno; - return -1; + return err; } } @@ -703,19 +737,19 @@ ncp_connect_addr(struct ncp_conn *conn, const struct sockaddr_ipx *target, || (conn->i.buffer_size < 512) || (conn->i.buffer_size > 1024)) { - ncp_close(conn); + ncp_do_close(conn); return -1; } return 0; } -static int +static long ncp_connect_any(struct ncp_conn *conn, int wdog_needed) { struct sockaddr_ipx addr; char name[NCP_BINDERY_NAME_LEN]; - int result; + long result; if (ipx_sap_find_nearest(IPX_SAP_FILE_SERVER, &addr, name) != 0) { @@ -730,12 +764,279 @@ ncp_connect_any(struct ncp_conn *conn, int wdog_needed) return 0; } +struct sockaddr_ipx * +ncp_find_fileserver(const char *server_name, long *err) +{ + char server[NCP_BINDERY_NAME_LEN]; + char nearest[NCP_BINDERY_NAME_LEN]; + struct nw_property prop; + struct prop_net_address *n_addr = (struct prop_net_address *)∝ + struct ncp_conn conn; + + static struct sockaddr_ipx result; + + initialize_NCPL_error_table(); + if (strlen(server_name) >= sizeof(server)) + { + *err = NCPL_ET_NAMETOOLONG; + return NULL; + } + + strcpy(server, server_name); + str_upper(server); + + if ((*err = ipx_sap_find_nearest(IPX_SAP_FILE_SERVER, + &result, nearest)) != 0) + { + return NULL; + } + + /* We have to ask the nearest server for our wanted server */ + + memzero(conn); + if ((*err = ncp_connect_addr(&conn, &result, 0)) != 0) + { + return NULL; + } + + /* The following optimization should have been done before + ncp_connect_addr. This would be convenient if there was a + simple way to find out whether there is a route to the + server. Parsing /proc/net/ipx_route is not too nice, so we + just connect to the server and immediately disconnect + again. This way we also find out if the server still has + free connection slots. */ + + if (strcmp(server, nearest) == 0) + { + /* Our wanted server answered the SAP GNS request, so + use it */ + ncp_do_close(&conn); + errno = 0; + return &result; + } + + if (ncp_read_property_value(&conn, NCP_BINDERY_FSERVER, server, 1, + "NET_ADDRESS", &prop) != 0) + { + ncp_do_close(&conn); + *err = NCPL_ET_HOST_UNKNOWN; + return NULL; + } + + if ((*err = ncp_do_close(&conn)) != 0) + { + return NULL; + } + + result.sipx_family = AF_IPX; + result.sipx_network = n_addr->network; + result.sipx_port = n_addr->port; + ipx_assign_node(result.sipx_node, n_addr->node); + + return &result; +} + + + + +static long +ncp_open_temporary(struct ncp_conn *conn, + const struct ncp_conn_spec *spec) +{ + struct sockaddr_ipx *addr; + long err; + + if (spec == NULL) + { + return ncp_connect_any(conn, 1); + } + + if ((addr = ncp_find_fileserver(spec->server, &err)) == NULL) + { + return err; + } + + if ((err = ncp_connect_addr(conn, addr, 1)) != 0) + { + return err; + } + + strcpy(conn->server, spec->server); + + if (strlen(spec->user) != 0) + { + if (ncp_login_object(conn, spec->user, spec->login_type, + spec->password) != 0) + { + ncp_do_close(conn); + return EACCES; + } + strcpy(conn->user, spec->user); + } + + return 0; +} + +char * +ncp_find_permanent(const struct ncp_conn_spec *spec) +{ + FILE *mtab; + struct ncp_conn_ent *conn_ent; + char *result = NULL; + int mount_fid; + struct ncp_fs_info i; + + if ((mtab = fopen(MOUNTED, "r")) == NULL) + { + return NULL; + } + + while ((conn_ent = ncp_get_conn_ent(mtab)) != NULL) + { + if (spec != NULL) + { + if ( (conn_ent->uid != spec->uid) + || ( (strlen(spec->server) != 0) + && (strcasecmp(conn_ent->server, + spec->server) != 0)) + || ( (strlen(spec->user) != 0) + && (strcasecmp(conn_ent->user, + spec->user) != 0))) + { + continue; + } + } + + mount_fid = open(conn_ent->mount_point, O_RDONLY, 0); + if (mount_fid < 0) + { + continue; + } + + i.version = NCP_GET_FS_INFO_VERSION; + + if (ioctl(mount_fid, NCP_IOC_GET_FS_INFO, &i) < 0) + { + close(mount_fid); + continue; + } + + close(mount_fid); + result = conn_ent->mount_point; + break; + } + + fclose(mtab); + errno = (result == NULL) ? ENOENT : 0; + return result; +} + static int +ncp_open_permanent(struct ncp_conn *conn, + const struct ncp_conn_spec *spec) +{ + char *mount_point; + + if (conn->is_connected != NOT_CONNECTED) + { + errno = EBUSY; + return -1; + } + + if ((mount_point = ncp_find_permanent(spec)) == NULL) + { + return -1; + } + + if (strlen(mount_point) >= sizeof(conn->mount_point)) + { + errno = ENAMETOOLONG; + return -1; + } + + /* The rest has already been done in ncp_find_permanent, so we + * do not check errors anymore */ + conn->mount_fid = open(mount_point, O_RDONLY, 0); + conn->i.version = NCP_GET_FS_INFO_VERSION; + ioctl(conn->mount_fid, NCP_IOC_GET_FS_INFO, &(conn->i)); + strncpy(conn->server, spec->server, sizeof(conn->server)); + strncpy(conn->user, spec->user, sizeof(conn->user)); + strcpy(conn->mount_point, mount_point); + conn->is_connected = CONN_PERMANENT; + return 0; +} + +struct ncp_conn * +ncp_open(const struct ncp_conn_spec *spec, long *err) +{ + struct ncp_conn *result; + + result = malloc(sizeof(struct ncp_conn)); + + if (result == NULL) + { + *err = ENOMEM; + return NULL; + } + + memzero(*result); + + if (ncp_open_permanent(result, spec) == 0) + { + return result; + } + + if ((*err = ncp_open_temporary(result, spec)) != 0) + { + free(result); + return NULL; + } + return result; +} + + +struct ncp_conn * +ncp_open_mount(const char *mount_point, long *err) +{ + struct ncp_conn *result; + + if (strlen(mount_point) >= sizeof(result->mount_point)) + { + *err = ENAMETOOLONG; + return NULL; + } + + result = malloc(sizeof(struct ncp_conn)); + + if (result == NULL) + { + *err = ENOMEM; + return NULL; + } + + memzero(*result); + + result->is_connected = NOT_CONNECTED; + + result->mount_fid = open(mount_point, O_RDONLY, 0); + if (result->mount_fid < 0) + { + free(result); + *err = ENODEV; + return NULL; + } + strcpy(result->mount_point, mount_point); + result->is_connected = CONN_PERMANENT; + return result; +} + +static long ncp_user_disconnect(struct ncp_conn *conn) { struct ncp_request_header *h = (struct ncp_request_header *)(conn->packet); - int result; + long result; h->type = NCP_DEALLOC_SLOT_REQUEST; @@ -762,11 +1063,11 @@ ncp_user_disconnect(struct ncp_conn *conn) return 0; } - -int -ncp_close(struct ncp_conn *conn) + +static long +ncp_do_close(struct ncp_conn *conn) { - int result = -1; + long result = -1; switch (conn->is_connected) { @@ -787,178 +1088,15 @@ ncp_close(struct ncp_conn *conn) return result; } -int -ncp_open_temporary(struct ncp_conn *conn, - const struct ncp_conn_spec *spec) +long +ncp_close(struct ncp_conn *conn) { - struct ncp_conn temp; - - struct nw_property prop; - struct prop_net_address *n_addr = (struct prop_net_address *)∝ - - struct sockaddr_ipx addr; - - int result; - - if (spec == NULL) - { - return ncp_connect_any(conn, 1); - } - - if (strlen(spec->server) == 0) - { - return -1; - } - - if ((result = ncp_connect_any(&temp, 0)) != 0) - { - return result; - } - - if ((result = ncp_read_property_value(&temp, NCP_BINDERY_FSERVER, - spec->server, 1, "NET_ADDRESS", - &prop)) != 0) - { - ncp_close(&temp); - return result; - } - - if ((result = ncp_close(&temp)) != 0) + long result; + if ((result = ncp_do_close(conn)) != 0) { return result; } - - addr.sipx_family = AF_IPX; - addr.sipx_network = n_addr->network; - addr.sipx_port = n_addr->port; - ipx_assign_node(addr.sipx_node, n_addr->node); - - if ((result = ncp_connect_addr(conn, &addr, 1)) != 0) - { - return result; - } - - strcpy(conn->server, spec->server); - - if (strlen(spec->user) != 0) - { - if (ncp_login_object(conn, spec->user, spec->login_type, - spec->password) != 0) - { - ncp_close(conn); - errno = EACCES; - return -1; - } - strcpy(conn->user, spec->user); - } - - return 0; -} - -static int -ncp_open_permanent(struct ncp_conn *conn, - const struct ncp_conn_spec *spec) -{ - FILE *mtab; - struct ncp_conn_ent *conn_ent; - - if (conn == NULL) - { - errno = EINVAL; - return -1; - } - - if (conn->is_connected != NOT_CONNECTED) - { - errno = EBUSY; - return -1; - } - - if ((mtab = fopen(MOUNTED, "r")) == NULL) - { - return -1; - } - - while ((conn_ent = ncp_get_conn_ent(mtab)) != NULL) - { - if (spec != NULL) - { - if ( (conn_ent->uid != spec->uid) - || ( (strlen(spec->server) != 0) - && (strcasecmp(conn_ent->server, - spec->server) != 0)) - || ( (strlen(spec->user) != 0) - && (strcasecmp(conn_ent->user, - spec->user) != 0))) - { - continue; - } - if (strlen(conn_ent->mount_point) - >= sizeof(conn->mount_point)) - { - continue; - } - } - - conn->mount_fid = open(conn_ent->mount_point, O_RDONLY, 0); - if (conn->mount_fid < 0) - { - continue; - } - - conn->i.version = NCP_GET_FS_INFO_VERSION; - - if (ioctl(conn->mount_fid, NCP_IOC_GET_FS_INFO, &(conn->i))<0) - { - close(conn->mount_fid); - continue; - } - - strncpy(conn->server, conn_ent->server, - sizeof(conn->server)); - strncpy(conn->user, conn_ent->user, - sizeof(conn->user)); - strcpy(conn->mount_point, conn_ent->mount_point); - conn->is_connected = CONN_PERMANENT; - fclose(mtab); - return 0; - } - - fclose(mtab); - return -1; -} - -int -ncp_open(struct ncp_conn *conn, const struct ncp_conn_spec *spec) -{ - if (ncp_open_permanent(conn, spec) != 0) - { - return ncp_open_temporary(conn, spec); - } - return 0; -} - - -int -ncp_open_mount(struct ncp_conn *conn, - const char *mount_point) -{ - conn->is_connected = NOT_CONNECTED; - - if (strlen(mount_point) >= sizeof(conn->mount_point)) - { - errno = ENAMETOOLONG; - return -1; - } - - conn->mount_fid = open(mount_point, O_RDONLY, 0); - if (conn->mount_fid < 0) - { - errno = ENODEV; - return -1; - } - strcpy(conn->mount_point, mount_point); - conn->is_connected = CONN_PERMANENT; + free(conn); return 0; } @@ -1150,7 +1288,7 @@ ncp_fopen_nwc(const char *user, const char *mode) struct ncp_conn_spec * ncp_find_conn_spec(const char *server, const char *user, const char *password, - uid_t uid) + uid_t uid, long *err) { static struct ncp_conn_spec spec; @@ -1159,6 +1297,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, FILE *nwc; struct ncp_conn_spec *nwc_ent; + *err = 0; memzero(spec); spec.uid = getuid(); @@ -1166,6 +1305,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, { if (strlen(server) >= sizeof(spec.server)) { + *err = NCPL_ET_NAMETOOLONG; return NULL; } strcpy(spec.server, server); @@ -1176,6 +1316,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, if (nwc == NULL) { + *err = NCPL_ET_NO_SPEC; return NULL; } @@ -1184,6 +1325,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, if (nwc_ent == NULL) { + *err = NCPL_ET_NO_SPEC; return NULL; } strcpy(spec.server, nwc_ent->server); @@ -1194,6 +1336,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, { if (strlen(user) >= sizeof(spec.user)) { + *err = NCPL_ET_NAMETOOLONG; return NULL; } strcpy(spec.user, user); @@ -1205,7 +1348,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, if (ncp_open_permanent(&conn, &spec) == 0) { - ncp_close(&conn); + ncp_do_close(&conn); return &spec; } @@ -1213,6 +1356,7 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, { if (strlen(password) >= sizeof(spec.password)) { + *err = NCPL_ET_NAMETOOLONG; return NULL; } strcpy(spec.password, password); @@ -1275,10 +1419,9 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password, return &spec; } -int -ncp_initialize_as(struct ncp_conn *conn, - int *argc, char **argv, - int login_necessary, int login_type) +struct ncp_conn * +ncp_initialize_as(int *argc, char **argv, + int login_necessary, int login_type, long *err) { char *server = NULL; char *user = NULL; @@ -1295,6 +1438,7 @@ ncp_initialize_as(struct ncp_conn *conn, if (arg_no+1 >= *argc) { /* No argument to switch */ + errno = EINVAL; return -1; } *target = argv[arg_no+1]; @@ -1312,8 +1456,9 @@ ncp_initialize_as(struct ncp_conn *conn, return 0; } - errno = EINVAL; - memzero(*conn); + initialize_NCPL_error_table(); + + *err = EINVAL; while (i < *argc) { @@ -1329,25 +1474,25 @@ ncp_initialize_as(struct ncp_conn *conn, case 'S': if (get_argument(i, &server) != 0) { - return -1; + return NULL; } continue; case 'U': if (get_argument(i, &user) != 0) { - return -1; + return NULL; } continue; case 'P': if (get_argument(i, &password) != 0) { - return -1; + return NULL; } continue; case 'n': if (get_argument(i, 0) != 0) { - return -1; + return NULL; } password = NWC_NOPASSWORD; continue; @@ -1355,35 +1500,31 @@ ncp_initialize_as(struct ncp_conn *conn, i += 1; } - if (login_necessary == 0) - { - errno = 0; - return ncp_open(conn, NULL); - } - if ((spec = ncp_find_conn_spec(server, user, password, - getuid())) == NULL) + getuid(), err)) == NULL) { - return -1; + return NULL; } - errno = 0; - spec->login_type = login_type; - return ncp_open(conn, spec); + if (login_necessary == 0) + { + spec->user[0] = '\0'; + } + + return ncp_open(spec, err); } -int -ncp_initialize(struct ncp_conn *conn, - int *argc, char **argv, - int login_necessary) +struct ncp_conn * +ncp_initialize(int *argc, char **argv, + int login_necessary, long *err) { - return ncp_initialize_as(conn, argc, argv, login_necessary, - NCP_BINDERY_USER); + return ncp_initialize_as(argc, argv, login_necessary, + NCP_BINDERY_USER, err); } -static int +static long ncp_request(struct ncp_conn *conn, int function) { switch (conn->is_connected) { @@ -1393,7 +1534,7 @@ ncp_request(struct ncp_conn *conn, int function) return ncp_temp_request(conn, function); default: } - return -ENOTCONN; + return ENOTCONN; } /****************************************************************************/ @@ -1544,11 +1685,11 @@ ncp_reply_dword(struct ncp_conn *conn, int offset) /* Here the ncp calls begin */ -static int +static long ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target) { - int result; + long result; ncp_init_request(conn); ncp_add_word(conn, htons(size)); @@ -1565,11 +1706,11 @@ ncp_negotiate_buffersize(struct ncp_conn *conn, } -int +long ncp_get_file_server_description_strings(struct ncp_conn *conn, char target[512]) { - int result; + long result; ncp_init_request_s(conn, 201); @@ -1584,10 +1725,10 @@ ncp_get_file_server_description_strings(struct ncp_conn *conn, return 0; } -int +long ncp_get_file_server_time(struct ncp_conn *conn, time_t *target) { - int result; + long result; ncp_init_request(conn); @@ -1602,15 +1743,14 @@ ncp_get_file_server_time(struct ncp_conn *conn, time_t *target) return 0; } -int -ncp_get_connlist(struct ncp_conn *conn, __u32 last_id, +long +ncp_get_connlist(struct ncp_conn *conn, __u16 object_type, const char *object_name, - int *returned_no, __u16 conn_numbers[256]) + int *returned_no, __u8 conn_numbers[256]) { - int result; + long result; - ncp_init_request_s(conn, 27); - ncp_add_dword(conn, htonl(last_id)); + ncp_init_request_s(conn, 21); ncp_add_word(conn, htons(object_type)); ncp_add_pstring(conn, object_name); @@ -1621,21 +1761,41 @@ ncp_get_connlist(struct ncp_conn *conn, __u32 last_id, } *returned_no = ncp_reply_byte(conn, 0); - memcpy(conn_numbers, ncp_reply_data(conn, 1), - sizeof(__u16) * (*returned_no)); + memcpy(conn_numbers, ncp_reply_data(conn, 1), (*returned_no)); + ncp_unlock_conn(conn); return 0; } +long +ncp_send_broadcast(struct ncp_conn *conn, + __u8 no_conn, const __u8 *connections, + const char *message) +{ + long result; + if (strlen(message) > 58) + { + return NCPL_ET_MSG_TOO_LONG; + } + + ncp_init_request_s(conn, 0); + ncp_add_byte(conn, no_conn); + ncp_add_mem(conn, (char *)(connections), no_conn); + ncp_add_pstring(conn, message); + + result = ncp_request(conn, 21); + ncp_unlock_conn(conn); + return result; +} /* * result is a 8-byte buffer */ -int +long ncp_get_encryption_key(struct ncp_conn *conn, char *target) { - int result; + long result; ncp_init_request_s(conn, 23); @@ -1656,13 +1816,13 @@ ncp_get_encryption_key(struct ncp_conn *conn, return 0; } -int +long ncp_get_bindery_object_id(struct ncp_conn *conn, __u16 object_type, const char *object_name, struct ncp_bindery_object *target) { - int result; + long result; ncp_init_request_s(conn, 53); ncp_add_word(conn, htons(object_type)); ncp_add_pstring(conn, object_name); @@ -1686,12 +1846,12 @@ ncp_get_bindery_object_id(struct ncp_conn *conn, return 0; } -int +long ncp_scan_bindery_object(struct ncp_conn *conn, __u32 last_id, __u16 object_type, char *search_string, struct ncp_bindery_object *target) { - int result; + long result; ncp_init_request_s(conn, 55); ncp_add_dword(conn, htonl(last_id)); ncp_add_word(conn, htons(object_type)); @@ -1715,13 +1875,13 @@ ncp_scan_bindery_object(struct ncp_conn *conn, } -int +long ncp_read_property_value(struct ncp_conn *conn, int object_type, const char *object_name, int segment, const char *prop_name, struct nw_property *target) { - int result; + long result; ncp_init_request_s(conn, 61); ncp_add_word(conn, htons(object_type)); ncp_add_pstring(conn, object_name); @@ -1740,7 +1900,7 @@ ncp_read_property_value(struct ncp_conn *conn, return 0; } -int +long ncp_login_encrypted(struct ncp_conn *conn, const struct ncp_bindery_object *object, const unsigned char *key, @@ -1749,7 +1909,7 @@ ncp_login_encrypted(struct ncp_conn *conn, dword tmpID = htonl(object->object_id); unsigned char buf[128]; unsigned char encrypted[8]; - int result; + long result; shuffle((byte *)&tmpID, passwd, strlen(passwd), buf); nw_encrypt(key, buf, encrypted); @@ -1759,16 +1919,12 @@ ncp_login_encrypted(struct ncp_conn *conn, ncp_add_word(conn, htons(object->object_type)); ncp_add_pstring(conn, object->object_name); - if ((result = ncp_request(conn, 23)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 23); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_login_user(struct ncp_conn *conn, const unsigned char *username, const unsigned char *password) @@ -1776,13 +1932,13 @@ ncp_login_user(struct ncp_conn *conn, return ncp_login_object(conn, username, NCP_BINDERY_USER, password); } -static int +static long ncp_login_object(struct ncp_conn *conn, const unsigned char *username, int login_type, const unsigned char *password) { - int result; + long result; unsigned char ncp_key[8]; struct ncp_bindery_object user; @@ -1802,13 +1958,11 @@ ncp_login_object(struct ncp_conn *conn, return 0; } - - -int +long ncp_get_volume_info_with_number(struct ncp_conn *conn, int n, struct ncp_volume_info *target) { - int result; + long result; int len; ncp_init_request_s(conn, 44); @@ -1841,10 +1995,10 @@ ncp_get_volume_info_with_number(struct ncp_conn *conn, int n, return 0; } -int +long ncp_get_volume_number(struct ncp_conn *conn, const char *name, int *target) { - int result; + long result; ncp_init_request_s(conn, 5); ncp_add_pstring(conn, name); @@ -1860,12 +2014,12 @@ ncp_get_volume_number(struct ncp_conn *conn, const char *name, int *target) } -int +long ncp_file_search_init(struct ncp_conn *conn, int dir_handle, const char *path, struct ncp_filesearch_info *target) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, dir_handle); @@ -1885,13 +2039,13 @@ ncp_file_search_init(struct ncp_conn *conn, } -int +long ncp_file_search_continue(struct ncp_conn *conn, struct ncp_filesearch_info *fsinfo, int attributes, const char *name, struct ncp_file_info *target) { - int result; + long result; ncp_init_request(conn); @@ -1925,12 +2079,12 @@ ncp_file_search_continue(struct ncp_conn *conn, return 0; } -int +long ncp_get_finfo(struct ncp_conn *conn, int dir_handle, const char *path, const char *name, struct ncp_file_info *target) { - int result; + long result; struct ncp_filesearch_info fsinfo; @@ -1952,13 +2106,13 @@ ncp_get_finfo(struct ncp_conn *conn, return ncp_file_search_continue(conn, &fsinfo, aDIR, name, target); } -int +long ncp_open_file(struct ncp_conn *conn, int dir_handle, const char *path, int attr, int access, struct ncp_file_info *target) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, dir_handle); @@ -1990,22 +2144,18 @@ ncp_open_file(struct ncp_conn *conn, return 0; } -int +long ncp_close_file(struct ncp_conn *conn, const char *file_id) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, 0); ncp_add_mem(conn, file_id, 6); - if ((result = ncp_request(conn, 66)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 66); ncp_unlock_conn(conn); - return 0; + return result; } static int @@ -2015,7 +2165,7 @@ ncp_do_create(struct ncp_conn *conn, struct ncp_file_info *target, int function) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, dir_handle); @@ -2046,7 +2196,7 @@ ncp_do_create(struct ncp_conn *conn, return 0; } -int +long ncp_create_newfile(struct ncp_conn *conn, int dir_handle, const char *path, int attr, @@ -2055,7 +2205,7 @@ ncp_create_newfile(struct ncp_conn *conn, return ncp_do_create(conn, dir_handle, path, attr, target, 77); } -int +long ncp_create_file(struct ncp_conn *conn, int dir_handle, const char *path, int attr, @@ -2064,34 +2214,30 @@ ncp_create_file(struct ncp_conn *conn, return ncp_do_create(conn, dir_handle, path, attr, target, 67); } -int +long ncp_erase_file(struct ncp_conn *conn, int dir_handle, const char *path, int attr) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, dir_handle); ncp_add_byte(conn, attr); ncp_add_pstring(conn, path); - if ((result = ncp_request(conn, 68)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 68); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_rename_file(struct ncp_conn *conn, int old_handle, const char *old_path, int attr, int new_handle, const char *new_path) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, old_handle); @@ -2109,69 +2255,56 @@ ncp_rename_file(struct ncp_conn *conn, return 0; } -int +long ncp_create_directory(struct ncp_conn *conn, int dir_handle, const char *path, int inherit_mask) { - int result; + long result; ncp_init_request_s(conn, 10); ncp_add_byte(conn, dir_handle); ncp_add_byte(conn, inherit_mask); ncp_add_pstring(conn, path); - if ((result = ncp_request(conn, 22)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 22); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_delete_directory(struct ncp_conn *conn, int dir_handle, const char *path) { - int result; + long result; ncp_init_request_s(conn, 11); ncp_add_byte(conn, dir_handle); - ncp_add_byte(conn, 0); /* reserved */ + ncp_add_byte(conn, 0); /* reserved */ ncp_add_pstring(conn, path); - if ((result = ncp_request(conn, 22)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 22); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_rename_directory(struct ncp_conn *conn, int dir_handle, const char *old_path, const char *new_path) { - int result; + long result; ncp_init_request_s(conn, 15); ncp_add_byte(conn, dir_handle); ncp_add_pstring(conn, old_path); ncp_add_pstring(conn, new_path); - if ((result = ncp_request(conn, 22)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 22); ncp_unlock_conn(conn); - return 0; + return result; } - static void ncp_add_handle_path(struct ncp_conn *conn, __u8 vol_num, @@ -2209,7 +2342,7 @@ ncp_extract_file_info(void *structure, struct nw_info_struct *target) return; } -int +long ncp_do_lookup(struct ncp_conn *conn, struct nw_info_struct *dir, char *path, /* may only be one component */ @@ -2217,7 +2350,7 @@ ncp_do_lookup(struct ncp_conn *conn, { __u8 vol_num; __u32 dir_base; - int result; + long result; char *volname = NULL; if (target == NULL) { @@ -2278,18 +2411,18 @@ ncp_do_lookup(struct ncp_conn *conn, return 0; } -int +long ncp_modify_file_or_subdir_dos_info(struct ncp_conn *conn, struct nw_info_struct *file, __u32 info_mask, struct nw_modify_dos_info *info) { - int result; + long result; ncp_init_request(conn); - ncp_add_byte(conn, 7); /* subfunction */ - ncp_add_byte(conn, 0); /* dos name space */ - ncp_add_byte(conn, 0); /* reserved */ + ncp_add_byte(conn, 7); /* subfunction */ + ncp_add_byte(conn, 0); /* dos name space */ + ncp_add_byte(conn, 0); /* reserved */ ncp_add_word(conn, 0x8006); /* search attribs: all */ ncp_add_dword(conn, info_mask); @@ -2297,38 +2430,28 @@ ncp_modify_file_or_subdir_dos_info(struct ncp_conn *conn, ncp_add_handle_path(conn, file->volNumber, file->DosDirNum, 1, NULL); - if ((result = ncp_request(conn, 87)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 87); ncp_unlock_conn(conn); - return 0; + return result; } - - -int +long ncp_del_file_or_subdir(struct ncp_conn *conn, struct nw_info_struct *dir, char *name) { - int result; + long result; ncp_init_request(conn); - ncp_add_byte(conn, 8); /* subfunction */ - ncp_add_byte(conn, 0); /* dos name space */ - ncp_add_byte(conn, 0); /* reserved */ + ncp_add_byte(conn, 8); /* subfunction */ + ncp_add_byte(conn, 0); /* dos name space */ + ncp_add_byte(conn, 0); /* reserved */ ncp_add_word(conn, 0x8006); /* search attribs: all */ ncp_add_handle_path(conn, dir->volNumber, dir->DosDirNum, 1, name); - if ((result = ncp_request(conn, 87)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 87); ncp_unlock_conn(conn); - return 0; + return result; } static inline void @@ -2340,7 +2463,7 @@ ConvertToNWfromDWORD ( __u32 sfd , __u8 ret[6] ) return; } -int +long ncp_open_create_file_or_subdir(struct ncp_conn *conn, struct nw_info_struct *dir, char *name, int open_create_mode, @@ -2348,7 +2471,7 @@ ncp_open_create_file_or_subdir(struct ncp_conn *conn, int desired_acc_rights, struct nw_file_info *target) { - int result; + long result; target->opened = 0; @@ -2380,13 +2503,13 @@ ncp_open_create_file_or_subdir(struct ncp_conn *conn, return 0; } -int +long ncp_initialize_search(struct ncp_conn *conn, const struct nw_info_struct *dir, int namespace, struct ncp_search_seq *target) { - int result; + long result; if ((namespace < 0) || (namespace > 255)) { @@ -2415,12 +2538,12 @@ ncp_initialize_search(struct ncp_conn *conn, } /* Search for everything */ -int +long ncp_search_for_file_or_subdir(struct ncp_conn *conn, struct ncp_search_seq *seq, struct nw_info_struct *target) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, 3); /* subfunction */ @@ -2445,12 +2568,12 @@ ncp_search_for_file_or_subdir(struct ncp_conn *conn, return 0; } -int +long ncp_ren_or_mov_file_or_subdir(struct ncp_conn *conn, struct nw_info_struct *old_dir, char *old_name, struct nw_info_struct *new_dir, char *new_name) { - int result; + long result; if ( (old_dir == NULL) || (old_name == NULL) || (new_dir == NULL) || (new_name == NULL)) @@ -2486,12 +2609,12 @@ ncp_ren_or_mov_file_or_subdir(struct ncp_conn *conn, /* Create a new job entry */ -int +long ncp_create_queue_job_and_file(struct ncp_conn *conn, __u32 queue_id, struct queue_job *job) { - int result; + long result; ncp_init_request_s(conn, 121); ncp_add_dword(conn, htonl(queue_id)); @@ -2509,68 +2632,55 @@ ncp_create_queue_job_and_file(struct ncp_conn *conn, return 0; } -int +long ncp_close_file_and_start_job(struct ncp_conn *conn, __u32 queue_id, struct queue_job *job) { - int result; + long result; ncp_init_request_s(conn, 127); ncp_add_dword(conn, htonl(queue_id)); ncp_add_dword(conn, job->j.JobNumber); - if ((result = ncp_request(conn, 23)) != 0) { - ncp_unlock_conn(conn); - return result; - } - + result = ncp_request(conn, 23); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_attach_to_queue(struct ncp_conn *conn, __u32 queue_id) { - int result; + long 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; - } - + result = ncp_request(conn, 23); ncp_unlock_conn(conn); - return 0; + return result; } - -int +long ncp_detach_from_queue(struct ncp_conn *conn, __u32 queue_id) { - int result; + long 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; - } - + result = ncp_request(conn, 23); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type, struct queue_job *job) { - int result; + long result; ncp_init_request_s(conn, 124); ncp_add_dword(conn, htonl(queue_id)); @@ -2588,52 +2698,43 @@ ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type, return 0; } -int +long ncp_finish_servicing_job(struct ncp_conn *conn, __u32 queue_id, __u32 job_number, __u32 charge_info) { - int result; + long 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; - } - + result = ncp_request(conn, 23); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_abort_servicing_job(struct ncp_conn *conn, __u32 queue_id, __u32 job_number) { - int result; + long 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; - } - + result = ncp_request(conn, 23); ncp_unlock_conn(conn); - return 0; + return result; } - static int ncp_do_read(struct ncp_conn *conn, const char *file_id, __u32 offset, __u16 to_read, char *target, int *bytes_read) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, 0); @@ -2654,7 +2755,7 @@ ncp_do_read(struct ncp_conn *conn, const char *file_id, return 0; } -int +long ncp_read(struct ncp_conn *conn, const char *file_id, off_t offset, size_t count, char *target) { @@ -2690,7 +2791,7 @@ ncp_do_write(struct ncp_conn *conn, const char *file_id, __u32 offset, __u16 to_write, const char *source, int *bytes_written) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, 0); @@ -2710,7 +2811,7 @@ ncp_do_write(struct ncp_conn *conn, const char *file_id, return 0; } -int +long ncp_write(struct ncp_conn *conn, const char *file_id, off_t offset, size_t count, const char *source) { @@ -2741,7 +2842,7 @@ ncp_write(struct ncp_conn *conn, const char *file_id, return already_written; } -int +long ncp_copy_file(struct ncp_conn *conn, const char source_file[6], const char target_file[6], @@ -2750,7 +2851,7 @@ ncp_copy_file(struct ncp_conn *conn, __u32 count, __u32 *copied_count) { - int result; + long result; ncp_init_request(conn); @@ -2772,10 +2873,10 @@ ncp_copy_file(struct ncp_conn *conn, return 0; } -int +long ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]) { - int result; + long result; int length; ncp_init_request_s(conn, 1); @@ -2793,30 +2894,26 @@ ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]) return 0; } -int +long ncp_dealloc_dir_handle(struct ncp_conn *conn, __u8 dir_handle) { - int result; + long 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; - } + result = ncp_request(conn, 22); ncp_unlock_conn(conn); - return 0; + return result; } -int +long ncp_alloc_short_dir_handle(struct ncp_conn *conn, struct nw_info_struct *dir, word alloc_mode, byte *target) { - int result; + long result; ncp_init_request(conn); ncp_add_byte(conn, 12); /* subfunction */ diff --git a/util/ncplib.h b/util/ncplib.h index 1352706..1115237 100644 --- a/util/ncplib.h +++ b/util/ncplib.h @@ -17,6 +17,7 @@ #include #include "ipxlib.h" +#include "com_err.h" #ifndef memzero #include @@ -83,41 +84,37 @@ struct ncp_search_seq { the argument list, opens the connection and removes the arguments from the list. It was designed after the X Windows init functions. */ -int -ncp_initialize(struct ncp_conn *conn, - int *argc, char **argv, - int login_necessary); +struct ncp_conn * +ncp_initialize(int *argc, char **argv, + int login_necessary, long *err); /* You can login as another object by this procedure. As a first use pserver comes to mind. */ -int -ncp_initialize_as(struct ncp_conn *conn, - int *argc, char **argv, - int login_necessary, int login_type); +struct ncp_conn * +ncp_initialize_as(int *argc, char **argv, + int login_necessary, int login_type, long *err); /* Open an existing permanent connection */ -int -ncp_open(struct ncp_conn *conn, - const struct ncp_conn_spec *spec); +struct ncp_conn * +ncp_open(const struct ncp_conn_spec *spec, long *err); /* Open a connection on an existing mount point */ -int -ncp_open_mount(struct ncp_conn *conn, - const char *mount_point); +struct ncp_conn * +ncp_open_mount(const char *mount_point, long *err); -/* Detach from and destroy a permanent connection */ -int -ncp_destroy_permanent(struct ncp_conn *conn); +/* Find a permanent connection that fits the spec, return NULL if + * there is none. */ +char * +ncp_find_permanent(const struct ncp_conn_spec *spec); -/* Create a temporary connection */ -int -ncp_open_temporary(struct ncp_conn *conn, - const struct ncp_conn_spec *spec); +/* Find the address of a file server */ +struct sockaddr_ipx * +ncp_find_fileserver(const char *server_name, long *err); /* Detach from a permanent connection or destroy a temporary connection */ -int +long ncp_close(struct ncp_conn *conn); /* like getmntent, get_ncp_conn_ent scans /etc/mtab for usable @@ -140,124 +137,129 @@ ncp_get_conn_ent(FILE *filep); struct ncp_conn_spec * ncp_find_conn_spec(const char *server, const char *user, const char *password, - uid_t uid); + uid_t uid, long *err); -int +long ncp_get_file_server_description_strings(struct ncp_conn *conn, char target[512]); -int +long ncp_get_file_server_time(struct ncp_conn *conn, time_t *target); -int -ncp_get_connlist(struct ncp_conn *conn, __u32 last_id, +long +ncp_get_connlist(struct ncp_conn *conn, __u16 object_type, const char *object_name, - int *returned_no, __u16 conn_numbers[256]); + int *returned_no, __u8 conn_numbers[256]); -int +long +ncp_send_broadcast(struct ncp_conn *conn, + __u8 no_conn, const __u8 *connections, + const char *message); + +long ncp_get_encryption_key(struct ncp_conn *conn, char *target); -int +long ncp_get_bindery_object_id(struct ncp_conn *conn, __u16 object_type, const char *object_name, struct ncp_bindery_object *target); -int +long ncp_scan_bindery_object(struct ncp_conn *conn, __u32 last_id, __u16 object_type, char *search_string, struct ncp_bindery_object *target); -int +long ncp_read_property_value(struct ncp_conn *conn, int object_type, const char *object_name, int segment, const char *prop_name, struct nw_property *target); -int +long ncp_login_encrypted(struct ncp_conn *conn, const struct ncp_bindery_object *object, const unsigned char *key, const unsigned char *passwd); -int +long ncp_login_user(struct ncp_conn *conn, const unsigned char *username, const unsigned char *password); -int +long ncp_get_volume_info_with_number(struct ncp_conn *conn, int n, struct ncp_volume_info *target); -int +long ncp_get_volume_number(struct ncp_conn *conn, const char *name, int *target); -int +long ncp_file_search_init(struct ncp_conn *conn, int dir_handle, const char *path, struct ncp_filesearch_info *target); -int +long ncp_file_search_continue(struct ncp_conn *conn, struct ncp_filesearch_info *fsinfo, int attributes, const char *path, struct ncp_file_info *target); -int +long ncp_get_finfo(struct ncp_conn *conn, int dir_handle, const char *path, const char *name, struct ncp_file_info *target); -int +long ncp_open_file(struct ncp_conn *conn, int dir_handle, const char *path, int attr, int access, struct ncp_file_info *target); -int +long ncp_close_file(struct ncp_conn *conn, const char *file_id); -int +long ncp_create_newfile(struct ncp_conn *conn, int dir_handle, const char *path, int attr, struct ncp_file_info *target); -int +long ncp_create_file(struct ncp_conn *conn, int dir_handle, const char *path, int attr, struct ncp_file_info *target); -int +long ncp_erase_file(struct ncp_conn *conn, int dir_handle, const char *path, int attr); -int +long ncp_rename_file(struct ncp_conn *conn, int old_handle, const char *old_path, int attr, int new_handle, const char *new_path); -int +long ncp_create_directory(struct ncp_conn *conn, int dir_handle, const char *path, int inherit_mask); -int +long ncp_delete_directory(struct ncp_conn *conn, int dir_handle, const char *path); -int +long ncp_rename_directory(struct ncp_conn *conn, int dir_handle, const char *old_path, const char *new_path); -int +long ncp_read(struct ncp_conn *conn, const char *file_id, off_t offset, size_t count, char *target); -int +long ncp_write(struct ncp_conn *conn, const char *file_id, off_t offset, size_t count, const char *source); -int +long ncp_copy_file(struct ncp_conn *conn, const char source_file[6], const char target_file[6], @@ -266,24 +268,24 @@ ncp_copy_file(struct ncp_conn *conn, __u32 count, __u32 *copied_count); -int +long ncp_do_lookup(struct ncp_conn *conn, struct nw_info_struct *dir, char *path, /* may only be one component */ struct nw_info_struct *target); -int +long ncp_modify_file_or_subdir_dos_info(struct ncp_conn *conn, struct nw_info_struct *file, __u32 info_mask, struct nw_modify_dos_info *info); -int +long ncp_del_file_or_subdir(struct ncp_conn *conn, struct nw_info_struct *dir, char *name); -int +long ncp_open_create_file_or_subdir(struct ncp_conn *conn, struct nw_info_struct *dir, char *name, int open_create_mode, @@ -291,63 +293,63 @@ ncp_open_create_file_or_subdir(struct ncp_conn *conn, int desired_acc_rights, struct nw_file_info *target); -int +long ncp_initialize_search(struct ncp_conn *conn, const struct nw_info_struct *dir, int namespace, struct ncp_search_seq *target); -int +long ncp_search_for_file_or_subdir(struct ncp_conn *conn, struct ncp_search_seq *seq, struct nw_info_struct *target); -int +long ncp_ren_or_mov_file_or_subdir(struct ncp_conn *conn, struct nw_info_struct *old_dir, char *old_name, struct nw_info_struct *new_dir, char *new_name); -int +long ncp_create_queue_job_and_file(struct ncp_conn *conn, __u32 queue_id, struct queue_job *job); -int +long ncp_close_file_and_start_job(struct ncp_conn *conn, __u32 queue_id, struct queue_job *job); -int +long ncp_attach_to_queue(struct ncp_conn *conn, __u32 queue_id); -int +long ncp_detach_from_queue(struct ncp_conn *conn, __u32 queue_id); -int +long ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type, struct queue_job *job); -int +long ncp_finish_servicing_job(struct ncp_conn *conn, __u32 queue_id, __u32 job_number, __u32 charge_info); -int +long ncp_abort_servicing_job(struct ncp_conn *conn, __u32 queue_id, __u32 job_number); -int +long ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]); -int +long ncp_dealloc_dir_handle(struct ncp_conn *conn, __u8 dir_handle); #define NCP_ALLOC_PERMANENT (0x0000) #define NCP_ALLOC_TEMPORARY (0x0001) #define NCP_ALLOC_SPECIAL (0x0002) -int +long ncp_alloc_short_dir_handle(struct ncp_conn *conn, struct nw_info_struct *dir, __u16 alloc_mode, diff --git a/util/ncplib_err.et b/util/ncplib_err.et new file mode 100644 index 0000000..5f7f691 --- /dev/null +++ b/util/ncplib_err.et @@ -0,0 +1,21 @@ +error_table NCPL + +ec NCPL_ET_NO_SERVER, + "No server found" + +ec NCPL_ET_HOST_UNKNOWN, + "Server Unknown" + +ec NCPL_ET_REQUEST_ERROR, + "NCP Request returned error code" + +ec NCPL_ET_NAMETOOLONG, + "Name too long" + +ec NCPL_ET_MSG_TOO_LONG, + "Message too long" + +ec NCPL_ET_NO_SPEC, + "Could not find valid connection spec" + +end \ No newline at end of file diff --git a/util/ncpmount.c b/util/ncpmount.c index 697cdb2..16c60c3 100644 --- a/util/ncpmount.c +++ b/util/ncpmount.c @@ -45,6 +45,7 @@ extern pid_t waitpid(pid_t, int *, int); #include #include #include "ncplib.h" +#include "com_err.h" static char *progname; static void usage(void); @@ -153,9 +154,11 @@ main(int argc, char *argv[]) int fd, result; struct sockaddr_ipx addr; + struct sockaddr_ipx *server_addr; int addrlen; int upcase_password; + long err; int um; unsigned int flags; @@ -163,6 +166,7 @@ main(int argc, char *argv[]) char mount_point[MAXPATHLEN]; struct mntent ment; FILE *mtab; + char *tmp_mount; char *server = NULL; char *user = NULL; @@ -171,13 +175,13 @@ main(int argc, char *argv[]) uid_t conn_uid = getuid(); - struct ncp_conn conn; + struct ncp_conn *conn; int opt; progname = argv[0]; - memzero(data); memzero(spec); memzero(conn); + memzero(data); memzero(spec); if (geteuid() != 0) { @@ -317,10 +321,10 @@ main(int argc, char *argv[]) } } - if ((spec = ncp_find_conn_spec(server, user, password, data.uid)) + if ((spec = ncp_find_conn_spec(server, user, password, data.uid, &err)) == NULL) { - fprintf(stderr, "Could not find valid server/user\n"); + com_err(progname, err, "in find_conn_spec"); exit(1); } @@ -376,32 +380,28 @@ main(int argc, char *argv[]) data.dir_mode |= S_IXOTH; } - if (ncp_open(&conn, spec) != 0) + if ((tmp_mount = ncp_find_permanent(spec)) != NULL) { - fprintf(stderr, "could not connect to server %s: %s\n", - server, strerror(errno)); - exit(1); - } - if (conn.is_connected == CONN_PERMANENT) - { fprintf(stderr, "You already have mounted server %s\nas user " "%s\non mount point %s\n", spec->server, spec->user, - conn.mount_point); - ncp_close(&conn); + tmp_mount); exit(1); } - data.serv_addr = conn.i.addr; - - ncp_close(&conn); + if ((server_addr = ncp_find_fileserver(spec->server, &err)) == NULL) + { + com_err("ncpmount", err, "when trying to find %s", + spec->server); + exit(1); + } + data.serv_addr = *server_addr; data.ncp_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX); if (data.ncp_fd == -1) { - fprintf(stderr, "could not open ncp socket: %s\n", - strerror(errno)); + com_err("ncpmount", err, "opening ncp_socket"); exit(1); } @@ -472,7 +472,11 @@ main(int argc, char *argv[]) flags = MS_MGC_VAL; - result = mount(NULL, mount_point, "ncpfs", flags, (char *)&data); + strcpy(mount_name, spec->server); + strcat(mount_name, "/"); + strcat(mount_name, spec->user); + + result = mount(mount_name, mount_point, "ncpfs", flags, (char *)&data); if (result < 0) { @@ -480,20 +484,17 @@ main(int argc, char *argv[]) exit(1); } - if ( (ncp_open_mount(&conn, mount_point) != 0) - || (ncp_login_user(&conn, spec->user, spec->password) != 0) - || (ioctl(conn.mount_fid, NCP_IOC_CONN_LOGGED_IN, NULL) != 0)) + if ( ((conn = ncp_open_mount(mount_point, &err)) == NULL) + || ((err = ncp_login_user(conn, spec->user, spec->password)) != 0) + || ((err = ioctl(conn->mount_fid, NCP_IOC_CONN_LOGGED_IN, + NULL)) != 0)) { - fprintf(stderr, "%s: login failed\n", strerror(errno)); - ncp_close(&conn); + com_err("ncpmount", err, "in login"); + ncp_close(conn); umount(mount_point); exit(1); } - ncp_close(&conn); - - strcpy(mount_name, spec->server); - strcat(mount_name, "/"); - strcat(mount_name, spec->user); + ncp_close(conn); ment.mnt_fsname = mount_name; ment.mnt_dir = mount_point; diff --git a/util/ncptest.c b/util/ncptest.c index 54637a6..ad9a268 100644 --- a/util/ncptest.c +++ b/util/ncptest.c @@ -38,115 +38,35 @@ extern pid_t waitpid(pid_t, int *, int); #include "ncplib.h" -void -test_print(struct ncp_conn *conn) -{ - struct ncp_bindery_object q; - struct queue_job j; - struct print_job_record pj; - int written; - - if (ncp_get_bindery_object_id(conn, NCP_BINDERY_PQUEUE, - "Q_DJ500", &q) != 0) { - printf("get oid error\n"); - return; - } - - memset(&j, 0, sizeof(j)); - - j.j.TargetServerID = 0xffffffff; /* any server */ - /* at once */ - memset(&(j.j.TargetExecTime), 0xff, sizeof(j.j.TargetExecTime)); - j.j.JobType = htons(0); - strcpy(j.j.JobTextDescription, "Test Job"); - - memset(&pj, 0, sizeof(pj)); - - pj.Version = 0; - pj.TabSize = 8; - pj.Copies = htons(1); - pj.CtrlFlags = 0; - pj.Lines = htons(66); - pj.Rows = htons(80); - strcpy(pj.FormName, "test"); - strcpy(pj.BannerName, "BannerName"); - strcpy(pj.FnameBanner, "BannerFile"); - strcpy(pj.FnameHeader, "HeaderName"); - strcpy(pj.Path, ""); - - memcpy(j.j.ClientRecordArea, &pj, sizeof(pj)); - - if (ncp_create_queue_job_and_file(conn, q.object_id, &j) != 0) { - printf("create error\n"); - return; - } - - if ((written = ncp_write(conn, j.file_handle, 0, 15, - "hallo, wie geht's?")) < 0) { - printf("write error\n"); - return; - } - - if (ncp_close_file_and_start_job(conn, q.object_id, &j) != 0) { - printf("close error\n"); - return; - } - - return; -} - -void -test_ls(struct ncp_conn *server) -{ - struct nw_info_struct sys; - struct nw_info_struct public; - struct ncp_search_seq seq; - struct nw_info_struct found; - int res; - - if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0) - { - printf("lookup error\n"); - return; - } - if (ncp_do_lookup(server, &sys, "PUBLIC", &public) != 0) - { - printf("lookup public error\n"); - return; - } - if (ncp_initialize_search(server, &public, 4, &seq) != 0) - { - printf("init error\n"); - return; - } - while ((res=ncp_search_for_file_or_subdir(server,&seq,&found)) == 0) - { - printf("found %s: %s\n", - (found.attributes & aDIR) ? "dir " : "file", - found.entryName); - } - - if (res == 0xfe) - { - printf("result: no more files\n"); - } - else - { - printf("other error: %x\n", res); - } - return; -} - void test_connlist(struct ncp_conn *conn) { - __u16 conn_list[256]; + __u8 conn_list[256] = {0,}; int no; - ncp_get_connlist(conn, 0, NCP_BINDERY_USER, "*", &no, conn_list); + ncp_get_connlist(conn, NCP_BINDERY_USER, "SUPERVISOR", &no, + conn_list); return; } +void +test_send(struct ncp_conn *conn) +{ + __u8 conn_list[256] = {0,}; + int no; + + if (ncp_get_connlist(conn, NCP_BINDERY_USER, "ME", &no, + conn_list) != 0) + { + no = 0; + } + + if (no > 0) + { + ncp_send_broadcast(conn, no, conn_list, "Hallo"); + } + return; +} void test_create(struct ncp_conn *conn) { @@ -191,15 +111,16 @@ test_create(struct ncp_conn *conn) int main(int argc, char *argv[]) { - struct ncp_conn conn; + struct ncp_conn *conn; + long err; - if (ncp_initialize(&conn, &argc, argv, 1) != 0) + if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL) { - perror("ncp_initialize"); + com_err(argv[0], err, "in ncp_initialize"); return 1; } - test_create(&conn); - ncp_close(&conn); + test_send(conn); + ncp_close(conn); return 0; } diff --git a/util/nprint.c b/util/nprint.c index 5a3d620..b9c54c5 100644 --- a/util/nprint.c +++ b/util/nprint.c @@ -25,7 +25,7 @@ static void help(void); void main(int argc, char *argv[]) { - struct ncp_conn conn; + struct ncp_conn *conn; char default_queue[] = "*"; char *queue = default_queue; @@ -42,10 +42,11 @@ main(int argc, char *argv[]) char *file_name; int file; + long err; progname = argv[0]; - memzero(j); memzero(pj); memzero(q); memzero(conn); + memzero(j); memzero(pj); memzero(q); if ( (argc == 2) && (strcmp(argv[1], "-h") == 0)) @@ -54,9 +55,9 @@ main(int argc, char *argv[]) exit(0); } - if (ncp_initialize(&conn, &argc, argv, 1) != 0) + if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL) { - perror("Could not open connection"); + com_err(argv[0], err, "in ncp_initialize"); exit(1); } @@ -82,7 +83,7 @@ main(int argc, char *argv[]) switch (opt) { case 'h': help(); - ncp_close(&conn); + ncp_close(conn); exit(1); case 'p': /* Path */ @@ -191,7 +192,7 @@ main(int argc, char *argv[]) { printf("queue name too long: %s\n", optarg); - ncp_close(&conn); + ncp_close(conn); exit(1); } queue = optarg; @@ -212,7 +213,7 @@ main(int argc, char *argv[]) default: usage(); - ncp_close(&conn); + ncp_close(conn); exit(1); } } @@ -220,7 +221,7 @@ main(int argc, char *argv[]) if (optind != argc-1) { usage(); - ncp_close(&conn); + ncp_close(conn); exit(1); } @@ -236,7 +237,7 @@ main(int argc, char *argv[]) if (file < 0) { perror("could not open file"); - ncp_close(&conn); + ncp_close(conn); exit(1); } @@ -268,18 +269,18 @@ main(int argc, char *argv[]) str_upper(queue); - if (ncp_scan_bindery_object(&conn, 0xffffffff, NCP_BINDERY_PQUEUE, + if (ncp_scan_bindery_object(conn, 0xffffffff, NCP_BINDERY_PQUEUE, queue, &q) != 0) { printf("could not find queue %s\n", queue); - ncp_close(&conn); + ncp_close(conn); exit(1); } - if (ncp_create_queue_job_and_file(&conn, q.object_id, &j) != 0) + if (ncp_create_queue_job_and_file(conn, q.object_id, &j) != 0) { printf("create error\n"); - ncp_close(&conn); + ncp_close(conn); exit(1); } @@ -292,7 +293,7 @@ main(int argc, char *argv[]) break; } - if (ncp_write(&conn, j.file_handle, + if (ncp_write(conn, j.file_handle, written, read_this_time, buf) < read_this_time) { break; @@ -303,13 +304,13 @@ main(int argc, char *argv[]) close(file); - if (ncp_close_file_and_start_job(&conn, q.object_id, &j) != 0) { + if (ncp_close_file_and_start_job(conn, q.object_id, &j) != 0) { printf("close error\n"); - ncp_close(&conn); + ncp_close(conn); return; } - ncp_close(&conn); + ncp_close(conn); return; } diff --git a/util/nsend.c b/util/nsend.c new file mode 100644 index 0000000..14c5828 --- /dev/null +++ b/util/nsend.c @@ -0,0 +1,65 @@ +/* + * nsend.c + * + * Send Messages to users + * + * Copyright (C) 1996 by Volker Lendecke + * + */ + +#include +#include +#include +#include "ncplib.h" + +int +main(int argc, char **argv) +{ + struct ncp_conn *conn; + __u8 conn_list[256] = {0,}; + int no_conn; + + char *message = NULL; + char *user = NULL; + long err; + + if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL) + { + com_err(argv[0], err, "in ncp_initialize"); + exit(1); + } + + if (argc != 3) + { + fprintf(stderr, "usage: %s [options] user message\n", argv[0]); + ncp_close(conn); + exit(1); + } + + user = argv[1]; + message = argv[2]; + + if ((err = ncp_get_connlist(conn, NCP_BINDERY_USER, user, &no_conn, + conn_list)) != 0) + { + com_err(argv[0], err, "in get_connlist"); + ncp_close(conn); + exit(1); + } + + if (no_conn == 0) + { + fprintf(stderr, "No connection found for %s\n", user); + ncp_close(conn); + exit(1); + } + + if ((err = ncp_send_broadcast(conn, no_conn, conn_list, message)) != 0) + { + com_err(argv[0], err, "in send_broadcast"); + ncp_close(conn); + exit(1); + } + ncp_close(conn); + return 0; +} diff --git a/util/nwfsinfo.c b/util/nwfsinfo.c index 7aec919..e820715 100644 --- a/util/nwfsinfo.c +++ b/util/nwfsinfo.c @@ -14,12 +14,13 @@ int main(int argc, char **argv) { - struct ncp_conn conn; + struct ncp_conn *conn; int opt; + long err; - if (ncp_initialize(&conn, &argc, argv, 0) != 0) + if ((conn = ncp_initialize(&argc, argv, 0, &err)) == NULL) { - perror("Could not open connection"); + com_err(argv[0], err, "in ncp_initialize"); return 1; } @@ -32,12 +33,12 @@ main(int argc, char **argv) char strings[512]; char *s; - if (ncp_get_file_server_description_strings(&conn, + if (ncp_get_file_server_description_strings(conn, strings) != 0) { perror("could not get strings"); - ncp_close(&conn); + ncp_close(conn); return 1; } @@ -57,10 +58,10 @@ main(int argc, char **argv) { time_t t; - if (ncp_get_file_server_time(&conn, &t) != 0) + if (ncp_get_file_server_time(conn, &t) != 0) { perror("could not get server time"); - ncp_close(&conn); + ncp_close(conn); return 1; } @@ -73,6 +74,6 @@ main(int argc, char **argv) } } - ncp_close(&conn); + ncp_close(conn); return 0; } diff --git a/util/nwlsobj.c b/util/nwlsobj.c new file mode 100644 index 0000000..13a7c21 --- /dev/null +++ b/util/nwlsobj.c @@ -0,0 +1,62 @@ +/* + * nwlsobj.c + * + * List bindery objects + * + * Copyright (C) 1996 by Volker Lendecke + * + */ + +#include +#include +#include +#include "ncplib.h" + +int +main(int argc, char **argv) +{ + struct ncp_conn *conn; + struct ncp_bindery_object o; + int found = 0; + + char default_pattern[] = "*"; + char *pattern = default_pattern; + char *p; + long err; + + if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL) + { + com_err(argv[0], err, "in ncp_initialize"); + return 1; + } + + if (argc > 2) + { + fprintf(stderr, "usage: %s [options]\n", argv[0]); + return 1; + } + + if (argc == 2) + { + pattern = argv[1]; + } + + for (p = pattern; *p != '\0'; p++) + { + *p = toupper(*p); + } + + o.object_id = 0xffffffff; + + while (ncp_scan_bindery_object(conn, o.object_id, + 0xffff, pattern, &o) == 0) + { + found = 1; + printf("%s %08X %04X\n", + o.object_name, (unsigned int)o.object_id, + (unsigned int)o.object_type); + } + + ncp_close(conn); + return 0; +} diff --git a/util/nwmsg.c b/util/nwmsg.c index 490d09a..492272e 100644 --- a/util/nwmsg.c +++ b/util/nwmsg.c @@ -30,7 +30,7 @@ static char *progname; void main(int argc, char *argv[]) { - struct ncp_conn conn; + struct ncp_conn *conn; char message[256]; struct ncp_fs_info info; struct passwd *pwd; @@ -39,6 +39,7 @@ main(int argc, char *argv[]) FILE *tty_file; FILE *mtab; struct mntent *mnt; + long err; progname = argv[0]; @@ -52,18 +53,17 @@ main(int argc, char *argv[]) exit(1); } - if (ncp_open_mount(&conn, argv[1]) != 0) + if ((conn = ncp_open_mount(argv[1], &err)) == NULL) { - fprintf(stderr, "%s: could not open connection %s\n", - progname, argv[1]); + com_err(progname, err, "in ncp_open_mount"); exit(1); } - if (ncp_get_broadcast_message(&conn, message) != 0) + if (ncp_get_broadcast_message(conn, message) != 0) { fprintf(stderr, "%s: could not get broadcast message\n", progname); - ncp_close(&conn); + ncp_close(conn); exit(1); } @@ -78,15 +78,15 @@ main(int argc, char *argv[]) #endif info.version = NCP_GET_FS_INFO_VERSION; - if (ioctl(conn.mount_fid, NCP_IOC_GET_FS_INFO, &info) < 0) + 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); + ncp_close(conn); exit(1); } - ncp_close(&conn); + ncp_close(conn); if ((pwd = getpwuid(info.mounted_uid)) == NULL) { @@ -104,7 +104,7 @@ main(int argc, char *argv[]) while ((mnt = getmntent(mtab)) != NULL) { - if (strcmp(mnt->mnt_dir, conn.mount_point) == 0) + if (strcmp(mnt->mnt_dir, conn->mount_point) == 0) { break; } diff --git a/util/pqlist.c b/util/pqlist.c index 325ea03..4c44728 100644 --- a/util/pqlist.c +++ b/util/pqlist.c @@ -15,17 +15,18 @@ int main(int argc, char **argv) { - struct ncp_conn conn; + struct ncp_conn *conn; struct ncp_bindery_object q; int found = 0; char default_pattern[] = "*"; char *pattern = default_pattern; char *p; + long err; - if (ncp_initialize(&conn, &argc, argv, 1) != 0) + if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL) { - perror("Could not open connection"); + com_err(argv[0], err, "in ncp_initialize"); return 1; } @@ -47,7 +48,7 @@ main(int argc, char **argv) if (isatty(1)) { - printf("\nServer: %s\n", conn.server); + printf("\nServer: %s\n", conn->server); printf("%-52s%-10s\n" "-----------------------------------------------" "-------------\n", @@ -57,8 +58,8 @@ main(int argc, char **argv) q.object_id = 0xffffffff; - while (ncp_scan_bindery_object(&conn, q.object_id, - NCP_BINDERY_PQUEUE, "*", &q) == 0) + while (ncp_scan_bindery_object(conn, q.object_id, + NCP_BINDERY_PQUEUE, pattern, &q) == 0) { found = 1; printf("%-52s", q.object_name); @@ -70,6 +71,6 @@ main(int argc, char **argv) printf("No queues found\n"); } - ncp_close(&conn); + ncp_close(conn); return 0; } diff --git a/util/pserver.c b/util/pserver.c index 3a2ac81..048aeb9 100644 --- a/util/pserver.c +++ b/util/pserver.c @@ -107,12 +107,13 @@ daemon_init(void) int main(int argc, char *argv[]) { - struct ncp_conn conn; + struct ncp_conn *conn; int poll_timeout = 30; int opt; int job_type = 0xffff; int debug = 0; int i; + long err; char *queue_name = NULL; @@ -146,9 +147,10 @@ main(int argc, char *argv[]) openlog("pserver", LOG_PID, LOG_LPR); } - if (ncp_initialize_as(&conn, &argc, argv, 1, NCP_BINDERY_PSERVER) != 0) + if ((conn = ncp_initialize_as(&argc, argv, 1, + NCP_BINDERY_PSERVER, &err)) == NULL) { - perror("Could not open connection"); + com_err(argv[0], err, "in ncp_initialize"); return 1; } @@ -193,10 +195,10 @@ main(int argc, char *argv[]) return 1; } - if (init_queue(&conn, queue_name, command, &q) != 0) + if (init_queue(conn, queue_name, command, &q) != 0) { perror("Could not init queue"); - ncp_close(&conn); + ncp_close(conn); return 1; } @@ -221,9 +223,9 @@ main(int argc, char *argv[]) sleep(poll_timeout); } - ncp_detach_from_queue(&conn, q.queue_id); + ncp_detach_from_queue(conn, q.queue_id); - ncp_close(&conn); + ncp_close(conn); return 0; } diff --git a/util/slist.c b/util/slist.c index b0b4206..08b2075 100644 --- a/util/slist.c +++ b/util/slist.c @@ -17,12 +17,13 @@ void main(int argc, char *argv[]) { - struct ncp_conn conn; + struct ncp_conn *conn; struct ncp_bindery_object obj; int found = 0; char default_pattern[] = "*"; char *pattern = default_pattern; char *p; + long err; if (argc > 2) { @@ -40,9 +41,9 @@ main(int argc, char *argv[]) *p = toupper(*p); } - if (ncp_initialize(&conn, &argc, argv, 0) != 0) + if ((conn = ncp_initialize(&argc, argv, 0, &err)) == NULL) { - perror("ncp_connect"); + com_err(argv[0], err, "in ncp_initialize"); exit(1); } @@ -58,7 +59,7 @@ main(int argc, char *argv[]) obj.object_id = 0xffffffff; - while (ncp_scan_bindery_object(&conn, obj.object_id, + while (ncp_scan_bindery_object(conn, obj.object_id, NCP_BINDERY_FSERVER, pattern, &obj) == 0) { @@ -70,7 +71,7 @@ main(int argc, char *argv[]) printf("%-52s", obj.object_name); - if (ncp_read_property_value(&conn, NCP_BINDERY_FSERVER, + if (ncp_read_property_value(conn, NCP_BINDERY_FSERVER, obj.object_name, 1, "NET_ADDRESS", &prop) == 0) { @@ -86,6 +87,6 @@ main(int argc, char *argv[]) printf("No servers found\n"); } - ncp_close(&conn); + ncp_close(conn); }