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 59 static int getfh_main(int, char **); 60 static int kqueue_main(int, char **); 61 static int rename_main(int, char **); 62 static int sockets_main(int, char **); 63 static int statvfs_main(int, char **); 64 65 /* --------------------------------------------------------------------- */ 66 67 int 68 getfh_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 126 int 127 kqueue_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 214 int 215 rename_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 231 int 232 sockets_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 #ifdef __FreeBSD__ 247 memset(&addr, 0, sizeof(addr)); 248 #endif 249 (void)strlcpy(addr.sun_path, argv[1], sizeof(addr.sun_path)); 250 addr.sun_family = PF_UNIX; 251 #ifdef __FreeBSD__ 252 error = bind(fd, (struct sockaddr *)&addr, SUN_LEN(&addr)); 253 #else 254 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 255 #endif 256 if (error == -1) { 257 warn("connect"); 258 #ifdef __FreeBSD__ 259 (void)close(fd); 260 #endif 261 return EXIT_FAILURE; 262 } 263 264 close(fd); 265 266 return EXIT_SUCCESS; 267 } 268 269 /* --------------------------------------------------------------------- */ 270 271 int 272 statvfs_main(int argc, char **argv) 273 { 274 int error; 275 struct statvfs buf; 276 277 if (argc < 2) 278 return EXIT_FAILURE; 279 280 error = statvfs(argv[1], &buf); 281 if (error != 0) { 282 warn("statvfs"); 283 return EXIT_FAILURE; 284 } 285 286 (void)printf("f_bsize=%lu\n", buf.f_bsize); 287 (void)printf("f_blocks=%" PRId64 "\n", buf.f_blocks); 288 (void)printf("f_bfree=%" PRId64 "\n", buf.f_bfree); 289 (void)printf("f_files=%" PRId64 "\n", buf.f_files); 290 291 return EXIT_SUCCESS; 292 } 293 294 /* --------------------------------------------------------------------- */ 295 296 int 297 main(int argc, char **argv) 298 { 299 int error; 300 301 if (argc < 2) 302 return EXIT_FAILURE; 303 304 argc -= 1; 305 argv += 1; 306 307 if (strcmp(argv[0], "getfh") == 0) 308 error = getfh_main(argc, argv); 309 else if (strcmp(argv[0], "kqueue") == 0) 310 error = kqueue_main(argc, argv); 311 else if (strcmp(argv[0], "rename") == 0) 312 error = rename_main(argc, argv); 313 else if (strcmp(argv[0], "sockets") == 0) 314 error = sockets_main(argc, argv); 315 else if (strcmp(argv[0], "statvfs") == 0) 316 error = statvfs_main(argc, argv); 317 else 318 error = EXIT_FAILURE; 319 320 return error; 321 } 322