afd24f8eab94e010be66f9f3b8d11e91e7a2045b
[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 #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))
36
37
38
39 extern char     *optarg;
40 extern int       optind, optopt, opterr;
41 char            *Progname;
42
43 extern void     print_victim(void *, size_t, dm_off_t);
44 extern void     err_msg(char *, ...);
45 extern void     errno_msg(char *, ...);
46
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 *);
50 void            usage(char *);
51
52 void
53 usage(
54         char *prog)
55 {
56         fprintf(stderr, "Usage: %s ", prog);
57         fprintf(stderr, " [-s file threshold]");
58         fprintf(stderr, " filesystem\n");
59 }
60
61 /*
62  * Convert an input string on the form 10m or 128K to something reasonable
63  */
64 int
65 verify_size(
66         char            *str,
67         dm_off_t        *sizep)
68 {
69         char            *cp;
70         dm_off_t         size;
71
72         if (strlen(str) > NUMLEN) {
73                 printf("Size %s is invalid \n", str);
74                 return(1);
75         }
76
77         size = strtol(str,0,0); 
78         if (size < 0 || size >= LONG_MAX ) {
79                 printf("Size %d is invalid \n", size);
80                 return(1);
81         }
82
83         cp = str;
84         while (isdigit(*cp))
85                 cp++;
86         if (*cp == 'k' || *cp == 'K') {
87                 if ( size >= (u_int) MAX_K) {
88 #ifdef  __sgi
89                         printf("Size %lld is invalid\n", size);
90 #else
91                         printf("Size %ld is invalid\n", size);
92 #endif
93                         return(1);
94                 }
95                 size *= 1024;
96         } else if (*cp == 'm' || *cp == 'M') {
97                 if ( size >= (u_int) MAX_M) {
98 #ifdef  __sgi
99                         printf("Size %lld is invalid\n", size);
100 #else
101                         printf("Size %ld is invalid\n", size);
102 #endif
103                         return(1);
104                 }
105                 size *= (1024*1024);
106         }
107         *sizep = size;
108         return(0);
109 }
110
111
112
113 int
114 main(
115         int     argc, 
116         char    *argv[])
117 {
118         
119         int              c;
120         int              error;
121         dm_off_t         size;
122         char            *fsname;
123         dm_sessid_t      sid;
124         void            *fs_hanp;
125         size_t           fs_hlen;
126         char            *sizep = "0";
127
128
129         Progname = argv[0];
130         size     = 0;
131
132         while ((c = getopt(argc, argv, "s:")) != EOF) {
133                 switch (c) {
134                 case 's':
135                         sizep = optarg;
136                         break;
137
138                 case '?':
139                 default:
140                         usage(Progname);
141                         exit(1);
142                 }
143         }
144         if (optind >= argc) {
145                 usage(Progname);
146                 exit(1);
147         }
148         /*
149          * Verify the input size string is legit
150          */
151         error = verify_size(sizep, &size);
152         if (error) 
153                 exit(1);
154
155         fsname = argv[optind];
156
157         /*
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
161          */
162         error = setup_dmapi(&sid);
163         if (error) 
164                 exit(1);
165         
166         if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) {
167                 errno_msg("Can't get filesystem handle");
168                 exit(1);
169         }
170
171
172
173         /*
174          * Get the attributes of all files in the filesystem
175          */
176         error = scan_fs(sid, fs_hanp, fs_hlen, size);
177         if (error) 
178                 exit(1);
179         
180
181         /*
182          * We're done, so we can shut down our session.
183          */
184         if (dm_destroy_session(sid) == -1) {
185                 errno_msg("Can't close session");
186                 exit(1);
187         }
188
189         return(0);
190
191 }
192
193 /*
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
196  * criteria.
197  *
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. 
201  */
202 int
203 scan_fs(
204         dm_sessid_t      sid, 
205         void            *fs_hanp, 
206         size_t           fs_hlen, 
207         dm_off_t         target_size)
208 {
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 */
217         int              error; 
218
219
220         /*
221          * Size the stat buffer to return info on 1K files at a time
222          */
223         buflen     = sizeof(dm_stat_t) * 1024;
224 #ifdef  VERITAS_21
225         if (buflen > 65536)
226                 buflen = 65536;
227 #endif
228         dm_statbuf = (dm_stat_t *)calloc(1, buflen);
229         if (dm_statbuf == NULL)  {
230                 err_msg("Can't get memory for stat buffer");
231                 return(1);
232         }
233
234
235         /*
236          * Initialize the offset opaque offset cookie that
237          * we use in successive calls to dm_get_bulkattr()
238          */
239         error = dm_init_attrloc(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &locp);
240         if (error == -1) {
241                 errno_msg("%s/%d: Can't initialize offset cookie (%d)", __FILE__, __LINE__, errno);
242                 free(dm_statbuf);
243                 return(1);
244         }
245
246         /*
247          * Set our stat mask so that we'll only get the normal stat(2)
248          * info and the file's handle
249          */
250         mask = DM_AT_HANDLE | DM_AT_STAT;
251         do {
252                 more = dm_get_bulkattr(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
253                                        mask, &locp, buflen, dm_statbuf, &rlenp);
254                 if (more == -1) {
255                         errno_msg("%s/%d: Can't get bulkattr for filesystem", __FILE__, __LINE__, errno);
256                         break;
257                 }
258
259                 /*
260                  * Walk through the stat buffer and pull out files 
261                  * that are of interest
262                  *
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.
266                  */
267                 sbuf = dm_statbuf;
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);
273
274                                 print_victim(hanp, hlen, sbuf->dt_size);
275                         }
276                         sbuf = DM_STEP_TO_NEXT(sbuf, dm_stat_t *);
277                 }
278         } while (more == 1);
279
280         free(dm_statbuf);
281         if (more == -1) 
282                 return(1);
283
284         return(0);
285 }
286