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