2 * Simple utility to find all files above a certain size in
3 * a filesystem. The output is to stdout, and is of the form:
4 * filehandle length filehandle file size in bytes
6 * The list is not sorted in any way.
8 * This code was written by Peter Lawthers, and placed in the public
9 * domain for use by DMAPI implementors and app writers.
11 * Standard disclaimer:
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
13 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
16 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #define NUMLEN 16 /* arbitrary max len of input size */
36 #define MAX_K (((u_int)LONG_MAX + 1) / 1024)
37 #define MAX_M (((u_int)LONG_MAX + 1) / (1024*1024))
42 extern int optind, optopt, opterr;
45 extern void print_victim(void *, size_t, dm_off_t);
46 extern void err_msg(char *, ...);
47 extern void errno_msg(char *, ...);
49 int setup_dmapi(dm_sessid_t *);
50 int scan_fs(dm_sessid_t, void *, size_t, dm_off_t);
51 int verify_size(char *, dm_off_t *);
58 fprintf(stderr, "Usage: %s ", prog);
59 fprintf(stderr, " [-s file threshold]");
60 fprintf(stderr, " filesystem\n");
64 * Convert an input string on the form 10m or 128K to something reasonable
74 if (strlen(str) > NUMLEN) {
75 printf("Size %s is invalid \n", str);
79 size = strtol(str,0,0);
80 if (size < 0 || size >= LONG_MAX ) {
81 printf("Size %lld is invalid \n", size);
88 if (*cp == 'k' || *cp == 'K') {
89 if ( size >= (u_int) MAX_K) {
90 printf("Size %lld is invalid\n", size);
94 } else if (*cp == 'm' || *cp == 'M') {
95 if ( size >= (u_int) MAX_M) {
96 printf("Size %lld is invalid\n", size);
126 while ((c = getopt(argc, argv, "s:")) != EOF) {
138 if (optind >= argc) {
143 * Verify the input size string is legit
145 error = verify_size(sizep, &size);
149 fsname = argv[optind];
152 * Now we have our filesystem name and possibly a size threshold
153 * to look for. Init the dmapi, and get a filesystem handle so
154 * we can scan the filesystem
156 error = setup_dmapi(&sid);
160 if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) {
161 errno_msg("Can't get filesystem handle");
168 * Get the attributes of all files in the filesystem
170 error = scan_fs(sid, fs_hanp, fs_hlen, size);
176 * We're done, so we can shut down our session.
178 if (dm_destroy_session(sid) == -1) {
179 errno_msg("Can't close session");
188 * Get the attributes for all the files in a filesystem in bulk,
189 * and print out the handles and sizes of any that meet our target
192 * We are not interested in file names; if we were, then we would
193 * have to do a dm_get_dirattrs() on each directroy, then use
194 * dm_handle_to_path() to get the pathname.
201 dm_off_t target_size)
203 u_int mask; /* attributes to scan for */
204 dm_stat_t *dm_statbuf, *sbuf; /* attributes buffer */
205 dm_attrloc_t locp; /* opaque location in fs */
206 size_t rlenp; /* ret length of stat info */
207 size_t buflen; /* length of stat buffer */
208 void *hanp; /* file handle */
209 size_t hlen; /* file handle */
210 int more; /* loop terminator */
215 * Size the stat buffer to return info on 1K files at a time
217 buflen = sizeof(dm_stat_t) * 1024;
222 dm_statbuf = (dm_stat_t *)calloc(1, buflen);
223 if (dm_statbuf == NULL) {
224 err_msg("Can't get memory for stat buffer");
230 * Initialize the offset opaque offset cookie that
231 * we use in successive calls to dm_get_bulkattr()
233 error = dm_init_attrloc(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &locp);
235 errno_msg("%s/%d: Can't initialize offset cookie (%d)", __FILE__, __LINE__, errno);
241 * Set our stat mask so that we'll only get the normal stat(2)
242 * info and the file's handle
244 mask = DM_AT_HANDLE | DM_AT_STAT;
246 more = dm_get_bulkattr(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
247 mask, &locp, buflen, dm_statbuf, &rlenp);
249 errno_msg("%s/%d: Can't get bulkattr for filesystem", __FILE__, __LINE__, errno);
254 * Walk through the stat buffer and pull out files
255 * that are of interest
257 * The stat buffer is variable length, so we must
258 * use the DM_STEP_TO_NEXT macro to access each individual
259 * dm_stat_t structure in the returned buffer.
262 while (sbuf != NULL) {
263 if (S_ISREG(sbuf->dt_mode) &&
264 sbuf->dt_size >= target_size) {
265 hanp = DM_GET_VALUE(sbuf, dt_handle, void *);
266 hlen = DM_GET_LEN(sbuf, dt_handle);
268 print_victim(hanp, hlen, sbuf->dt_size);
270 sbuf = DM_STEP_TO_NEXT(sbuf, dm_stat_t *);