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