Add DMAPI tests test_bulkall, test_bulkattr.
[xfstests-dev.git] / dmapi / src / suite2 / src / test_bulkall.c
1 /*
2  * This code was written by Peter Lawthers, and placed in the public
3  * domain for use by DMAPI implementors and app writers.
4  *
5  * Standard disclaimer:
6  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
7  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
10  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
11  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
15  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16  * SUCH DAMAGE.
17  *
18  * October 1, 2003: Dean Roehrich
19  *  - Adapted to test dm_get_bulkall, from migfind.c.
20  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <sys/stat.h>
27
28 #include <lib/hsm.h>
29
30 #include <getopt.h>
31
32
33 extern char     *optarg;
34 extern int       optind, optopt, opterr;
35 char            *Progname;
36
37 extern void     err_msg(char *, ...);
38 extern void     errno_msg(char *, ...);
39
40 int             setup_dmapi(dm_sessid_t *);
41 int             scan_fs(dm_sessid_t, void *, size_t, dm_attrname_t*, size_t,
42                         int, int);
43 void            usage(char *);
44
45 void
46 usage(
47         char *prog)
48 {
49         fprintf(stderr, "Usage: %s ", prog);
50         fprintf(stderr, " <-a attrname> [-b bufsz] [-v] [-q]");
51         fprintf(stderr, " filesystem\n");
52 }
53
54 #define V_PRINT         0x01
55 #define V_VERBOSE       0x02
56
57 int
58 main(
59         int     argc, 
60         char    *argv[])
61 {
62         
63         int              c;
64         int              error;
65         char            *fsname;
66         dm_sessid_t      sid;
67         void            *fs_hanp;
68         size_t           fs_hlen;
69         dm_attrname_t   dmattr;
70         size_t          bufsz = 65536;
71         dm_size_t       ret;
72         int             extras = 0;
73         int             verbose = V_PRINT;
74
75         Progname = argv[0];
76         memset(&dmattr, 0, sizeof(dmattr));
77
78         while ((c = getopt(argc, argv, "a:b:evq")) != EOF) {
79                 switch (c) {
80                 case 'a':
81                         if (strlen(optarg) > (DM_ATTR_NAME_SIZE-1)){
82                                 printf("Arg for -a too long\n");
83                                 exit(1);
84                         }
85                         strcpy((char*)dmattr.an_chars, optarg);
86                         break;
87                 case 'b':
88                         bufsz = atoi(optarg);
89                         break;
90                 case 'e':
91                         extras++;
92                         break;
93                 case 'v':
94                         verbose |= V_VERBOSE;
95                         break;
96                 case 'q':
97                         verbose &= ~V_PRINT;
98                         break;
99                 case '?':
100                 default:
101                         usage(Progname);
102                         exit(1);
103                 }
104         }
105         if (optind >= argc) {
106                 usage(Progname);
107                 exit(1);
108         }
109         if (dmattr.an_chars[0] == '\0') {
110                 usage(Progname);
111                 exit(1);
112         }
113         fsname = argv[optind];
114
115         /*
116          * Now we have our filesystem name and possibly a size threshold
117          * to look for. Init the dmapi, and get a filesystem handle so
118          * we can scan the filesystem
119          */
120         error = setup_dmapi(&sid);
121         if (error) 
122                 exit(1);
123         
124         if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) {
125                 errno_msg("Can't get filesystem handle");
126                 exit(1);
127         }
128
129
130         if( dm_get_config(fs_hanp, fs_hlen, DM_CONFIG_BULKALL, &ret) ||
131            (ret != DM_TRUE)) {
132                 printf("Kernel does not have dm_get_bulkall\n");
133                 exit(1);
134         }
135
136         /*
137          * Get the attributes of all files in the filesystem
138          */
139         error = scan_fs(sid, fs_hanp, fs_hlen, &dmattr, bufsz, extras, verbose);
140         if (error) 
141                 exit(1);
142         
143
144         /*
145          * We're done, so we can shut down our session.
146          */
147         if (dm_destroy_session(sid) == -1) {
148                 errno_msg("Can't close session");
149                 exit(1);
150         }
151
152         return(0);
153
154 }
155
156 void
157 my_print_victim(
158         void            *hanp,
159         size_t          hlen,
160         dm_xstat_t      *xbuf,
161         dm_stat_t       *sbuf,
162         int             extras,
163         int             verbose)
164 {
165         u_int            attrlen;
166         char            *attrval;
167
168         if (hlen > HANDLE_LEN) {
169                 if (verbose & V_PRINT)
170                         printf("-- invalid length --\n");
171         }
172         else {
173                 char handle_str[HANDLE_STR];
174                 if (verbose & V_PRINT) {
175                         printf("%d\t", hlen);
176                         hantoa(hanp, hlen, handle_str);
177                         printf("%s ", handle_str);
178                         if (extras) {
179                                 printf("size=%lld ",
180                                        (int64_t)sbuf->dt_size);
181                                 printf("ino=%lld ",
182                                        (int64_t)sbuf->dt_ino);
183                         }
184                 }
185
186                 attrval = DM_GET_VALUE(xbuf,
187                                   dx_attrdata, char*);
188                 attrlen = DM_GET_LEN(xbuf,
189                                   dx_attrdata);
190                 /* Hmmm, a hole in the dmapi spec.
191                  * No way to have a null pointer
192                  * for the value.  No way to
193                  * distinguish between a zero-length
194                  * attribute value and not finding
195                  * the attribute in the first place.
196                  *
197                  * Punt.  Since I cannot get a null
198                  * pointer for the value, let's look
199                  * at the length.  If it's zero,
200                  * we'll say the attribute was
201                  * not found.
202                  */
203                 if (verbose & V_PRINT) {
204                         if (attrlen) {
205                                 printf("%d (%s)\n",
206                                        attrlen,
207                                        isalpha(attrval[0]) ? attrval : "");
208                         }
209                         else {
210                                 printf("<none>\n");
211                         }
212                 }
213         }
214 }
215
216 /*
217  * Get the attributes for all the files in a filesystem in bulk,
218  * including the specified dmattr,
219  * and print out the handles and dmattr values.
220  */
221 int
222 scan_fs(
223         dm_sessid_t      sid, 
224         void            *fs_hanp, 
225         size_t           fs_hlen, 
226         dm_attrname_t   *dmattr,
227         size_t          buflen,
228         int             extras,
229         int             verbose)
230 {
231         u_int            mask;                  /* attributes to scan for */
232         dm_xstat_t      *dm_xstatbuf, *xbuf;    /* attributes buffer */
233         dm_stat_t       *sbuf;
234         dm_attrloc_t     locp;                  /* opaque location in fs */
235         size_t           rlenp;                 /* ret length of stat info */
236         void            *hanp;                  /* file handle */
237         size_t           hlen;                  /* file handle */
238         int              more;                  /* loop terminator */
239         int              error; 
240
241 #ifdef  VERITAS_21
242         if (buflen > 65536)
243                 buflen= 65536;
244 #endif
245         dm_xstatbuf = (dm_xstat_t *)calloc(1, buflen);
246         if (dm_xstatbuf == NULL)  {
247                 err_msg("Can't get memory for stat buffer");
248                 return(1);
249         }
250
251
252         /*
253          * Initialize the offset opaque offset cookie that
254          * we use in successive calls to dm_get_bulkattr()
255          */
256         error = dm_init_attrloc(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &locp);
257         if (error == -1) {
258                 errno_msg("%s/%d: Can't initialize offset cookie (%d)", __FILE__, __LINE__, errno);
259                 free(dm_xstatbuf);
260                 return(1);
261         }
262
263         /*
264          * Set our stat mask so that we'll only get the normal stat(2)
265          * info and the file's handle
266          */
267         mask = DM_AT_HANDLE | DM_AT_STAT;
268         do {
269                 more = dm_get_bulkall(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
270                                       mask, dmattr, &locp, buflen,
271                                       dm_xstatbuf, &rlenp);
272                 if (verbose & V_VERBOSE)
273                         fprintf(stderr, "BULKALL more=%d, rlen=%d\n", more, rlenp);
274                 if (more == -1) {
275                         errno_msg("%s/%d: Can't get bulkall for filesystem", __FILE__, __LINE__, errno);
276                         break;
277                 }
278
279                 /*
280                  * Walk through the stat buffer and pull out files 
281                  * that are of interest
282                  *
283                  * The stat buffer is variable length, so we must
284                  * use the DM_STEP_TO_NEXT macro to access each individual
285                  * dm_xstat_t structure in the returned buffer.
286                  */
287                 xbuf = dm_xstatbuf;
288                 while (xbuf != NULL) {
289                         sbuf = &xbuf->dx_statinfo;
290                         if (S_ISREG(sbuf->dt_mode)) {
291                                 hanp = DM_GET_VALUE(sbuf, dt_handle, void *);
292                                 hlen = DM_GET_LEN(sbuf, dt_handle);
293
294                                 my_print_victim(hanp, hlen, xbuf, sbuf,
295                                                 extras, verbose);
296                         }
297                         /* The sbuf has the offset to the next xbuf */
298                         xbuf = DM_STEP_TO_NEXT(sbuf, dm_xstat_t *);
299                 }
300         } while (more == 1);
301
302         free(dm_xstatbuf);
303         if (more == -1) 
304                 return(1);
305
306         return(0);
307 }
308