From 0520c1d2f73e251154dd10f04c3133ea7a6c35d0 Mon Sep 17 00:00:00 2001 From: ncpfs archive import Date: Tue, 28 Apr 2026 20:39:57 +0200 Subject: [PATCH] Import ncpfs 0.19 --- .downloads/ncpfs-0.19.tgz | Bin 0 -> 103260 bytes Changes | 10 + Makefile | 4 +- README | 18 +- TODO | 20 + ipxdump/ipxdump.c | 18 +- ipxdump/ipxparse.c | 157 ++++- kernel-1.2/linux/ncp_fs.h | 10 +- kernel-1.2/src/dir.c | 5 + kernel-1.2/src/ioctl.c | 22 + man/Makefile | 5 +- man/nsend.1 | 108 +++ ncpfs-0.18.lsm => ncpfs-0.19.lsm | 8 +- util/Makefile | 36 +- util/com_err.h | 1 + util/com_err/ChangeLog | 49 ++ util/com_err/Makefile | 25 + util/com_err/com_err.3 | 96 +++ util/com_err/com_err.c | 114 ++++ util/com_err/com_err.h | 40 ++ util/com_err/com_err.texinfo | 554 ++++++++++++++++ util/com_err/compile_et | 11 + util/com_err/compile_et.1 | 79 +++ util/com_err/error_message.c | 82 +++ util/com_err/error_table.h | 35 + util/com_err/et_c.awk | 185 ++++++ util/com_err/et_h.awk | 157 +++++ util/com_err/et_name.c | 36 + util/com_err/init_et.c | 58 ++ util/com_err/internal.h | 22 + util/com_err/mit-sipb-copyright.h | 19 + util/ipx_sap_types | 32 + util/ncplib.c | 1021 ++++++++++++++++------------- util/ncplib.h | 138 ++-- util/ncplib_err.et | 21 + util/ncpmount.c | 59 +- util/ncptest.c | 133 +--- util/nprint.c | 35 +- util/nsend.c | 65 ++ util/nwfsinfo.c | 17 +- util/nwlsobj.c | 62 ++ util/nwmsg.c | 20 +- util/pqlist.c | 15 +- util/pserver.c | 16 +- util/slist.c | 13 +- 45 files changed, 2872 insertions(+), 759 deletions(-) create mode 100644 .downloads/ncpfs-0.19.tgz create mode 100644 TODO create mode 100644 man/nsend.1 rename ncpfs-0.18.lsm => ncpfs-0.19.lsm (83%) create mode 120000 util/com_err.h create mode 100644 util/com_err/ChangeLog create mode 100644 util/com_err/Makefile create mode 100644 util/com_err/com_err.3 create mode 100644 util/com_err/com_err.c create mode 100644 util/com_err/com_err.h create mode 100644 util/com_err/com_err.texinfo create mode 100755 util/com_err/compile_et create mode 100644 util/com_err/compile_et.1 create mode 100644 util/com_err/error_message.c create mode 100644 util/com_err/error_table.h create mode 100644 util/com_err/et_c.awk create mode 100644 util/com_err/et_h.awk create mode 100644 util/com_err/et_name.c create mode 100644 util/com_err/init_et.c create mode 100644 util/com_err/internal.h create mode 100644 util/com_err/mit-sipb-copyright.h create mode 100644 util/ipx_sap_types create mode 100644 util/ncplib_err.et create mode 100644 util/nsend.c create mode 100644 util/nwlsobj.c diff --git a/.downloads/ncpfs-0.19.tgz b/.downloads/ncpfs-0.19.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a366ce80dfac858a1841a5cdcbb50f01a78d3691 GIT binary patch literal 103260 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 literal 0 HcmV?d00001 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); }