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