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 /* --------------------------------------------------------------------- */ 54 55 static int getfh_main(int, char **); 56 static int kqueue_main(int, char **); 57 static int rename_main(int, char **); 58 static int sockets_main(int, char **); 59 static int statvfs_main(int, char **); 60 61 /* --------------------------------------------------------------------- */ 62 63 int 64 getfh_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 warn("getfh"); 96 return EXIT_FAILURE; 97 } 98 } 99 } 100 101 error = write(STDOUT_FILENO, fh, fh_size); 102 if (error == -1) { 103 warn("write"); 104 return EXIT_FAILURE; 105 } 106 free(fh); 107 108 return 0; 109 } 110 111 /* --------------------------------------------------------------------- */ 112 113 int 114 kqueue_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 201 int 202 rename_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 warn("rename"); 210 return EXIT_FAILURE; 211 } 212 213 return EXIT_SUCCESS; 214 } 215 216 /* --------------------------------------------------------------------- */ 217 218 int 219 sockets_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 warn("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 warn("connect"); 239 return EXIT_FAILURE; 240 } 241 242 close(fd); 243 244 return EXIT_SUCCESS; 245 } 246 247 /* --------------------------------------------------------------------- */ 248 249 int 250 statvfs_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 warn("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 274 int 275 main(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