check: allow '-e testid' to exclude a single test
[xfstests-dev.git] / dmapi / src / sample_hsm / migfind.c
1 /*
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
5  *
6  * The list is not sorted in any way.
7  *
8  * This code was written by Peter Lawthers, and placed in the public
9  * domain for use by DMAPI implementors and app writers.
10  *
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
22  * SUCH DAMAGE.
23  */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <limits.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <sys/stat.h>
30
31 #include <lib/hsm.h>
32
33 #include <getopt.h>
34
35 #define NUMLEN  16              /* arbitrary max len of input size */
36 #define MAX_K   (((u_int)LONG_MAX) / 1024)
37 #define MAX_M   (((u_int)LONG_MAX) / (1024*1024))
38
39
40
41 extern char     *optarg;
42 extern int       optind, optopt, opterr;
43 char            *Progname;
44
45 extern void     print_victim(void *, size_t, dm_off_t);
46 extern void     err_msg(char *, ...);
47 extern void     errno_msg(char *, ...);
48
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 *);
52 void            usage(char *);
53
54 void
55 usage(
56         char *prog)
57 {
58         fprintf(stderr, "Usage: %s ", prog);
59         fprintf(stderr, " [-s file threshold]");
60         fprintf(stderr, " filesystem\n");
61 }
62
63 /*
64  * Convert an input string on the form 10m or 128K to something reasonable
65  */
66 int
67 verify_size(
68         char            *str,
69         dm_off_t        *sizep)
70 {
71         char            *cp;
72         dm_off_t         size;
73
74         if (strlen(str) > NUMLEN) {
75                 printf("Size %s is invalid \n", str);
76                 return(1);
77         }
78
79         size = strtol(str,0,0); 
80         if (size < 0 || size >= LONG_MAX ) {
81                 printf("Size %lld is invalid \n", (long long) size);
82                 return(1);
83         }
84
85         cp = str;
86         while (isdigit(*cp))
87                 cp++;
88         if (*cp == 'k' || *cp == 'K') {
89                 if ( size >= (u_int) MAX_K) {
90                         printf("Size %lld is invalid\n", (long long) size);
91                         return(1);
92                 }
93                 size *= 1024;
94         } else if (*cp == 'm' || *cp == 'M') {
95                 if ( size >= (u_int) MAX_M) {
96                         printf("Size %lld is invalid\n", (long long) size);
97                         return(1);
98                 }
99                 size *= (1024*1024);
100         }
101         *sizep = size;
102         return(0);
103 }
104
105
106
107 int
108 main(
109         int     argc, 
110         char    *argv[])
111 {
112         
113         int              c;
114         int              error;
115         dm_off_t         size;
116         char            *fsname;
117         dm_sessid_t      sid;
118         void            *fs_hanp;
119         size_t           fs_hlen;
120         char            *sizep = "0";
121
122
123         Progname = argv[0];
124         size     = 0;
125
126         while ((c = getopt(argc, argv, "s:")) != EOF) {
127                 switch (c) {
128                 case 's':
129                         sizep = optarg;
130                         break;
131
132                 case '?':
133                 default:
134                         usage(Progname);
135                         exit(1);
136                 }
137         }
138         if (optind >= argc) {
139                 usage(Progname);
140                 exit(1);
141         }
142         /*
143          * Verify the input size string is legit
144          */
145         error = verify_size(sizep, &size);
146         if (error) 
147                 exit(1);
148
149         fsname = argv[optind];
150
151         /*
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
155          */
156         error = setup_dmapi(&sid);
157         if (error) 
158                 exit(1);
159         
160         if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) {
161                 errno_msg("Can't get filesystem handle");
162                 exit(1);
163         }
164
165
166
167         /*
168          * Get the attributes of all files in the filesystem
169          */
170         error = scan_fs(sid, fs_hanp, fs_hlen, size);
171         if (error) 
172                 exit(1);
173         
174
175         /*
176          * We're done, so we can shut down our session.
177          */
178         if (dm_destroy_session(sid) == -1) {
179                 errno_msg("Can't close session");
180                 exit(1);
181         }
182
183         return(0);
184
185 }
186
187 /*
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
190  * criteria.
191  *
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. 
195  */
196 int
197 scan_fs(
198         dm_sessid_t      sid, 
199         void            *fs_hanp, 
200         size_t           fs_hlen, 
201         dm_off_t         target_size)
202 {
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 */
211         int              error; 
212
213
214         /*
215          * Size the stat buffer to return info on 1K files at a time
216          */
217         buflen     = sizeof(dm_stat_t) * 1024;
218 #ifdef  VERITAS_21
219         if (buflen > 65536)
220                 buflen = 65536;
221 #endif
222         dm_statbuf = (dm_stat_t *)calloc(1, buflen);
223         if (dm_statbuf == NULL)  {
224                 err_msg("Can't get memory for stat buffer");
225                 return(1);
226         }
227
228
229         /*
230          * Initialize the offset opaque offset cookie that
231          * we use in successive calls to dm_get_bulkattr()
232          */
233         error = dm_init_attrloc(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &locp);
234         if (error == -1) {
235                 errno_msg("%s/%d: Can't initialize offset cookie (%d)", __FILE__, __LINE__, errno);
236                 free(dm_statbuf);
237                 return(1);
238         }
239
240         /*
241          * Set our stat mask so that we'll only get the normal stat(2)
242          * info and the file's handle
243          */
244         mask = DM_AT_HANDLE | DM_AT_STAT;
245         do {
246                 more = dm_get_bulkattr(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
247                                        mask, &locp, buflen, dm_statbuf, &rlenp);
248                 if (more == -1) {
249                         errno_msg("%s/%d: Can't get bulkattr for filesystem", __FILE__, __LINE__, errno);
250                         break;
251                 }
252
253                 /*
254                  * Walk through the stat buffer and pull out files 
255                  * that are of interest
256                  *
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.
260                  */
261                 sbuf = dm_statbuf;
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);
267
268                                 print_victim(hanp, hlen, sbuf->dt_size);
269                         }
270                         sbuf = DM_STEP_TO_NEXT(sbuf, dm_stat_t *);
271                 }
272         } while (more == 1);
273
274         free(dm_statbuf);
275         if (more == -1) 
276                 return(1);
277
278         return(0);
279 }
280