1/*	$NetBSD: h_tools.c,v 1.8 2007/07/23 15:05:43 jmmv Exp $	*/
2
3/*-
4 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Helper tools for several tests.  These are kept in a single file due
35 * to the limitations of bsd.prog.mk to build a single program in a
36 * given directory.
37 */
38
39#include <sys/param.h>
40#include <sys/types.h>
41#include <sys/event.h>
42#include <sys/mount.h>
43#include <sys/statvfs.h>
44#include <sys/stdint.h>
45#include <sys/socket.h>
46#include <sys/time.h>
47#include <sys/un.h>
48
49#include <assert.h>
50#include <err.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58/* --------------------------------------------------------------------- */
59
60static int getfh_main(int, char **);
61static int kqueue_main(int, char **);
62static int rename_main(int, char **);
63static int sockets_main(int, char **);
64static int statvfs_main(int, char **);
65
66/* --------------------------------------------------------------------- */
67
68int
69getfh_main(int argc, char **argv)
70{
71	int error;
72	fhandle_t fh;
73
74	if (argc < 2)
75		return EXIT_FAILURE;
76
77	error = getfh(argv[1], &fh);
78	if (error == 0)
79		err(EXIT_FAILURE, "can not getfh");
80
81	error = write(STDOUT_FILENO, &fh, sizeof(fh));
82	if (error == -1) {
83		perror("write");
84		return EXIT_FAILURE;
85	}
86
87	return 0;
88}
89
90/* --------------------------------------------------------------------- */
91
92int
93kqueue_main(int argc, char **argv)
94{
95	char *line;
96	int i, kq;
97	size_t len;
98	struct kevent *changes, event;
99
100	if (argc < 2)
101		return EXIT_FAILURE;
102
103	argc--;
104	argv++;
105
106	changes = malloc(sizeof(struct kevent) * (argc - 1));
107	if (changes == NULL)
108		errx(EXIT_FAILURE, "not enough memory");
109
110	for (i = 0; i < argc; i++) {
111		int fd;
112
113		fd = open(argv[i], O_RDONLY);
114		if (fd == -1)
115			err(EXIT_FAILURE, "cannot open %s", argv[i]);
116
117		EV_SET(&changes[i], fd, EVFILT_VNODE,
118		    EV_ADD | EV_ENABLE | EV_ONESHOT,
119		    NOTE_ATTRIB | NOTE_DELETE | NOTE_EXTEND | NOTE_LINK |
120		    NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE,
121		    0, 0);
122	}
123
124	kq = kqueue();
125	if (kq == -1)
126		err(EXIT_FAILURE, "kqueue");
127
128	while ((line = fgetln(stdin, &len)) != NULL) {
129		int ec, nev;
130		struct timespec to;
131
132		to.tv_sec = 0;
133		to.tv_nsec = 100000;
134
135		(void)kevent(kq, changes, argc, &event, 1, &to);
136
137		assert(len > 0);
138		assert(line[len - 1] == '\n');
139		line[len - 1] = '\0';
140		ec = system(line);
141		if (ec != EXIT_SUCCESS)
142			errx(ec, "%s returned %d", line, ec);
143
144		do {
145			nev = kevent(kq, changes, argc, &event, 1, &to);
146			if (nev == -1)
147				err(EXIT_FAILURE, "kevent");
148			else if (nev > 0) {
149				for (i = 0; i < argc; i++)
150					if (event.ident == changes[i].ident)
151						break;
152
153				if (event.fflags & NOTE_ATTRIB)
154					printf("%s - NOTE_ATTRIB\n", argv[i]);
155				if (event.fflags & NOTE_DELETE)
156					printf("%s - NOTE_DELETE\n", argv[i]);
157				if (event.fflags & NOTE_EXTEND)
158					printf("%s - NOTE_EXTEND\n", argv[i]);
159				if (event.fflags & NOTE_LINK)
160					printf("%s - NOTE_LINK\n", argv[i]);
161				if (event.fflags & NOTE_RENAME)
162					printf("%s - NOTE_RENAME\n", argv[i]);
163				if (event.fflags & NOTE_REVOKE)
164					printf("%s - NOTE_REVOKE\n", argv[i]);
165				if (event.fflags & NOTE_WRITE)
166					printf("%s - NOTE_WRITE\n", argv[i]);
167			}
168		} while (nev > 0);
169	}
170
171	for (i = 0; i < argc; i++)
172		close(changes[i].ident);
173	free(changes);
174
175	return EXIT_SUCCESS;
176}
177
178/* --------------------------------------------------------------------- */
179
180int
181rename_main(int argc, char **argv)
182{
183
184	if (argc < 3)
185		return EXIT_FAILURE;
186
187	if (rename(argv[1], argv[2]) == -1) {
188		perror("rename");
189		return EXIT_FAILURE;
190	}
191
192	return EXIT_SUCCESS;
193}
194
195/* --------------------------------------------------------------------- */
196
197int
198sockets_main(int argc, char **argv)
199{
200	int error, fd;
201	struct sockaddr_un addr;
202
203	if (argc < 2)
204		return EXIT_FAILURE;
205
206	fd = socket(PF_LOCAL, SOCK_STREAM, 0);
207	if (fd == -1) {
208		perror("socket");
209		return EXIT_FAILURE;
210	}
211
212	(void)strlcpy(addr.sun_path, argv[1], sizeof(addr.sun_path));
213	addr.sun_family = PF_UNIX;
214
215	error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
216	if (error == -1) {
217		perror("connect");
218		return EXIT_FAILURE;
219	}
220
221	close(fd);
222
223	return EXIT_SUCCESS;
224}
225
226/* --------------------------------------------------------------------- */
227
228int
229statvfs_main(int argc, char **argv)
230{
231	int error;
232	struct statfs buf;
233
234	if (argc < 2)
235		return EXIT_FAILURE;
236
237	memset(&buf, 0, sizeof(buf));
238	buf.f_version = STATFS_VERSION;
239	error = statfs(argv[1], &buf);
240	if (error != 0) {
241		perror("statvfs");
242		return EXIT_FAILURE;
243	}
244
245	(void)printf("f_bsize=%ju\n", (uintmax_t)buf.f_bsize);
246	(void)printf("f_blocks=%ju\n", (uintmax_t)buf.f_blocks);
247	(void)printf("f_bfree=%ju\n", (uintmax_t)buf.f_bfree);
248	(void)printf("f_files=%ju\n", (uintmax_t)buf.f_files);
249
250	return EXIT_SUCCESS;
251}
252
253/* --------------------------------------------------------------------- */
254
255int
256main(int argc, char **argv)
257{
258	int error;
259
260	if (argc < 2)
261		return EXIT_FAILURE;
262
263	argc -= 1;
264	argv += 1;
265
266	if (strcmp(argv[0], "getfh") == 0)
267		error = getfh_main(argc, argv);
268	else if (strcmp(argv[0], "kqueue") == 0)
269		error = kqueue_main(argc, argv);
270	else if (strcmp(argv[0], "rename") == 0)
271		error = rename_main(argc, argv);
272	else if (strcmp(argv[0], "sockets") == 0)
273		error = sockets_main(argc, argv);
274	else if (strcmp(argv[0], "statvfs") == 0)
275		error = statvfs_main(argc, argv);
276	else
277		error = EXIT_FAILURE;
278
279	return error;
280}
281