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
33 #define NUMLEN 16 /* arbitrary max len of input size */
34 #define MAX_K (((u_int)LONG_MAX + 1) / 1024)
35 #define MAX_M (((u_int)LONG_MAX + 1) / (1024*1024))
40 extern int optind, optopt, opterr;
43 extern void print_victim(void *, size_t, dm_off_t);
44 extern void err_msg(char *, ...);
45 extern void errno_msg(char *, ...);
47 int setup_dmapi(dm_sessid_t *);
48 int scan_fs(dm_sessid_t, void *, size_t, dm_off_t);
49 int verify_size(char *, dm_off_t *);
56 fprintf(stderr, "Usage: %s ", prog);
57 fprintf(stderr, " [-s file threshold]");
58 fprintf(stderr, " filesystem\n");
62 * Convert an input string on the form 10m or 128K to something reasonable
72 if (strlen(str) > NUMLEN) {
73 printf("Size %s is invalid \n", str);
77 size = strtol(str,0,0);
78 if (size < 0 || size >= LONG_MAX ) {
79 printf("Size %d is invalid \n", size);
86 if (*cp == 'k' || *cp == 'K') {
87 if ( size >= (u_int) MAX_K) {
89 printf("Size %lld is invalid\n", size);
91 printf("Size %ld is invalid\n", size);
96 } else if (*cp == 'm' || *cp == 'M') {
97 if ( size >= (u_int) MAX_M) {
99 printf("Size %lld is invalid\n", size);
101 printf("Size %ld is invalid\n", size);
132 while ((c = getopt(argc, argv, "s:")) != EOF) {
144 if (optind >= argc) {
149 * Verify the input size string is legit
151 error = verify_size(sizep, &size);
155 fsname = argv[optind];
158 * Now we have our filesystem name and possibly a size threshold
159 * to look for. Init the dmapi, and get a filesystem handle so
160 * we can scan the filesystem
162 error = setup_dmapi(&sid);
166 if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) {
167 errno_msg("Can't get filesystem handle");
174 * Get the attributes of all files in the filesystem
176 error = scan_fs(sid, fs_hanp, fs_hlen, size);
182 * We're done, so we can shut down our session.
184 if (dm_destroy_session(sid) == -1) {
185 errno_msg("Can't close session");
194 * Get the attributes for all the files in a filesystem in bulk,
195 * and print out the handles and sizes of any that meet our target
198 * We are not interested in file names; if we were, then we would
199 * have to do a dm_get_dirattrs() on each directroy, then use
200 * dm_handle_to_path() to get the pathname.
207 dm_off_t target_size)
209 u_int mask; /* attributes to scan for */
210 dm_stat_t *dm_statbuf, *sbuf; /* attributes buffer */
211 dm_attrloc_t locp; /* opaque location in fs */
212 size_t rlenp; /* ret length of stat info */
213 size_t buflen; /* length of stat buffer */
214 void *hanp; /* file handle */
215 size_t hlen; /* file handle */
216 int more; /* loop terminator */
221 * Size the stat buffer to return info on 1K files at a time
223 buflen = sizeof(dm_stat_t) * 1024;
228 dm_statbuf = (dm_stat_t *)calloc(1, buflen);
229 if (dm_statbuf == NULL) {
230 err_msg("Can't get memory for stat buffer");
236 * Initialize the offset opaque offset cookie that
237 * we use in successive calls to dm_get_bulkattr()
239 error = dm_init_attrloc(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &locp);
241 errno_msg("%s/%d: Can't initialize offset cookie (%d)", __FILE__, __LINE__, errno);
247 * Set our stat mask so that we'll only get the normal stat(2)
248 * info and the file's handle
250 mask = DM_AT_HANDLE | DM_AT_STAT;
252 more = dm_get_bulkattr(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
253 mask, &locp, buflen, dm_statbuf, &rlenp);
255 errno_msg("%s/%d: Can't get bulkattr for filesystem", __FILE__, __LINE__, errno);
260 * Walk through the stat buffer and pull out files
261 * that are of interest
263 * The stat buffer is variable length, so we must
264 * use the DM_STEP_TO_NEXT macro to access each individual
265 * dm_stat_t structure in the returned buffer.
268 while (sbuf != NULL) {
269 if (S_ISREG(sbuf->dt_mode) &&
270 sbuf->dt_size >= target_size) {
271 hanp = DM_GET_VALUE(sbuf, dt_handle, void *);
272 hlen = DM_GET_LEN(sbuf, dt_handle);
274 print_victim(hanp, hlen, sbuf->dt_size);
276 sbuf = DM_STEP_TO_NEXT(sbuf, dm_stat_t *);