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