1272343Sngie/*	$NetBSD: h_tools.c,v 1.4 2011/06/11 18:03:17 christos Exp $	*/
2272343Sngie
3272343Sngie/*
4272343Sngie * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * Redistribution and use in source and binary forms, with or without
8272343Sngie * modification, are permitted provided that the following conditions
9272343Sngie * are met:
10272343Sngie * 1. Redistributions of source code must retain the above copyright
11272343Sngie *    notice, this list of conditions and the following disclaimer.
12272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
13272343Sngie *    notice, this list of conditions and the following disclaimer in the
14272343Sngie *    documentation and/or other materials provided with the distribution.
15272343Sngie *
16272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26272343Sngie * POSSIBILITY OF SUCH DAMAGE.
27272343Sngie */
28272343Sngie
29272343Sngie/*
30272343Sngie * Helper tools for several tests.  These are kept in a single file due
31272343Sngie * to the limitations of bsd.prog.mk to build a single program in a
32272343Sngie * given directory.
33272343Sngie */
34272343Sngie
35272343Sngie#include <sys/param.h>
36272343Sngie#include <sys/types.h>
37272343Sngie#include <sys/event.h>
38272343Sngie#include <sys/mount.h>
39272343Sngie#include <sys/statvfs.h>
40272343Sngie#include <sys/socket.h>
41272343Sngie#include <sys/time.h>
42272343Sngie#include <sys/un.h>
43272343Sngie
44272343Sngie#include <assert.h>
45272343Sngie#include <err.h>
46272343Sngie#include <errno.h>
47272343Sngie#include <fcntl.h>
48272343Sngie#include <stdio.h>
49272343Sngie#include <stdlib.h>
50272343Sngie#include <string.h>
51272343Sngie#include <unistd.h>
52272343Sngie
53309668Sngie#ifdef __FreeBSD__
54309668Sngie#include <inttypes.h>
55309668Sngie#endif
56309668Sngie
57272343Sngie/* --------------------------------------------------------------------- */
58272343Sngie
59272343Sngiestatic int getfh_main(int, char **);
60272343Sngiestatic int kqueue_main(int, char **);
61272343Sngiestatic int rename_main(int, char **);
62272343Sngiestatic int sockets_main(int, char **);
63272343Sngiestatic int statvfs_main(int, char **);
64272343Sngie
65272343Sngie/* --------------------------------------------------------------------- */
66272343Sngie
67272343Sngieint
68272343Sngiegetfh_main(int argc, char **argv)
69272343Sngie{
70272343Sngie	int error;
71272343Sngie	void *fh;
72272343Sngie	size_t fh_size;
73272343Sngie
74272343Sngie	if (argc < 2)
75272343Sngie		return EXIT_FAILURE;
76272343Sngie
77309668Sngie#ifdef __FreeBSD__
78309668Sngie	fh_size = sizeof(fhandle_t);
79309668Sngie#else
80272343Sngie	fh_size = 0;
81309668Sngie#endif
82309668Sngie
83272343Sngie	fh = NULL;
84272343Sngie	for (;;) {
85272343Sngie		if (fh_size) {
86272343Sngie			fh = malloc(fh_size);
87272343Sngie			if (fh == NULL) {
88272343Sngie				fprintf(stderr, "out of memory");
89272343Sngie				return EXIT_FAILURE;
90272343Sngie			}
91272343Sngie		}
92272343Sngie		/*
93272343Sngie		 * The kernel provides the necessary size in fh_size -
94272343Sngie		 * but it may change if someone moves things around,
95272343Sngie		 * so retry untill we have enough memory.
96272343Sngie		 */
97309668Sngie#ifdef __FreeBSD__
98309668Sngie		error = getfh(argv[1], fh);
99309668Sngie#else
100272343Sngie		error = getfh(argv[1], fh, &fh_size);
101309668Sngie#endif
102272343Sngie		if (error == 0) {
103272343Sngie			break;
104272343Sngie		} else {
105272343Sngie			if (fh != NULL)
106272343Sngie				free(fh);
107272343Sngie			if (errno != E2BIG) {
108272343Sngie				warn("getfh");
109272343Sngie				return EXIT_FAILURE;
110272343Sngie			}
111272343Sngie		}
112272343Sngie	}
113272343Sngie
114272343Sngie	error = write(STDOUT_FILENO, fh, fh_size);
115272343Sngie	if (error == -1) {
116272343Sngie		warn("write");
117272343Sngie		return EXIT_FAILURE;
118272343Sngie	}
119272343Sngie	free(fh);
120272343Sngie
121272343Sngie	return 0;
122272343Sngie}
123272343Sngie
124272343Sngie/* --------------------------------------------------------------------- */
125272343Sngie
126272343Sngieint
127272343Sngiekqueue_main(int argc, char **argv)
128272343Sngie{
129272343Sngie	char *line;
130272343Sngie	int i, kq;
131272343Sngie	size_t len;
132272343Sngie	struct kevent *changes, event;
133272343Sngie
134272343Sngie	if (argc < 2)
135272343Sngie		return EXIT_FAILURE;
136272343Sngie
137272343Sngie	argc--;
138272343Sngie	argv++;
139272343Sngie
140272343Sngie	changes = malloc(sizeof(struct kevent) * argc);
141272343Sngie	if (changes == NULL)
142272343Sngie		errx(EXIT_FAILURE, "not enough memory");
143272343Sngie
144272343Sngie	for (i = 0; i < argc; i++) {
145272343Sngie		int fd;
146272343Sngie
147272343Sngie		fd = open(argv[i], O_RDONLY);
148272343Sngie		if (fd == -1)
149272343Sngie			err(EXIT_FAILURE, "cannot open %s", argv[i]);
150272343Sngie
151272343Sngie		EV_SET(&changes[i], fd, EVFILT_VNODE,
152272343Sngie		    EV_ADD | EV_ENABLE | EV_ONESHOT,
153272343Sngie		    NOTE_ATTRIB | NOTE_DELETE | NOTE_EXTEND | NOTE_LINK |
154272343Sngie		    NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE,
155272343Sngie		    0, 0);
156272343Sngie	}
157272343Sngie
158272343Sngie	kq = kqueue();
159272343Sngie	if (kq == -1)
160272343Sngie		err(EXIT_FAILURE, "kqueue");
161272343Sngie
162272343Sngie	while ((line = fgetln(stdin, &len)) != NULL) {
163272343Sngie		int ec, nev;
164272343Sngie		struct timespec to;
165272343Sngie
166272343Sngie		to.tv_sec = 0;
167272343Sngie		to.tv_nsec = 100000;
168272343Sngie
169272343Sngie		(void)kevent(kq, changes, argc, &event, 1, &to);
170272343Sngie
171272343Sngie		assert(len > 0);
172272343Sngie		assert(line[len - 1] == '\n');
173272343Sngie		line[len - 1] = '\0';
174272343Sngie		ec = system(line);
175272343Sngie		if (ec != EXIT_SUCCESS)
176272343Sngie			errx(ec, "%s returned %d", line, ec);
177272343Sngie
178272343Sngie		do {
179272343Sngie			nev = kevent(kq, changes, argc, &event, 1, &to);
180272343Sngie			if (nev == -1)
181272343Sngie				err(EXIT_FAILURE, "kevent");
182272343Sngie			else if (nev > 0) {
183272343Sngie				for (i = 0; i < argc; i++)
184272343Sngie					if (event.ident == changes[i].ident)
185272343Sngie						break;
186272343Sngie
187272343Sngie				if (event.fflags & NOTE_ATTRIB)
188272343Sngie					printf("%s - NOTE_ATTRIB\n", argv[i]);
189272343Sngie				if (event.fflags & NOTE_DELETE)
190272343Sngie					printf("%s - NOTE_DELETE\n", argv[i]);
191272343Sngie				if (event.fflags & NOTE_EXTEND)
192272343Sngie					printf("%s - NOTE_EXTEND\n", argv[i]);
193272343Sngie				if (event.fflags & NOTE_LINK)
194272343Sngie					printf("%s - NOTE_LINK\n", argv[i]);
195272343Sngie				if (event.fflags & NOTE_RENAME)
196272343Sngie					printf("%s - NOTE_RENAME\n", argv[i]);
197272343Sngie				if (event.fflags & NOTE_REVOKE)
198272343Sngie					printf("%s - NOTE_REVOKE\n", argv[i]);
199272343Sngie				if (event.fflags & NOTE_WRITE)
200272343Sngie					printf("%s - NOTE_WRITE\n", argv[i]);
201272343Sngie			}
202272343Sngie		} while (nev > 0);
203272343Sngie	}
204272343Sngie
205272343Sngie	for (i = 0; i < argc; i++)
206272343Sngie		close(changes[i].ident);
207272343Sngie	free(changes);
208272343Sngie
209272343Sngie	return EXIT_SUCCESS;
210272343Sngie}
211272343Sngie
212272343Sngie/* --------------------------------------------------------------------- */
213272343Sngie
214272343Sngieint
215272343Sngierename_main(int argc, char **argv)
216272343Sngie{
217272343Sngie
218272343Sngie	if (argc < 3)
219272343Sngie		return EXIT_FAILURE;
220272343Sngie
221272343Sngie	if (rename(argv[1], argv[2]) == -1) {
222272343Sngie		warn("rename");
223272343Sngie		return EXIT_FAILURE;
224272343Sngie	}
225272343Sngie
226272343Sngie	return EXIT_SUCCESS;
227272343Sngie}
228272343Sngie
229272343Sngie/* --------------------------------------------------------------------- */
230272343Sngie
231272343Sngieint
232272343Sngiesockets_main(int argc, char **argv)
233272343Sngie{
234272343Sngie	int error, fd;
235272343Sngie	struct sockaddr_un addr;
236272343Sngie
237272343Sngie	if (argc < 2)
238272343Sngie		return EXIT_FAILURE;
239272343Sngie
240272343Sngie	fd = socket(PF_LOCAL, SOCK_STREAM, 0);
241272343Sngie	if (fd == -1) {
242272343Sngie		warn("socket");
243272343Sngie		return EXIT_FAILURE;
244272343Sngie	}
245272343Sngie
246311622Sngie#ifdef	__FreeBSD__
247311622Sngie	memset(&addr, 0, sizeof(addr));
248311622Sngie#endif
249272343Sngie	(void)strlcpy(addr.sun_path, argv[1], sizeof(addr.sun_path));
250272343Sngie	addr.sun_family = PF_UNIX;
251311622Sngie#ifdef	__FreeBSD__
252311622Sngie	error = bind(fd, (struct sockaddr *)&addr, SUN_LEN(&addr));
253311622Sngie#else
254272343Sngie	error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
255311622Sngie#endif
256272343Sngie	if (error == -1) {
257272343Sngie		warn("connect");
258311622Sngie#ifdef	__FreeBSD__
259311622Sngie		(void)close(fd);
260311622Sngie#endif
261272343Sngie		return EXIT_FAILURE;
262272343Sngie	}
263272343Sngie
264272343Sngie	close(fd);
265272343Sngie
266272343Sngie	return EXIT_SUCCESS;
267272343Sngie}
268272343Sngie
269272343Sngie/* --------------------------------------------------------------------- */
270272343Sngie
271272343Sngieint
272272343Sngiestatvfs_main(int argc, char **argv)
273272343Sngie{
274272343Sngie	int error;
275272343Sngie	struct statvfs buf;
276272343Sngie
277272343Sngie	if (argc < 2)
278272343Sngie		return EXIT_FAILURE;
279272343Sngie
280272343Sngie	error = statvfs(argv[1], &buf);
281272343Sngie	if (error != 0) {
282272343Sngie		warn("statvfs");
283272343Sngie		return EXIT_FAILURE;
284272343Sngie	}
285272343Sngie
286272343Sngie	(void)printf("f_bsize=%lu\n", buf.f_bsize);
287272343Sngie	(void)printf("f_blocks=%" PRId64 "\n", buf.f_blocks);
288272343Sngie	(void)printf("f_bfree=%" PRId64 "\n", buf.f_bfree);
289272343Sngie	(void)printf("f_files=%" PRId64 "\n", buf.f_files);
290272343Sngie
291272343Sngie	return EXIT_SUCCESS;
292272343Sngie}
293272343Sngie
294272343Sngie/* --------------------------------------------------------------------- */
295272343Sngie
296272343Sngieint
297272343Sngiemain(int argc, char **argv)
298272343Sngie{
299272343Sngie	int error;
300272343Sngie
301272343Sngie	if (argc < 2)
302272343Sngie		return EXIT_FAILURE;
303272343Sngie
304272343Sngie	argc -= 1;
305272343Sngie	argv += 1;
306272343Sngie
307272343Sngie	if (strcmp(argv[0], "getfh") == 0)
308272343Sngie		error = getfh_main(argc, argv);
309272343Sngie	else if (strcmp(argv[0], "kqueue") == 0)
310272343Sngie		error = kqueue_main(argc, argv);
311272343Sngie	else if (strcmp(argv[0], "rename") == 0)
312272343Sngie		error = rename_main(argc, argv);
313272343Sngie	else if (strcmp(argv[0], "sockets") == 0)
314272343Sngie		error = sockets_main(argc, argv);
315272343Sngie	else if (strcmp(argv[0], "statvfs") == 0)
316272343Sngie		error = statvfs_main(argc, argv);
317272343Sngie	else
318272343Sngie		error = EXIT_FAILURE;
319272343Sngie
320272343Sngie	return error;
321272343Sngie}
322