1 /*- 2 * Copyright (c) 2023 Klara, Inc. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <err.h> 8 #include <fcntl.h> 9 #include <stdbool.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <sysexits.h> 13 #include <unistd.h> 14 15 static bool verbose; 16 17 /* 18 * Returns true if the file named by its argument is sparse, i.e. if 19 * seeking to SEEK_HOLE returns a different value than seeking to 20 * SEEK_END. 21 */ 22 static bool 23 sparse(const char *filename) 24 { 25 off_t hole, end; 26 int fd; 27 28 if ((fd = open(filename, O_RDONLY)) < 0 || 29 (hole = lseek(fd, 0, SEEK_HOLE)) < 0 || 30 (end = lseek(fd, 0, SEEK_END)) < 0) 31 err(1, "%s", filename); 32 close(fd); 33 if (end > hole) { 34 if (verbose) 35 printf("%s: hole at %zu\n", filename, (size_t)hole); 36 return (true); 37 } 38 return (false); 39 } 40 41 static void 42 usage(void) 43 { 44 45 fprintf(stderr, "usage: sparse [-v] file [...]\n"); 46 exit(EX_USAGE); 47 } 48 49 int 50 main(int argc, char *argv[]) 51 { 52 int opt, rv; 53 54 while ((opt = getopt(argc, argv, "v")) != -1) { 55 switch (opt) { 56 case 'v': 57 verbose = true; 58 break; 59 default: 60 usage(); 61 break; 62 } 63 } 64 argc -= optind; 65 argv += optind; 66 if (argc == 0) 67 usage(); 68 rv = EXIT_SUCCESS; 69 while (argc-- > 0) 70 if (!sparse(*argv++)) 71 rv = EXIT_FAILURE; 72 exit(rv); 73 } 74