generic/60[78]: ensure the initial DAX file flag state before test
[xfstests-dev.git] / dmapi / src / common / lib / util.c
1 /*
2  * Utility routines
3  *
4  * This code was written by Peter Lawthers, and placed in the public
5  * domain for use by DMAPI implementors and app writers.
6  *
7  * Standard disclaimer:
8  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
12  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18  * SUCH DAMAGE.
19  */
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23
24 #include <unistd.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27
28 #include <lib/hsm.h>
29
30 #include <string.h>
31 #include <time.h>
32 #ifdef linux
33 #include <stdint.h>
34 #define S_IAMB (S_IRWXU|S_IRWXG|S_IRWXO)
35 #endif
36
37 #define S_MASK  (S_ISUID|S_ISGID|S_ISVTX|S_IAMB)
38
39 extern char     *Progname;
40 extern int       errno;
41
42 void             err_msg(char *, ...);
43 void             errno_msg(char *, ...);
44
45 struct ev_name_to_value ev_names[] = {
46         { "DM_EVENT_CANCEL",            DM_EVENT_CANCEL         },
47         { "DM_EVENT_MOUNT",             DM_EVENT_MOUNT          },
48         { "DM_EVENT_PREUNMOUNT",        DM_EVENT_PREUNMOUNT     },
49         { "DM_EVENT_UNMOUNT",           DM_EVENT_UNMOUNT        },
50         { "DM_EVENT_DEBUT",             DM_EVENT_DEBUT          },
51         { "DM_EVENT_CREATE",            DM_EVENT_CREATE         },
52         { "DM_EVENT_CLOSE",             DM_EVENT_CLOSE          },
53         { "DM_EVENT_POSTCREATE",        DM_EVENT_POSTCREATE     },
54         { "DM_EVENT_REMOVE",            DM_EVENT_REMOVE         },
55         { "DM_EVENT_POSTREMOVE",        DM_EVENT_POSTREMOVE     },
56         { "DM_EVENT_RENAME",            DM_EVENT_RENAME         },
57         { "DM_EVENT_POSTRENAME",        DM_EVENT_POSTRENAME     },
58         { "DM_EVENT_LINK",              DM_EVENT_LINK           },
59         { "DM_EVENT_POSTLINK",          DM_EVENT_POSTLINK       },
60         { "DM_EVENT_SYMLINK",           DM_EVENT_SYMLINK        },
61         { "DM_EVENT_POSTSYMLINK",       DM_EVENT_POSTSYMLINK    },
62         { "DM_EVENT_READ",              DM_EVENT_READ           },
63         { "DM_EVENT_WRITE",             DM_EVENT_WRITE          },
64         { "DM_EVENT_TRUNCATE",          DM_EVENT_TRUNCATE       },
65         { "DM_EVENT_ATTRIBUTE",         DM_EVENT_ATTRIBUTE      },
66         { "DM_EVENT_DESTROY",           DM_EVENT_DESTROY        },
67         { "DM_EVENT_NOSPACE",           DM_EVENT_NOSPACE        },
68         { "DM_EVENT_USER",              DM_EVENT_USER           }
69 };
70
71 int     ev_namecnt = sizeof(ev_names) / sizeof(ev_names[0]);
72
73 dm_eventtype_t
74 ev_name_to_value(
75         char            *name)
76 {
77         int             i;
78
79         for (i = 0; i < ev_namecnt; i++) {
80                 if (!strcmp(name, ev_names[i].name)) 
81                         return(ev_names[i].value);
82         }
83         return(DM_EVENT_INVALID);
84 }
85
86 char *
87 ev_value_to_name(
88         dm_eventtype_t  event)
89 {
90         static char             buffer[100];
91         int             i;
92
93         for (i = 0; i < ev_namecnt; i++) {
94                 if (event == ev_names[i].value)
95                         return(ev_names[i].name);
96         }
97         sprintf(buffer, "Unknown Event Number %d\n", event);
98         return(buffer);
99 }
100
101
102
103 struct rt_name_to_value rt_names[] = {
104         { "DM_RIGHT_NULL",              DM_RIGHT_NULL           },
105         { "DM_RIGHT_SHARED",            DM_RIGHT_SHARED         },
106         { "DM_RIGHT_EXCL",              DM_RIGHT_EXCL           }
107 };
108
109 int     rt_namecnt = sizeof(rt_names) / sizeof(rt_names[0]);
110
111 int
112 rt_name_to_value(
113         char            *name,
114         dm_right_t      *rightp)
115 {
116         int             i;
117
118         for (i = 0; i < rt_namecnt; i++) {
119                 if (!strcmp(name, rt_names[i].name)) {
120                         *rightp = rt_names[i].value;
121                         return(0);
122                 }
123         }
124         return(1);
125 }
126
127
128 char *
129 rt_value_to_name(
130         dm_right_t      right)
131 {
132         int             i;
133
134         for (i = 0; i < rt_namecnt; i++) {
135                 if (right == rt_names[i].value)
136                         return(rt_names[i].name);
137         }
138         return(NULL);
139 }
140  
141  
142 /*
143  * Convert a handle from (possibly) binary to ascii. 
144  */
145 void
146 hantoa(
147         void    *hanp,
148         size_t   hlen,
149         char    *handle_str)
150 {
151         int     i;
152         u_char  *cp;
153
154         cp = (u_char *)hanp;
155         for (i=0;i<hlen; i++)  {
156                 sprintf(handle_str, "%.2x", *cp++);
157                 handle_str += 2;
158         }
159         *handle_str = '\0';     /* Null-terminate to make it printable */
160 }
161
162 /*
163  * Convert a handle from ascii back to it's native binary representation
164  */
165
166 int
167 atohan(
168         char    *handle_str,
169         void    **hanpp,
170         size_t   *hlenp) 
171 {
172         u_char  handle[HANDLE_LEN];
173         char    cur_char[3];
174         int     i = 0;
175         u_long  num;
176
177         if (strlen(handle_str) > HANDLE_LEN * 2){
178                 return(EBADF);
179         }
180
181         while (*handle_str && *(handle_str + 1)) {
182                 if (i == HANDLE_LEN){
183                         return(EBADF);
184                 }
185                 if( ! (isxdigit(*handle_str) && (isxdigit(*(handle_str +1))))) {
186                         return(EBADF);
187                 }
188                 cur_char[0] = *handle_str;
189                 cur_char[1] = *(handle_str + 1);
190                 cur_char[2] = '\0';
191                 num = strtol(cur_char, (char **)0, 16);
192                 handle[i++] = num & 0xff;
193                 handle_str += 2;
194         }
195         if (*handle_str){
196                 return(EBADF);
197         }
198         *hlenp = i;
199         if ((*hanpp = malloc(*hlenp)) == NULL)
200                 return(ENOMEM);
201         memcpy(*hanpp, handle, *hlenp);
202         return(0);
203 }
204
205
206 int
207 opaque_to_handle(
208         char            *name,
209         void            **hanpp,
210         size_t          *hlenp)
211 {
212         if (atohan(name, hanpp, hlenp)) {
213                 /* not a handle */
214         } else if (dm_handle_is_valid(*hanpp, *hlenp) == DM_FALSE) {
215                 dm_handle_free(*hanpp, *hlenp);
216                 /* not a handle */
217         } else {
218                 return(0);
219         }
220
221         /* Perhaps it is a pathname */
222
223         if (dm_path_to_handle(name, hanpp, hlenp)) {
224                 return(errno);
225         }
226         return(0);
227 }
228
229
230 void
231 print_handle(
232         void    *hanp,
233         size_t   hlen)
234 {
235         char    handle_str[HANDLE_STR];
236
237         if (hlen > HANDLE_LEN)  {
238                 printf("-- invalid hlen length %zd --\n", hlen);
239                 return;
240         }
241
242         printf("print_handle: ");
243         printf("%zd\t", hlen);
244         hantoa(hanp, hlen, handle_str);
245         printf("%s\n ", handle_str);
246 }
247
248 void
249 print_victim(
250         void            *hanp, 
251         size_t           hlen,
252         dm_off_t         fsize)
253 {
254         char    handle_str[HANDLE_STR];
255
256         if (hlen > HANDLE_LEN)  {
257                 printf("-- invalid length --\n");
258                 return;
259         }
260
261         printf("%zd\t", hlen);
262         hantoa(hanp, hlen, handle_str);
263         printf("%s ", handle_str);
264         printf("\t%lld \n", (long long) fsize);
265 }
266
267
268 /*
269  * Print out a simple error message, and include the errno
270  * string with it.
271  */
272 void
273 errno_msg(char *fmt, ...)
274 {
275         va_list         ap;
276         int             old_errno;
277
278         old_errno = errno;
279         fprintf(stderr, "%s: ", Progname);
280
281         va_start(ap, fmt );
282         vfprintf(stderr, fmt, ap);
283         va_end(ap);
284
285         errno = old_errno;
286         perror("\n\tError");
287 }
288
289 /*
290  * Print out a simple error message
291  */
292 void
293 err_msg(char *fmt, ...)
294 {
295         va_list         ap;
296         
297         fprintf(stderr, "%s: ", Progname);
298
299         va_start(ap, fmt );
300         vfprintf(stderr, fmt, ap);
301         va_end(ap);
302
303 }
304
305
306 /*
307  * Initialize the interface to the DMAPI
308  */
309 int
310 setup_dmapi(dm_sessid_t  *sidp)
311 {
312         char    *cp;
313
314         if (dm_init_service(&cp) == -1)  {
315                 err_msg("%s/%d: Can't init dmapi\n", __FILE__, __LINE__);
316                 return(1);
317         }
318         if (strcmp(cp, DM_VER_STR_CONTENTS)) {
319                 err_msg("%s/%d: Compiled for a different version\n", __FILE__, __LINE__);
320                 return(1);
321         }
322
323         find_test_session(sidp);
324         return(0);
325 }
326
327 /*
328  * Get the file's change indicator
329  */
330 int
331 get_dmchange(
332         dm_sessid_t      sid,
333         void            *hanp, 
334         size_t           hlen, 
335         dm_token_t       token,
336         u_int           *change_start)
337 {
338         int             error;
339         dm_stat_t       statbuf;
340
341
342         error = dm_get_fileattr(sid, hanp, hlen, token, DM_AT_CFLAG, &statbuf);
343         if (error == -1) {
344                 errno_msg("%s/%d: Can't stat file (%d)", __FILE__, __LINE__, errno);
345                 return(1);
346         }
347         *change_start = statbuf.dt_change;
348         return(0);
349 }
350
351
352 /*
353  * Write a file's data to the staging file. We write the file out
354  * in 4meg chunks.
355  */
356 int
357 save_filedata(
358         dm_sessid_t      sid, 
359         void            *hanp, 
360         size_t           hlen, 
361         int              stg_fd, 
362         dm_size_t        fsize)
363 {
364         char            *filebuf;
365         int              i, nbufs;
366         int              retval;
367         dm_ssize_t       nread, lastbuf;
368         ssize_t          nwrite;
369         dm_off_t         off;
370
371         nbufs  = fsize / CHUNKSIZE;
372         off    = 0;
373         retval = 0;
374         filebuf = malloc(CHUNKSIZE);
375         if (filebuf == NULL) {
376                 err_msg("%s/%d: Can't alloc memory for file buffer\n", __FILE__, __LINE__);
377                 goto out;
378         }
379
380         for (i = 0; i<nbufs; i++) {
381                 nread = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, off, 
382                                         (dm_ssize_t)CHUNKSIZE, filebuf);
383                 if (nread != CHUNKSIZE) {
384                         errno_msg("%s/%d: invis read err: got %d, expected %d, buf %d",
385                                 __FILE__, __LINE__,
386                                 nread, (dm_ssize_t)CHUNKSIZE, i);
387                         retval = 1;
388                         goto out;
389                 }
390                 off += nread;
391
392                 nwrite = write(stg_fd, filebuf, CHUNKSIZE);
393                 if (nwrite != CHUNKSIZE) {
394                         errno_msg("%s/%d: write err %d, expected %d, buf %d",
395                                   __FILE__, __LINE__,
396                                   nwrite, CHUNKSIZE, i);
397                         retval = 1;
398                         goto out;
399                 }
400         }
401
402         lastbuf = fsize % CHUNKSIZE;
403         nread  = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, off, 
404                                 (dm_ssize_t)lastbuf, filebuf);
405         if (nread != lastbuf) {
406                 errno_msg("%s/%d: invis read error- got %d, expected %d, last buf",
407                                 __FILE__, __LINE__,
408                                 nread, lastbuf);
409                 retval = 1;
410                 goto out;
411         }
412
413         nwrite = write(stg_fd, filebuf, (int)lastbuf);
414         if (nwrite != lastbuf) {
415                 errno_msg("%s/%d: write error %d, expected %d, last buffer", 
416                                 __FILE__, __LINE__,
417                                 nwrite, lastbuf);
418                 retval = 1;
419         }
420 out:
421         if (filebuf)
422                 free(filebuf);
423
424         close(stg_fd);
425         return(retval);
426 }
427
428
429
430 /*
431  * Read a file's data from the staging file. 
432  * Since we only have the staging file handle (not a file descriptor)
433  * we use dm_read_invis() to read the data. 
434  *
435  * We stage the entire file in, regardless of how much was asked for, 
436  * starting at the faulting offset.
437  */
438 int
439 restore_filedata(
440         dm_sessid_t      sid, 
441         void            *hanp, 
442         size_t           hlen, 
443         dm_token_t       token,
444         void            *stg_hanp,
445         size_t           stg_hlen,
446         dm_off_t         off)
447 {
448         char            *filebuf;
449         int              i, nbufs;
450         int              error, retval;
451         dm_ssize_t       nread, nwrite, lastbuf;
452         dm_off_t         fsize;
453         dm_stat_t        dm_statbuf;
454
455         error = dm_get_fileattr(sid, hanp, hlen, token, DM_AT_STAT,
456                                 &dm_statbuf);
457         if (error == -1) {
458                 errno_msg("%s/%d: Can't get dm stats of file (%d)", __FILE__, __LINE__, errno);
459                 return(1);
460         }
461
462         fsize  = dm_statbuf.dt_size;
463         nbufs  = fsize / CHUNKSIZE;
464         retval = 0;
465
466         filebuf = malloc(CHUNKSIZE);
467         if (filebuf == NULL) {
468                 err_msg("%s/%d: Can't alloc memory for file buffer\n", __FILE__, __LINE__);
469                 goto out;
470         }
471
472         for (i = 0; i<nbufs; i++) {
473                 nread = dm_read_invis(sid, stg_hanp, stg_hlen, DM_NO_TOKEN, 
474                                         off, (dm_ssize_t)CHUNKSIZE, filebuf);
475                 if (nread != CHUNKSIZE) {
476                         errno_msg("%s/%d: invis read err: got %d, expected %d, buf %d",
477                                   __FILE__, __LINE__,
478                                 nread, CHUNKSIZE, i);
479                         retval = 1;
480                         goto out;
481                 }
482
483                 nwrite = dm_write_invis(sid, hanp, hlen, token, 0, off, nread,
484                                         filebuf);
485                 if (nwrite != nread) {
486                         errno_msg("%s/%d: write error -got %d, expected %d, buf %d", 
487                                   __FILE__, __LINE__,
488                                 nwrite, nread, i);
489                         retval = 1;
490                         goto out;
491                 }
492                 off += CHUNKSIZE;
493         }
494
495         lastbuf = fsize % CHUNKSIZE;
496         nread  = dm_read_invis(sid, stg_hanp, stg_hlen, DM_NO_TOKEN, off, 
497                                 (dm_ssize_t)lastbuf, filebuf);
498         if (nread != lastbuf) {
499                 errno_msg("%s/%d: invis read error- got %d, expected %d, last buf",
500                                 __FILE__, __LINE__,
501                                 nread, lastbuf);
502                 retval = 1;
503                 goto out;
504         }
505
506         nwrite = dm_write_invis(sid, hanp, hlen, token, 0, off, lastbuf, filebuf);
507         if (nwrite != lastbuf) {
508                 errno_msg("%s/%d: write error - got %d, expected %d, last buffer", 
509                                 __FILE__, __LINE__,
510                                 nwrite, lastbuf);
511                 retval = 1;
512         }
513 out:
514         if (filebuf)
515                 free(filebuf);
516         return(retval);
517 }
518
519
520 extern mode_t
521 field_to_mode(
522         mode_t  mode)
523 {
524         switch (mode & S_IFMT) {
525
526         case S_IFBLK:
527                 return(S_IFBLK);
528
529         case S_IFREG:
530                 return(S_IFREG);
531
532         case S_IFDIR:
533                 return(S_IFDIR);
534
535         case S_IFCHR:
536                 return(S_IFCHR);
537
538         case S_IFIFO:
539                 return(S_IFIFO);
540
541         case S_IFLNK:
542                 return(S_IFLNK);
543
544         case S_IFSOCK:
545                 return(S_IFSOCK);
546
547         default:
548                 return(0);
549         }
550 }
551
552
553 extern int
554 validate_state(
555         dm_stat_t       *dmstat,
556         char            *pathname,
557         int             report_errors)
558 {
559         struct  stat    statb;
560         int             errors = 0;
561
562         /* Get the stat block for the file. */
563
564         if (lstat(pathname, &statb)) {
565                 perror("stat failed");
566                 exit(1);
567         }
568
569         /* Compare its fields against the dm_stat_t structure. */
570
571         if (dmstat->dt_dev != statb.st_dev) {
572                 if (report_errors) {
573                         fprintf(stdout, "ERROR:dmstat->dt_dev 0x%llx, "
574                                 "statb.st_dev 0x%llx\n",
575                                 (unsigned long long) dmstat->dt_dev,
576                                 (unsigned long long) statb.st_dev);
577                 }
578                 errors++;
579         }
580         if (dmstat->dt_ino != statb.st_ino) {
581                 if (report_errors) {
582                         fprintf(stdout, "ERROR:dmstat->dt_ino %llx, "
583                                 "statb.st_ino %llx\n",
584                                 (unsigned long long) dmstat->dt_ino,
585                                 (unsigned long long) statb.st_ino);
586                 }
587                 errors++;
588         }
589         if ((dmstat->dt_mode & S_IFMT) != field_to_mode(statb.st_mode)) {
590                 if (report_errors) {
591                         fprintf(stdout, "ERROR:dmstat->dt_mode (mode) %s, "
592                                 "statb.st_mode (mode) %s\n",
593                                 mode_to_string(dmstat->dt_mode),
594                                 mode_to_string(field_to_mode(statb.st_mode)));
595                 }
596                 errors++;
597         }
598         if ((dmstat->dt_mode & S_MASK) != (statb.st_mode & S_MASK)) {
599                 if (report_errors) {
600                         fprintf(stdout, "ERROR:dmstat->dt_mode (perm) 0%o, "
601                                 "statb.st_mode (perm) 0%o\n",
602                                 dmstat->dt_mode & S_MASK,
603                                 statb.st_mode & S_MASK);
604                 }
605                 errors++;
606         }
607         if (dmstat->dt_nlink != statb.st_nlink) {
608                 if (report_errors) {
609                         fprintf(stdout, "ERROR:dmstat->dt_nlink %u, "
610                                 "statb.st_nlink %u\n",
611                                 (unsigned int) dmstat->dt_nlink,
612                                 (unsigned int) statb.st_nlink);
613                 }
614                 errors++;
615         }
616         if (dmstat->dt_uid !=  statb.st_uid) {
617                 if (report_errors) {
618                         fprintf(stdout, "ERROR:dmstat->dt_uid %d, "
619                                 "statb.st_uid %d\n", dmstat->dt_uid,
620                                 statb.st_uid);
621                 }
622                 errors++;
623         }
624         if (dmstat->dt_gid != statb.st_gid) {
625                 if (report_errors) {
626                         fprintf(stdout, "ERROR:dmstat->dt_gid %d, "
627                                 "statb.st_gid %d\n", dmstat->dt_gid,
628                                 statb.st_gid);
629                 }
630                 errors++;
631         }
632         if (dmstat->dt_rdev != statb.st_rdev) {
633                 if (report_errors) {
634                         fprintf(stdout, "ERROR:dmstat->dt_rdev 0x%llx, "
635                                 "statb.st_rdev 0x%llx\n",
636                                 (unsigned long long) dmstat->dt_rdev,
637                                 (unsigned long long) statb.st_rdev);
638                 }
639                 errors++;
640         }
641         if (dmstat->dt_size != statb.st_size) {
642                 if (report_errors) {
643                         fprintf(stdout, "ERROR:dmstat->dt_size %lld, "
644                                 "statb.st_size %lld\n",
645                                 (long long) dmstat->dt_size,
646                                 (long long) statb.st_size);
647                 }
648                 errors++;
649         }
650         if (dmstat->dt_atime != statb.st_atime) {
651                 if (report_errors) {
652                         fprintf(stdout, "ERROR:dmstat->dt_atime %ld, "
653                                 "statb.st_atime %ld\n", dmstat->dt_atime,
654                                 statb.st_atime);
655                 }
656                 errors++;
657         }
658         if (dmstat->dt_mtime != statb.st_mtime) {
659                 if (report_errors) {
660                         fprintf(stdout, "ERROR:dmstat->dt_mtime %ld, "
661                                 "statb.st_mtime %ld\n", dmstat->dt_mtime,
662                                 statb.st_mtime);
663                 }
664                 errors++;
665         }
666         if (dmstat->dt_ctime != statb.st_ctime) {
667                 if (report_errors) {
668                         fprintf(stdout, "ERROR:dmstat->dt_ctime %ld, "
669                                 "statb.st_ctime %ld\n", dmstat->dt_ctime,
670                                 statb.st_ctime);
671                 }
672                 errors++;
673         }
674         if (dmstat->dt_dtime != statb.st_ctime) {
675                 if (report_errors) {
676                         fprintf(stdout, "ERROR:dmstat->dt_dtime %ld, "
677                                 "statb.st_ctime %ld\n", dmstat->dt_dtime,
678                                 statb.st_ctime);
679                 }
680                 errors++;
681         }
682         if (dmstat->dt_blksize != statb.st_blksize) {
683                 if (report_errors) {
684                         fprintf(stdout, "ERROR:dmstat->dt_blksize %d, "
685                                 "statb.st_blksize %ld\n", dmstat->dt_blksize,
686                                 statb.st_blksize);
687                 }
688                 errors++;
689         }
690         if (dmstat->dt_blocks != statb.st_blocks) {
691                 if (report_errors) {
692                         fprintf(stdout, "ERROR:dmstat->dt_blocks %lld, "
693                                 "statb.st_blocks %lld\n",
694                                 (long long) dmstat->dt_blocks,
695                                 (long long) statb.st_blocks);
696                 }
697                 errors++;
698         }
699
700         if (errors && report_errors)
701                 fprintf(stdout, "There were %d differences\n", errors);
702         return(errors);
703 }
704
705
706 extern char *
707 date_to_string(
708         time_t          timeval)
709 {
710 static  char            buffer[21];
711         char            *tmstr;
712
713         if (timeval == (time_t)0) {
714                 strcpy(buffer, "0");
715         } else {
716                 tmstr = asctime(localtime(&timeval));
717                 tmstr += 4;
718                 strncpy(buffer, tmstr, 20);
719                 buffer[20] = '\0';
720         }
721         return(buffer);
722 }
723
724
725 extern char *
726 mode_to_string(
727         mode_t  mode)
728 {
729 static  char            buffer[256];
730
731         switch (mode & S_IFMT) {
732
733         case S_IFBLK:
734                 return("S_IFBLK");
735
736         case S_IFREG:
737                 return("S_IFREG");
738
739         case S_IFDIR:
740                 return("S_IFDIR");
741
742         case S_IFCHR:
743                 return("S_IFCHR");
744
745         case S_IFIFO:
746                 return("S_IFIFO");
747
748         case S_IFLNK:
749                 return("S_IFLNK");
750
751         case S_IFSOCK:
752                 return("S_IFSOCK");
753
754         default:
755                 sprintf(buffer, "Invalid mode 0%o", mode & S_IFMT);
756                 return(buffer);
757         }
758 }
759
760
761 extern char *
762 emask_to_string(
763         dm_eventset_t   emask)
764 {
765 static  char            buffer[256];
766         char            *name;
767         int             len = 0;
768         int             i;
769
770         for (i = 0; i < 32; i++) {
771                 if (!DMEV_ISSET(i, emask))
772                         continue;
773
774                 switch (i) {
775                 case DM_EVENT_CREATE:
776                         name = "DM_EVENT_CREATE";
777                         break;
778                 case DM_EVENT_POSTCREATE:
779                         name = "DM_EVENT_POSTCREATE";
780                         break;
781                 case DM_EVENT_REMOVE:
782                         name = "DM_EVENT_REMOVE";
783                         break;
784                 case DM_EVENT_POSTREMOVE:
785                         name = "DM_EVENT_POSTREMOVE";
786                         break;
787                 case DM_EVENT_RENAME:
788                         name = "DM_EVENT_RENAME";
789                         break;
790                 case DM_EVENT_POSTRENAME:
791                         name = "DM_EVENT_POSTRENAME";
792                         break;
793                 case DM_EVENT_LINK:
794                         name = "DM_EVENT_LINK";
795                         break;
796                 case DM_EVENT_POSTLINK:
797                         name = "DM_EVENT_POSTLINK";
798                         break;
799                 case DM_EVENT_SYMLINK:
800                         name = "DM_EVENT_SYMLINK";
801                         break;
802                 case DM_EVENT_POSTSYMLINK:
803                         name = "DM_EVENT_POSTSYMLINK";
804                         break;
805                 case DM_EVENT_READ:
806                         name = "DM_EVENT_READ";
807                         break;
808                 case DM_EVENT_WRITE:
809                         name = "DM_EVENT_WRITE";
810                         break;
811                 case DM_EVENT_TRUNCATE:
812                         name = "DM_EVENT_TRUNCATE";
813                         break;
814                 case DM_EVENT_ATTRIBUTE:
815                         name = "DM_EVENT_ATTRIBUTE";
816                         break;
817                 case DM_EVENT_DESTROY:
818                         name = "DM_EVENT_DESTROY";
819                         break;
820                 default:
821                         fprintf(stderr, "Unknown event type %d\n", i);
822                         exit(1);
823                 }
824                 sprintf(buffer + len, "%c%s", (len ? '|' : '('), name);
825                 len = strlen(buffer);
826         }
827
828         if (len == 0) {
829                 sprintf(buffer, "(none)");
830         } else {
831                 sprintf(buffer + len, ")");
832         }
833         return(buffer);
834 }
835
836
837 #if defined(linux)
838
839 extern char *
840 xflags_to_string(
841         u_int           xflags)
842 {
843 static  char            buffer[256];
844         int             len = 0;
845
846         if (xflags & ~(DM_XFLAG_REALTIME|DM_XFLAG_PREALLOC|DM_XFLAG_HASATTR)) {
847                 sprintf(buffer, "Invalid xflags 0%o", xflags);
848                 return(buffer);
849         }
850
851         if (xflags & DM_XFLAG_REALTIME) {
852                 sprintf(buffer + len, "%cREALTIME", (len ? '|' : '('));
853                 len = strlen(buffer);
854         }
855         if (xflags & DM_XFLAG_PREALLOC) {
856                 sprintf(buffer + len, "%cPREALLOC", (len ? '|' : '('));
857                 len = strlen(buffer);
858         }
859         if (xflags & DM_XFLAG_HASATTR) {
860                 sprintf(buffer + len, "%cHASATTR", (len ? '|' : '('));
861                 len = strlen(buffer);
862         }
863         if (len == 0) {
864                 sprintf(buffer, "(none)");
865         } else {
866                 sprintf(buffer + len, ")");
867         }
868         return(buffer);
869 }
870
871 #endif
872
873
874 extern void
875 print_state(
876         dm_stat_t       *dmstat)
877 {
878         /* Print all the stat block fields. */
879
880         fprintf(stdout, "dt_dev         0x%llx\n",
881                 (unsigned long long) dmstat->dt_dev);
882         fprintf(stdout, "dt_ino         %llx\n",
883                 (unsigned long long) dmstat->dt_ino);
884         fprintf(stdout, "dt_mode (type) %s\n",
885                 mode_to_string(dmstat->dt_mode));
886         fprintf(stdout, "dt_mode (perm) 0%o\n", dmstat->dt_mode & S_MASK);
887         fprintf(stdout, "dt_nlink       %d\n",  dmstat->dt_nlink);
888         fprintf(stdout, "dt_uid         %d\n",  dmstat->dt_uid);
889         fprintf(stdout, "dt_gid         %d\n", dmstat->dt_gid);
890         fprintf(stdout, "dt_rdev        0x%llx\n",
891                 (unsigned long long) dmstat->dt_rdev);
892         fprintf(stdout, "dt_size        %lld\n",
893                 (unsigned long long) dmstat->dt_size);
894
895         fprintf(stdout, "dt_atime       %s\n",
896                 date_to_string(dmstat->dt_atime));
897         fprintf(stdout, "dt_mtime       %s\n",
898                 date_to_string(dmstat->dt_mtime));
899         fprintf(stdout, "dt_ctime       %s\n",
900                 date_to_string(dmstat->dt_ctime));
901
902         fprintf(stdout, "dt_blksize     %d\n", dmstat->dt_blksize);
903         fprintf(stdout, "dt_blocks      %lld\n", (long long) dmstat->dt_blocks);
904
905 #if defined(linux)
906         fprintf(stdout, "dt_xfs_igen    %d\n",  dmstat->dt_xfs_igen);
907         fprintf(stdout, "dt_xfs_xflags  %s\n",
908                 xflags_to_string(dmstat->dt_xfs_xflags));
909         fprintf(stdout, "dt_xfs_extsize %d\n", dmstat->dt_xfs_extsize);
910         fprintf(stdout, "dt_xfs_extents %d\n", dmstat->dt_xfs_extents);
911         fprintf(stdout, "dt_xfs_aextents %d\n", dmstat->dt_xfs_aextents);
912 #endif
913
914         fputc('\n', stdout);
915
916         /* Print all other fields. */
917
918         fprintf(stdout, "emask           %s\n",
919                 emask_to_string(dmstat->dt_emask));
920         fprintf(stdout, "nevents         %d\n", dmstat->dt_nevents);
921         fprintf(stdout, "pmanreg         %d\n", dmstat->dt_pmanreg);
922         fprintf(stdout, "pers            %d\n", dmstat->dt_pers);
923         fprintf(stdout, "dt_dtime        %s\n",
924                 date_to_string(dmstat->dt_dtime));
925         fprintf(stdout, "change          %d\n", dmstat->dt_change);
926 }
927
928
929 extern void
930 print_line(
931         dm_stat_t       *dmstat)
932 {
933         fprintf(stdout, "0x%llx|",  (unsigned long long) dmstat->dt_dev);
934         fprintf(stdout, "%llx|",  (unsigned long long) dmstat->dt_ino);
935         fprintf(stdout, "%s|", mode_to_string(dmstat->dt_mode));
936         fprintf(stdout, "0%o|", dmstat->dt_mode & S_MASK);
937         fprintf(stdout, "%d|",  dmstat->dt_nlink);
938         fprintf(stdout, "%d|",  dmstat->dt_uid);
939         fprintf(stdout, "%d|", dmstat->dt_gid);
940         fprintf(stdout, "0x%llx|", (unsigned long long) dmstat->dt_rdev);
941         fprintf(stdout, "%lld|", (long long) dmstat->dt_size);
942
943         fprintf(stdout, "%s|", date_to_string(dmstat->dt_atime));
944         fprintf(stdout, "%s|", date_to_string(dmstat->dt_mtime));
945         fprintf(stdout, "%s|", date_to_string(dmstat->dt_ctime));
946
947         fprintf(stdout, "%d|", dmstat->dt_blksize);
948         fprintf(stdout, "%lld|", (long long) dmstat->dt_blocks);
949
950         fprintf(stdout, "%d|",  dmstat->dt_xfs_igen);
951         fprintf(stdout, "%s|", xflags_to_string(dmstat->dt_xfs_xflags));
952         fprintf(stdout, "%d|", dmstat->dt_xfs_extsize);
953         fprintf(stdout, "%d|", dmstat->dt_xfs_extents);
954         fprintf(stdout, "%d|", dmstat->dt_xfs_aextents);
955
956         /* Print all other fields. */
957
958         fprintf(stdout, "%s|", emask_to_string(dmstat->dt_emask));
959         fprintf(stdout, "%d|", dmstat->dt_nevents);
960         fprintf(stdout, "%d|", dmstat->dt_pmanreg);
961         fprintf(stdout, "%d|", dmstat->dt_pers);
962         fprintf(stdout, "%s|", date_to_string(dmstat->dt_dtime));
963         fprintf(stdout, "%d", dmstat->dt_change);
964
965         fputc('\n', stdout);
966 }