h_tools.c revision 313514
1/*	$NetBSD: h_tools.c,v 1.4 2011/06/11 18:03:17 christos 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#ifdef __FreeBSD__
54#include <inttypes.h>
55#endif
56
57/* --------------------------------------------------------------------- */
58
59static int getfh_main(int, char **);
60static int kqueue_main(int, char **);
61static int rename_main(int, char **);
62static int sockets_main(int, char **);
63static int statvfs_main(int, char **);
64
65/* --------------------------------------------------------------------- */
66
67int
68getfh_main(int argc, char **argv)
69{
70	int error;
71	void *fh;
72	size_t fh_size;
73
74	if (argc < 2)
75		return EXIT_FAILURE;
76
77#ifdef __FreeBSD__
78	fh_size = sizeof(fhandle_t);
79#else
80	fh_size = 0;
81#endif
82
83	fh = NULL;
84	for (;;) {
85		if (fh_size) {
86			fh = malloc(fh_size);
87			if (fh == NULL) {
88				fprintf(stderr, "out of memory");
89				return EXIT_FAILURE;
90			}
91		}
92		/*
93		 * The kernel provides the necessary size in fh_size -
94		 * but it may change if someone moves things around,
95		 * so retry untill we have enough memory.
96		 */
97#ifdef __FreeBSD__
98		error = getfh(argv[1], fh);
99#else
100		error = getfh(argv[1], fh, &fh_size);
101#endif
102		if (error == 0) {
103			break;
104		} else {
105			if (fh != NULL)
106				free(fh);
107			if (errno != E2BIG) {
108				warn("getfh");
109				return EXIT_FAILURE;
110			}
111		}
112	}
113
114	error = write(STDOUT_FILENO, fh, fh_size);
115	if (error == -1) {
116		warn("write");
117		return EXIT_FAILURE;
118	}
119	free(fh);
120
121	return 0;
122}
123
124/* --------------------------------------------------------------------- */
125
126int
127kqueue_main(int argc, char **argv)
128{
129	char *line;
130	int i, kq;
131	size_t len;
132	struct kevent *changes, event;
133
134	if (argc < 2)
135		return EXIT_FAILURE;
136
137	argc--;
138	argv++;
139
140	changes = malloc(sizeof(struct kevent) * argc);
141	if (changes == NULL)
142		errx(EXIT_FAILURE, "not enough memory");
143
144	for (i = 0; i < argc; i++) {
145		int fd;
146
147		fd = open(argv[i], O_RDONLY);
148		if (fd == -1)
149			err(EXIT_FAILURE, "cannot open %s", argv[i]);
150
151		EV_SET(&changes[i], fd, EVFILT_VNODE,
152		    EV_ADD | EV_ENABLE | EV_ONESHOT,
153		    NOTE_ATTRIB | NOTE_DELETE | NOTE_EXTEND | NOTE_LINK |
154		    NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE,
155		    0, 0);
156	}
157
158	kq = kqueue();
159	if (kq == -1)
160		err(EXIT_FAILURE, "kqueue");
161
162	while ((line = fgetln(stdin, &len)) != NULL) {
163		int ec, nev;
164		struct timespec to;
165
166		to.tv_sec = 0;
167		to.tv_nsec = 100000;
168
169		(void)kevent(kq, changes, argc, &event, 1, &to);
170
171		assert(len > 0);
172		assert(line[len - 1] == '\n');
173		line[len - 1] = '\0';
174		ec = system(line);
175		if (ec != EXIT_SUCCESS)
176			errx(ec, "%s returned %d", line, ec);
177
178		do {
179			nev = kevent(kq, changes, argc, &event, 1, &to);
180			if (nev == -1)
181				err(EXIT_FAILURE, "kevent");
182			else if (nev > 0) {
183				for (i = 0; i < argc; i++)
184					if (event.ident == changes[i].ident)
185						break;
186
187				if (event.fflags & NOTE_ATTRIB)
188					printf("%s - NOTE_ATTRIB\n", argv[i]);
189				if (event.fflags & NOTE_DELETE)
190					printf("%s - NOTE_DELETE\n", argv[i]);
191				if (event.fflags & NOTE_EXTEND)
192					printf("%s - NOTE_EXTEND\n", argv[i]);
193				if (event.fflags & NOTE_LINK)
194					printf("%s - NOTE_LINK\n", argv[i]);
195				if (event.fflags & NOTE_RENAME)
196					printf("%s - NOTE_RENAME\n", argv[i]);
197				if (event.fflags & NOTE_REVOKE)
198					printf("%s - NOTE_REVOKE\n", argv[i]);
199				if (event.fflags & NOTE_WRITE)
200					printf("%s - NOTE_WRITE\n", argv[i]);
201			}
202		} while (nev > 0);
203	}
204
205	for (i = 0; i < argc; i++)
206		close(changes[i].ident);
207	free(changes);
208
209	return EXIT_SUCCESS;
210}
211
212/* --------------------------------------------------------------------- */
213
214int
215rename_main(int argc, char **argv)
216{
217
218	if (argc < 3)
219		return EXIT_FAILURE;
220
221	if (rename(argv[1], argv[2]) == -1) {
222		warn("rename");
223		return EXIT_FAILURE;
224	}
225
226	return EXIT_SUCCESS;
227}
228
229/* --------------------------------------------------------------------- */
230
231int
232sockets_main(int argc, char **argv)
233{
234	int error, fd;
235	struct sockaddr_un addr;
236
237	if (argc < 2)
238		return EXIT_FAILURE;
239
240	fd = socket(PF_LOCAL, SOCK_STREAM, 0);
241	if (fd == -1) {
242		warn("socket");
243		return EXIT_FAILURE;
244	}
245
246	(void)strlcpy(addr.sun_path, argv[1], sizeof(addr.sun_path));
247	addr.sun_family = PF_UNIX;
248
249	error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
250	if (error == -1) {
251		warn("connect");
252		return EXIT_FAILURE;
253	}
254
255	close(fd);
256
257	return EXIT_SUCCESS;
258}
259
260/* --------------------------------------------------------------------- */
261
262int
263statvfs_main(int argc, char **argv)
264{
265	int error;
266	struct statvfs buf;
267
268	if (argc < 2)
269		return EXIT_FAILURE;
270
271	error = statvfs(argv[1], &buf);
272	if (error != 0) {
273		warn("statvfs");
274		return EXIT_FAILURE;
275	}
276
277	(void)printf("f_bsize=%lu\n", buf.f_bsize);
278	(void)printf("f_blocks=%" PRId64 "\n", buf.f_blocks);
279	(void)printf("f_bfree=%" PRId64 "\n", buf.f_bfree);
280	(void)printf("f_files=%" PRId64 "\n", buf.f_files);
281
282	return EXIT_SUCCESS;
283}
284
285/* --------------------------------------------------------------------- */
286
287int
288main(int argc, char **argv)
289{
290	int error;
291
292	if (argc < 2)
293		return EXIT_FAILURE;
294
295	argc -= 1;
296	argv += 1;
297
298	if (strcmp(argv[0], "getfh") == 0)
299		error = getfh_main(argc, argv);
300	else if (strcmp(argv[0], "kqueue") == 0)
301		error = kqueue_main(argc, argv);
302	else if (strcmp(argv[0], "rename") == 0)
303		error = rename_main(argc, argv);
304	else if (strcmp(argv[0], "sockets") == 0)
305		error = sockets_main(argc, argv);
306	else if (strcmp(argv[0], "statvfs") == 0)
307		error = statvfs_main(argc, argv);
308	else
309		error = EXIT_FAILURE;
310
311	return error;
312}
313