1/*
2 * Copyright (c) 1999, Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *    This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34
35__FBSDID("$FreeBSD$");
36
37#include <sys/param.h>
38#include <sys/time.h>
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45#include <netncp/ncp_lib.h>
46
47extern char *__progname;
48
49static struct ncp_conn_stat conndesc;
50
51static void help(void);
52static void show_connlist(void);
53static void show_serverlist(char *server);
54static void show_userlist(char *server);
55static void list_volumes(char *server);
56static void str_trim_right(char *s, char c);
57
58
59static int
60ncp_get_connid(char *server, int justattach)
61{
62	int connid, error;
63	struct ncp_conn_loginfo li;
64
65	connid = ncp_conn_find(server, NULL);
66	if (connid > 0) {
67		ncp_conn_getinfo(connid, &conndesc);
68		return connid;
69	}
70	if (!justattach) {
71		if (connid == -1) {
72			printf("You are not attached to server %s\n",server);
73			return -1;
74		}
75		printf("You are not attached to any server\n");
76		return -1;
77	}
78	ncp_li_init(&li, 0, NULL);
79	if (server) {
80		ncp_li_setserver(&li, server);
81		error = ncp_find_fileserver(&li, AF_IPX, NULL);
82		if (error) {
83			printf("Could not find server %s\n", li.server);
84			return -1;
85		}
86	} else {
87		error = ncp_find_fileserver(&li, AF_IPX, NULL);
88		if (error) {
89			printf("Can't find any file server\n");
90			return -1;
91		}
92	}
93	error = ncp_connect(&li, &connid);
94	if (error) {
95		printf("Can't attach to a nearest server\n");
96		return -1;
97	}
98	ncp_conn_getinfo(connid, &conndesc);
99	return connid;
100}
101
102static struct ncp_bitname conn_statenames [] = {
103	{NCPFL_INVALID, "invalid"},
104	{NCPFL_LOGGED,	"active"},
105	{NCPFL_PERMANENT, "permanent"},
106	{NCPFL_PRIMARY,	"primary"},
107	{0, NULL}
108};
109
110static void
111str_trim_right(char *s, char c)
112{
113	int len;
114
115	for (len = strlen(s) - 1; len > 0 && s[len] == c; len--)
116		s[len] = '\0';
117}
118
119void
120show_connlist(void)
121{
122	void *p;
123	int cnt;
124	char buf[200];
125	struct ncp_conn_stat *ncsp;
126
127	printf("Active NCP connections:\n");
128	p = ncp_conn_list();
129	if (p == NULL) {
130		printf("None\n");
131		return;
132	}
133	printf(" refid server:user(connid), owner:group(mode), refs, <state>\n");
134	cnt = *(int*)p;
135	ncsp = (struct ncp_conn_stat*)(((int*)p)+1);
136	while (cnt--) {
137		printf("%6d %s:%s(%d), %s:%s(%o), %d, %s",
138		    ncsp->connRef, ncsp->li.server,ncsp->user,ncsp->connid,
139		    user_from_uid(ncsp->owner, 0),
140		    group_from_gid(ncsp->group, 0),
141		    ncsp->li.access_mode,
142		    ncsp->ref_cnt,
143		    ncp_printb(buf, ncsp->flags, conn_statenames));
144		printf("\n");
145		ncsp++;
146	}
147	free(p);
148	printf("\n");
149}
150
151void
152show_serverlist(char *server)
153{
154	int found = 0, connid;
155	struct ncp_bindery_object obj;
156	char *pattern = "*";
157
158	connid = ncp_get_connid(server, 1);
159	if (connid < 0)
160		return;
161	printf("Visible servers (from %s):\n", conndesc.li.server);
162	printf("Name                                            Network    Node       Port\n");
163	printf("----------------------------------------------- -------- ------------ ----\n");
164	obj.object_id = 0xffffffff;
165
166	while (ncp_scan_bindery_object(connid, obj.object_id, NCP_BINDERY_FSERVER,
167	    pattern, &obj) == 0) {
168		struct nw_property prop;
169		struct ipx_addr *naddr = (struct ipx_addr *) &prop;
170
171		found = 1;
172		printf("%-48s", obj.object_name);
173
174		if (ncp_read_property_value(connid, NCP_BINDERY_FSERVER,
175					    obj.object_name, 1, "NET_ADDRESS",
176					    &prop) == 0) {
177			ipx_print_addr(naddr);
178		}
179		printf("\n");
180	}
181
182	if (!found) {
183		printf("No servers found\n");
184	}
185	printf("\n");
186}
187
188
189void
190show_userlist(char *server)
191{
192	int connid, error, i;
193	struct ncp_file_server_info info;
194	struct ncp_bindery_object user;
195	time_t login_time;
196	struct ipx_addr addr;
197	u_int8_t conn_type;
198
199	connid = ncp_get_connid(server, 0);
200	if (connid < 0) return;
201	if (ncp_get_file_server_information(connid, &info) != 0) {
202		perror("Could not get server information");
203		return;
204	}
205	printf("User information for server %s\n",info.ServerName);
206	printf("\n%-6s%-21s%-27s%-12s\n"
207	       "---------------------------------------------"
208	       "---------------------------------\n",
209	       "Conn",
210	       "User name",
211	       "Station Address",
212	       "Login time");
213	for (i = 1; i <= info.MaximumServiceConnections; i++) {
214		char name[49];
215		name[48] = '\0';
216		error = ncp_get_stations_logged_info(connid, i, &user, &login_time);
217		if (error) continue;
218		memset(&addr, 0, sizeof(addr));
219		error = ncp_get_internet_address(connid, i, &addr, &conn_type);
220		if (error) continue;
221		memcpy(name, user.object_name, 48);
222		str_trim_right(name, ' ');
223		printf("%4d: %-20s ", i, name);
224		ipx_print_addr(&addr);
225		printf(" ");
226		printf("%s", ctime(&login_time));
227	}
228
229	return;
230}
231
232void
233show_queuelist(char *server, char *patt)
234{
235	struct ncp_bindery_object q;
236	int found = 0, connid;
237	char default_pattern[] = "*";
238	char *pattern = default_pattern;
239
240	connid = ncp_get_connid(server, 1);
241	if (connid < 0) return;
242	if (patt != NULL)
243		pattern = patt;
244	ncp_str_upper(pattern);
245
246	printf("\nServer: %s\n", server);
247	printf("%-52s%-10s\n"
248	       "-----------------------------------------------"
249	       "-------------\n",
250	       "Print queue name",
251	       "Queue ID");
252	q.object_id = 0xffffffff;
253
254	while (ncp_scan_bindery_object(connid, q.object_id,
255				       NCP_BINDERY_PQUEUE, pattern, &q) == 0)
256	{
257		found = 1;
258		printf("%-52s", q.object_name);
259		printf("%08X\n", (unsigned int) q.object_id);
260	}
261
262	if (!found) {
263		printf("No queues found\n");
264	}
265	return;
266}
267
268void
269list_volumes(char *server)
270{
271	int found = 0, connid, i, error;
272	struct ncp_file_server_info si;
273	char volname[NCP_VOLNAME_LEN+1];
274
275	connid = ncp_get_connid(server, 1);
276	if (connid < 0) return;
277
278	error = ncp_get_file_server_information(connid, &si);
279	if (error) {
280		ncp_error("Can't get information for server %s", error, server);
281		return;
282	}
283
284	printf("\nMounted volumes on server %s:\n", server);
285	printf("Number Name\n");
286	printf("------ -----------------------------------------------\n");
287
288	for(i = 0; i < si.NumberMountedVolumes; i++) {
289		if (NWGetVolumeName(connid, i, volname))
290			continue;
291		found = 1;
292		printf("%6d %s\n", i, volname);
293	}
294
295	if (!found)
296		printf("No volumes found ?\n");
297	return;
298}
299
300struct ncp_bind_type {
301	u_long	type;
302	char	*name;
303};
304
305static struct ncp_bind_type btypes[] = {
306	{NCP_BINDERY_USER,	"USER"},
307	{NCP_BINDERY_UGROUP,	"GROUP"},
308	{NCP_BINDERY_PSERVER,	"PSERVER"},
309	{0x278,			"TREE"},
310	{0, NULL}
311};
312
313void
314list_bindery(char *server, char *type, char *patt)
315{
316	struct ncp_bindery_object q;
317	int i, found = 0, connid;
318	char default_pattern[] = "*";
319	char *pattern = default_pattern;
320	u_long objtype;
321
322	ncp_str_upper(type);
323	objtype = 0;
324
325	for(i = 0; btypes[i].type; i++) {
326		if (strcmp(btypes[i].name, type) == 0) {
327			objtype = btypes[i].type;
328			break;
329		}
330	}
331	if (!objtype) {
332		printf("Bindery object of type %s is unknown\n", type);
333		return;
334	}
335	if (patt != NULL)
336		pattern = patt;
337	ncp_str_upper(pattern);
338	connid = ncp_get_connid(server, 1);
339	if (connid < 0) return;
340
341	connid = ncp_get_connid(server, 1);
342	if (connid < 0) return;
343
344
345	printf("\nServer: %s\n", server);
346	printf("%-52s%-10s\n"
347	       "-----------------------------------------------"
348	       "-------------\n",
349	       "Object name",
350	       "Object ID");
351
352	q.object_id = 0xffffffff;
353	while (ncp_scan_bindery_object(connid, q.object_id,
354				       objtype, pattern, &q) == 0)
355	{
356		found = 1;
357		printf("%-52s", q.object_name);
358		printf("%08X\n", (unsigned int) q.object_id);
359	}
360
361	if (!found) {
362		printf("No bindery objects found\n");
363	}
364	return;
365}
366
367enum listop {
368	LO_NONE, LO_SERVERS, LO_QUEUES, LO_BINDERY, LO_USERS, LO_VOLUMES
369};
370
371#define MAX_ARGS	10
372
373int
374main(int argc, char *argv[])
375{
376	int opt, nargs = 0, i;
377	enum listop what;
378	char *args[MAX_ARGS];
379
380	bzero(args, sizeof(args));
381
382	what = LO_NONE;
383	while ((opt = getopt(argc, argv, "h")) != -1) {
384		switch (opt) {
385		    case 'h': case '?':
386			help();
387			/*NOTREACHED */
388		    default:
389			help();
390			return 1;
391		}
392	}
393	if (optind >= argc)
394		help();
395
396	if(ncp_initlib())
397		exit(1);
398
399	switch(argv[optind++][0]) {
400	    case 'b':
401		what = LO_BINDERY;
402		nargs = 2;
403		break;
404	    case 'c':
405		show_connlist();
406		return 0;
407	    case 's':
408		what = LO_SERVERS;
409		break;
410	    case 'u':
411		what = LO_USERS;
412		nargs = 1;
413		break;
414	    case 'q':
415		what = LO_QUEUES;
416		nargs = 1;
417		break;
418	    case 'v':
419		what = LO_VOLUMES;
420		nargs = 1;
421		break;
422	    default:
423		printf("Unknown command %s\n", argv[optind-1]);
424		help();
425	}
426	for (i = 0; i < MAX_ARGS; i++) {
427		if (optind < argc) {
428			args[i] = argv[optind++];
429		} else if (i < nargs) {
430			printf("Not enough arguments\n");
431			help();
432			return 1;
433		} else
434			break;
435	}
436	switch(what) {
437	    case LO_SERVERS:
438		show_serverlist(args[0]);
439		break;
440	    case LO_USERS:
441		show_userlist(args[0]);
442		break;
443	    case LO_QUEUES:
444		show_queuelist(args[0], args[1]);
445		break;
446	    case LO_VOLUMES:
447		list_volumes(args[0]);
448		break;
449	    case LO_BINDERY:
450		list_bindery(args[0], args[1], args[2]);
451		break;
452	    default:
453		help();
454	}
455	return 0;
456}
457
458static void
459help(void)
460{
461	printf("\n");
462	printf("usage: %s command [args]\n", __progname);
463	printf("where commands are:\n"
464	" b server user|group [pattern]	list bindery objects on server\n"
465	" c 				display opened connections\n"
466	" s [server]			display known servers\n"
467	" u server			list logged-in users on server\n"
468	" q server [pattern]		list print queues on server\n"
469	" v server			list mounted volumes on a specified server\n"
470	"\n");
471	exit(1);
472}
473