cmd/xfsprogs/libdm/dmapi_tests/README 1.1 Renamed to cmd/xfstests/dmapi/README
[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 #ifdef linux
30 #include <time.h>
31 #define S_IAMB (S_IRWXU|S_IRWXG|S_IRWXO)
32 #endif
33
34 #define S_MASK  (S_ISUID|S_ISGID|S_ISVTX|S_IAMB)
35
36 extern char     *Progname;
37 extern int       errno;
38
39 void             err_msg(char *, ...);
40 void             errno_msg(char *, ...);
41
42 struct ev_name_to_value ev_names[] = {
43         { "DM_EVENT_CANCEL",            DM_EVENT_CANCEL         },
44         { "DM_EVENT_MOUNT",             DM_EVENT_MOUNT          },
45         { "DM_EVENT_PREUNMOUNT",        DM_EVENT_PREUNMOUNT     },
46         { "DM_EVENT_UNMOUNT",           DM_EVENT_UNMOUNT        },
47         { "DM_EVENT_DEBUT",             DM_EVENT_DEBUT          },
48         { "DM_EVENT_CREATE",            DM_EVENT_CREATE         },
49         { "DM_EVENT_CLOSE",             DM_EVENT_CLOSE          },
50         { "DM_EVENT_POSTCREATE",        DM_EVENT_POSTCREATE     },
51         { "DM_EVENT_REMOVE",            DM_EVENT_REMOVE         },
52         { "DM_EVENT_POSTREMOVE",        DM_EVENT_POSTREMOVE     },
53         { "DM_EVENT_RENAME",            DM_EVENT_RENAME         },
54         { "DM_EVENT_POSTRENAME",        DM_EVENT_POSTRENAME     },
55         { "DM_EVENT_LINK",              DM_EVENT_LINK           },
56         { "DM_EVENT_POSTLINK",          DM_EVENT_POSTLINK       },
57         { "DM_EVENT_SYMLINK",           DM_EVENT_SYMLINK        },
58         { "DM_EVENT_POSTSYMLINK",       DM_EVENT_POSTSYMLINK    },
59         { "DM_EVENT_READ",              DM_EVENT_READ           },
60         { "DM_EVENT_WRITE",             DM_EVENT_WRITE          },
61         { "DM_EVENT_TRUNCATE",          DM_EVENT_TRUNCATE       },
62         { "DM_EVENT_ATTRIBUTE",         DM_EVENT_ATTRIBUTE      },
63         { "DM_EVENT_DESTROY",           DM_EVENT_DESTROY        },
64         { "DM_EVENT_NOSPACE",           DM_EVENT_NOSPACE        },
65         { "DM_EVENT_USER",              DM_EVENT_USER           }
66 };
67
68 int     ev_namecnt = sizeof(ev_names) / sizeof(ev_names[0]);
69
70 dm_eventtype_t
71 ev_name_to_value(
72         char            *name)
73 {
74         int             i;
75
76         for (i = 0; i < ev_namecnt; i++) {
77                 if (!strcmp(name, ev_names[i].name)) 
78                         return(ev_names[i].value);
79         }
80         return(DM_EVENT_INVALID);
81 }
82
83 char *
84 ev_value_to_name(
85         dm_eventtype_t  event)
86 {
87         static char             buffer[100];
88         int             i;
89
90         for (i = 0; i < ev_namecnt; i++) {
91                 if (event == ev_names[i].value)
92                         return(ev_names[i].name);
93         }
94         sprintf(buffer, "Unknown Event Number %d\n", event);
95         return(buffer);
96 }
97
98
99
100 struct rt_name_to_value rt_names[] = {
101         { "DM_RIGHT_NULL",              DM_RIGHT_NULL           },
102         { "DM_RIGHT_SHARED",            DM_RIGHT_SHARED         },
103         { "DM_RIGHT_EXCL",              DM_RIGHT_EXCL           }
104 };
105
106 int     rt_namecnt = sizeof(rt_names) / sizeof(rt_names[0]);
107
108 int
109 rt_name_to_value(
110         char            *name,
111         dm_right_t      *rightp)
112 {
113         int             i;
114
115         for (i = 0; i < rt_namecnt; i++) {
116                 if (!strcmp(name, rt_names[i].name)) {
117                         *rightp = rt_names[i].value;
118                         return(0);
119                 }
120         }
121         return(1);
122 }
123
124
125 char *
126 rt_value_to_name(
127         dm_right_t      right)
128 {
129         int             i;
130
131         for (i = 0; i < rt_namecnt; i++) {
132                 if (right == rt_names[i].value)
133                         return(rt_names[i].name);
134         }
135         return(NULL);
136 }
137  
138  
139 /*
140  * Convert a handle from (possibly) binary to ascii. 
141  */
142 void
143 hantoa(
144         void    *hanp,
145         size_t   hlen,
146         char    *handle_str)
147 {
148         int     i;
149         u_char  *cp;
150
151         cp = (u_char *)hanp;
152         for (i=0;i<hlen; i++)  {
153                 sprintf(handle_str, "%.2x", *cp++);
154                 handle_str += 2;
155         }
156         *handle_str = '\0';     /* Null-terminate to make it printable */
157 }
158
159 /*
160  * Convert a handle from ascii back to it's native binary representation
161  */
162
163 int
164 atohan(
165         char    *handle_str,
166         void    **hanpp,
167         size_t   *hlenp) 
168 {
169         u_char  handle[HANDLE_LEN];
170         char    cur_char[3];
171         int     i = 0;
172         u_long  num;
173
174         if (strlen(handle_str) > HANDLE_LEN * 2){
175                 return(EBADF);
176         }
177
178         while (*handle_str && *(handle_str + 1)) {
179                 if (i == HANDLE_LEN){
180                         return(EBADF);
181                 }
182                 cur_char[0] = *handle_str;
183                 cur_char[1] = *(handle_str + 1);
184                 cur_char[2] = '\0';
185                 num = strtol(cur_char, (char **)0, 16);
186                 handle[i++] = num & 0xff;
187                 handle_str += 2;
188         }
189         if (*handle_str){
190                 return(EBADF);
191         }
192         *hlenp = i;
193         if ((*hanpp = malloc(*hlenp)) == NULL)
194                 return(ENOMEM);
195         memcpy(*hanpp, handle, *hlenp);
196         return(0);
197 }
198
199
200 int
201 opaque_to_handle(
202         char            *name,
203         void            **hanpp,
204         size_t          *hlenp)
205 {
206         if (atohan(name, hanpp, hlenp)) {
207                 /* not a handle */
208         } else if (dm_handle_is_valid(*hanpp, *hlenp) == DM_FALSE) {
209                 dm_handle_free(*hanpp, *hlenp);
210                 /* not a handle */
211         } else {
212                 return(0);
213         }
214
215         /* Perhaps it is a pathname */
216
217         if (dm_path_to_handle(name, hanpp, hlenp)) {
218                 return(errno);
219         }
220         return(0);
221 }
222
223
224 void
225 print_handle(
226         void    *hanp,
227         size_t   hlen)
228 {
229         char    handle_str[HANDLE_STR];
230
231         if (hlen > HANDLE_LEN)  {
232                 printf("-- invalid hlen length %d --\n", hlen);
233                 return;
234         }
235
236         printf("print_handle: ");
237         printf("%d\t", hlen);
238         hantoa(hanp, hlen, handle_str);
239         printf("%s\n ", handle_str);
240 }
241
242 void
243 print_victim(
244         void            *hanp, 
245         size_t           hlen,
246         dm_off_t         fsize)
247 {
248         char    handle_str[HANDLE_STR];
249
250         if (hlen > HANDLE_LEN)  {
251                 printf("-- invalid length --\n");
252                 return;
253         }
254
255         printf("%d\t", hlen);   
256         hantoa(hanp, hlen, handle_str);
257         printf("%s ", handle_str);
258 #ifdef __sgi
259         printf("\t%lld \n", fsize);
260 #else
261         printf("\t%ld \n", fsize);
262 #endif
263 }
264
265
266 /*
267  * Print out a simple error message, and include the errno
268  * string with it.
269  */
270 void
271 errno_msg(char *fmt, ...)
272 {
273         va_list         ap;
274         int             old_errno;
275
276         old_errno = errno;
277         fprintf(stderr, "%s: ", Progname);
278
279         va_start(ap, fmt );
280         vfprintf(stderr, fmt, ap);
281         va_end(ap);
282
283         errno = old_errno;
284         perror("\n\tError");
285 }
286
287 /*
288  * Print out a simple error message
289  */
290 void
291 err_msg(char *fmt, ...)
292 {
293         va_list         ap;
294         
295         fprintf(stderr, "%s: ", Progname);
296
297         va_start(ap, fmt );
298         vfprintf(stderr, fmt, ap);
299         va_end(ap);
300
301 }
302
303
304 /*
305  * Initialize the interface to the DMAPI
306  */
307 int
308 setup_dmapi(dm_sessid_t  *sidp)
309 {
310         char    *cp;
311
312         if (dm_init_service(&cp) == -1)  {
313                 err_msg("%s/%d: Can't init dmapi", __FILE__, __LINE__);
314                 return(1);
315         }
316         if (strcmp(cp, DM_VER_STR_CONTENTS)) {
317                 err_msg("%s/%d: Compiled for a different version", __FILE__, __LINE__);
318                 return(1);
319         }
320
321         find_test_session(sidp);
322         return(0);
323 }
324
325 /*
326  * Get the file's change indicator
327  */
328 int
329 get_dmchange(
330         dm_sessid_t      sid,
331         void            *hanp, 
332         size_t           hlen, 
333         dm_token_t       token,
334         u_int           *change_start)
335 {
336         int             error;
337         dm_stat_t       statbuf;
338
339
340         error = dm_get_fileattr(sid, hanp, hlen, token, DM_AT_CFLAG, &statbuf);
341         if (error == -1) {
342                 errno_msg("%s/%d: Can't stat file (%d)", __FILE__, __LINE__, errno);
343                 return(1);
344         }
345         *change_start = statbuf.dt_change;
346         return(0);
347 }
348
349
350 /*
351  * Write a file's data to the staging file. We write the file out
352  * in 4meg chunks.
353  */
354 int
355 save_filedata(
356         dm_sessid_t      sid, 
357         void            *hanp, 
358         size_t           hlen, 
359         int              stg_fd, 
360         dm_size_t        fsize)
361 {
362         char            *filebuf;
363         int              i, nbufs;
364         int              retval;
365         dm_ssize_t       nread, lastbuf;
366         ssize_t          nwrite;
367         dm_off_t         off;
368
369         nbufs  = fsize / CHUNKSIZE;
370         off    = 0;
371         retval = 0;
372         filebuf = malloc(CHUNKSIZE);
373         if (filebuf == NULL) {
374                 err_msg("%s/%d: Can't alloc memory for file buffer", __FILE__, __LINE__);
375                 goto out;
376         }
377
378         for (i = 0; i<nbufs; i++) {
379                 nread = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, off, 
380                                         (dm_ssize_t)CHUNKSIZE, filebuf);
381                 if (nread != CHUNKSIZE) {
382 #ifdef  __sgi
383                         errno_msg("%s/%d: invis read err: got %lld, expected %lld, buf %d",
384 #else
385                         errno_msg("%s/%d: invis read err: got %d, expected %d, buf %d",
386 #endif
387                                 __FILE__, __LINE__,
388                                 nread, (dm_ssize_t)CHUNKSIZE, i);
389                         retval = 1;
390                         goto out;
391                 }
392                 off += nread;
393
394                 nwrite = write(stg_fd, filebuf, CHUNKSIZE);
395                 if (nwrite != CHUNKSIZE) {
396                         errno_msg("%s/%d: write err %d, expected %d, buf %d",
397                                   __FILE__, __LINE__,
398                                   nwrite, CHUNKSIZE, i);
399                         retval = 1;
400                         goto out;
401                 }
402         }
403
404         lastbuf = fsize % CHUNKSIZE;
405         nread  = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, off, 
406                                 (dm_ssize_t)lastbuf, filebuf);
407         if (nread != lastbuf) {
408 #ifdef  __sgi
409                 errno_msg("%s/%d: invis read error- got %lld, expected %lld, last buf",
410 #else
411                 errno_msg("%s/%d: invis read error- got %d, expected %d, last buf",
412 #endif
413                                 __FILE__, __LINE__,
414                                 nread, lastbuf);
415                 retval = 1;
416                 goto out;
417         }
418
419         nwrite = write(stg_fd, filebuf, (int)lastbuf);
420         if (nwrite != lastbuf) {
421 #ifdef  __sgi
422                 errno_msg("%s/%d: write error %d, expected %lld, last buffer", 
423 #else
424                 errno_msg("%s/%d: write error %d, expected %d, last buffer", 
425 #endif
426                                 __FILE__, __LINE__,
427                                 nwrite, lastbuf);
428                 retval = 1;
429         }
430 out:
431         if (filebuf)
432                 free(filebuf);
433
434         close(stg_fd);
435         return(retval);
436 }
437
438
439
440 /*
441  * Read a file's data from the staging file. 
442  * Since we only have the staging file handle (not a file descriptor)
443  * we use dm_read_invis() to read the data. 
444  *
445  * We stage the entire file in, regardless of how much was asked for, 
446  * starting at the faulting offset.
447  */
448 int
449 restore_filedata(
450         dm_sessid_t      sid, 
451         void            *hanp, 
452         size_t           hlen, 
453         dm_token_t       token,
454         void            *stg_hanp,
455         size_t           stg_hlen,
456         dm_off_t         off)
457 {
458         char            *filebuf;
459         int              i, nbufs;
460         int              error, retval;
461         dm_ssize_t       nread, nwrite, lastbuf;
462         dm_off_t         fsize;
463         dm_stat_t        dm_statbuf;
464
465         error = dm_get_fileattr(sid, hanp, hlen, token, DM_AT_STAT,
466                                 &dm_statbuf);
467         if (error == -1) {
468                 errno_msg("%s/%d: Can't get dm stats of file (%d)", __FILE__, __LINE__, errno);
469                 return(1);
470         }
471
472         fsize  = dm_statbuf.dt_size;
473         nbufs  = fsize / CHUNKSIZE;
474         retval = 0;
475
476         filebuf = malloc(CHUNKSIZE);
477         if (filebuf == NULL) {
478                 err_msg("%s/%d: Can't alloc memory for file buffer", __FILE__, __LINE__);
479                 goto out;
480         }
481
482         for (i = 0; i<nbufs; i++) {
483                 nread = dm_read_invis(sid, stg_hanp, stg_hlen, DM_NO_TOKEN, 
484                                         off, (dm_ssize_t)CHUNKSIZE, filebuf);
485                 if (nread != CHUNKSIZE) {
486                         errno_msg("%s/%d: invis read err: got %d, expected %d, buf %d",
487                                   __FILE__, __LINE__,
488                                 nread, CHUNKSIZE, i);
489                         retval = 1;
490                         goto out;
491                 }
492
493                 nwrite = dm_write_invis(sid, hanp, hlen, token, 0, off, nread,
494                                         filebuf);
495                 if (nwrite != nread) {
496                         errno_msg("%s/%d: write error -got %d, expected %d, buf %d", 
497                                   __FILE__, __LINE__,
498                                 nwrite, nread, i);
499                         retval = 1;
500                         goto out;
501                 }
502                 off += CHUNKSIZE;
503         }
504
505         lastbuf = fsize % CHUNKSIZE;
506         nread  = dm_read_invis(sid, stg_hanp, stg_hlen, DM_NO_TOKEN, off, 
507                                 (dm_ssize_t)lastbuf, filebuf);
508         if (nread != lastbuf) {
509                 errno_msg("%s/%d: invis read error- got %d, expected %d, last buf",
510                                 __FILE__, __LINE__,
511                                 nread, lastbuf);
512                 retval = 1;
513                 goto out;
514         }
515
516         nwrite = dm_write_invis(sid, hanp, hlen, token, 0, off, lastbuf, filebuf);
517         if (nwrite != lastbuf) {
518                 errno_msg("%s/%d: write error - got %d, expected %d, last buffer", 
519                                 __FILE__, __LINE__,
520                                 nwrite, lastbuf);
521                 retval = 1;
522         }
523 out:
524         if (filebuf)
525                 free(filebuf);
526         return(retval);
527 }
528
529
530 extern mode_t
531 field_to_mode(
532         mode_t  mode)
533 {
534         switch (mode & S_IFMT) {
535
536         case S_IFBLK:
537                 return(S_IFBLK);
538
539         case S_IFREG:
540                 return(S_IFREG);
541
542         case S_IFDIR:
543                 return(S_IFDIR);
544
545         case S_IFCHR:
546                 return(S_IFCHR);
547
548         case S_IFIFO:
549                 return(S_IFIFO);
550
551         case S_IFLNK:
552                 return(S_IFLNK);
553
554         case S_IFSOCK:
555                 return(S_IFSOCK);
556
557         default:
558                 return(0);
559         }
560 }
561
562
563 extern int
564 validate_state(
565         dm_stat_t       *dmstat,
566         char            *pathname,
567         int             report_errors)
568 {
569         struct  stat    statb;
570         int             errors = 0;
571
572         /* Get the stat block for the file. */
573
574         if (lstat(pathname, &statb)) {
575                 perror("stat failed");
576                 exit(1);
577         }
578
579         /* Compare its fields against the dm_stat_t structure. */
580
581         if (dmstat->dt_dev != statb.st_dev) {
582                 if (report_errors) {
583                         fprintf(stdout, "ERROR:dmstat->dt_dev 0x%x, "
584                                 "statb.st_dev 0x%x\n", dmstat->dt_dev,
585                                 statb.st_dev);
586                 }
587                 errors++;
588         }
589         if (dmstat->dt_ino != statb.st_ino) {
590                 if (report_errors) {
591                         fprintf(stdout, "ERROR:dmstat->dt_ino %llx, "
592 #if     defined(__sgi) && (_MIPS_SIM != _MIPS_SIM_ABI32)
593                                 "statb.st_ino %llx\n",
594 #else
595                                 "statb.st_ino %x\n",
596 #endif
597                                 dmstat->dt_ino, statb.st_ino);
598                 }
599                 errors++;
600         }
601         if ((dmstat->dt_mode & S_IFMT) != field_to_mode(statb.st_mode)) {
602                 if (report_errors) {
603                         fprintf(stdout, "ERROR:dmstat->dt_mode (mode) %s, "
604                                 "statb.st_mode (mode) %s\n",
605                                 mode_to_string(dmstat->dt_mode),
606                                 mode_to_string(field_to_mode(statb.st_mode)));
607                 }
608                 errors++;
609         }
610         if ((dmstat->dt_mode & S_MASK) != (statb.st_mode & S_MASK)) {
611                 if (report_errors) {
612                         fprintf(stdout, "ERROR:dmstat->dt_mode (perm) 0%o, "
613                                 "statb.st_mode (perm) 0%o\n",
614                                 dmstat->dt_mode & S_MASK,
615                                 statb.st_mode & S_MASK);
616                 }
617                 errors++;
618         }
619         if (dmstat->dt_nlink != statb.st_nlink) {
620                 if (report_errors) {
621                         fprintf(stdout, "ERROR:dmstat->dt_nlink %d, "
622                                 "statb.st_nlink %d\n", dmstat->dt_nlink,
623                                 statb.st_nlink);
624                 }
625                 errors++;
626         }
627         if (dmstat->dt_uid !=  statb.st_uid) {
628                 if (report_errors) {
629                         fprintf(stdout, "ERROR:dmstat->dt_uid %d, "
630                                 "statb.st_uid %d\n", dmstat->dt_uid,
631                                 statb.st_uid);
632                 }
633                 errors++;
634         }
635         if (dmstat->dt_gid != statb.st_gid) {
636                 if (report_errors) {
637                         fprintf(stdout, "ERROR:dmstat->dt_gid %d, "
638                                 "statb.st_gid %d\n", dmstat->dt_gid,
639                                 statb.st_gid);
640                 }
641                 errors++;
642         }
643         if (dmstat->dt_rdev != statb.st_rdev) {
644                 if (report_errors) {
645                         fprintf(stdout, "ERROR:dmstat->dt_rdev 0x%x, "
646                                 "statb.st_rdev 0x%x\n", dmstat->dt_rdev,
647                                 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(__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 %d, "
666                                 "statb.st_atime %d\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 %d, "
674                                 "statb.st_mtime %d\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 %d, "
682                                 "statb.st_ctime %d\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 %d, "
690                                 "statb.st_ctime %d\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 %d\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(__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%x\n",  dmstat->dt_dev);
897 #ifdef  __sgi
898         fprintf(stdout, "dt_ino         %llx\n",  dmstat->dt_ino);
899 #else
900         fprintf(stdout, "dt_ino         %x\n",  dmstat->dt_ino);
901 #endif
902         fprintf(stdout, "dt_mode (type) %s\n",
903                 mode_to_string(dmstat->dt_mode));
904         fprintf(stdout, "dt_mode (perm) 0%o\n", dmstat->dt_mode & S_MASK);
905         fprintf(stdout, "dt_nlink       %d\n",  dmstat->dt_nlink);
906         fprintf(stdout, "dt_uid         %d\n",  dmstat->dt_uid);
907         fprintf(stdout, "dt_gid         %d\n", dmstat->dt_gid);
908         fprintf(stdout, "dt_rdev        0x%x\n", dmstat->dt_rdev);
909 #ifdef  __sgi
910         fprintf(stdout, "dt_size        %lld\n", dmstat->dt_size);
911 #else
912         fprintf(stdout, "dt_size        %d\n", dmstat->dt_size);
913 #endif
914
915         fprintf(stdout, "dt_atime       %s\n",
916                 date_to_string(dmstat->dt_atime));
917         fprintf(stdout, "dt_mtime       %s\n",
918                 date_to_string(dmstat->dt_mtime));
919         fprintf(stdout, "dt_ctime       %s\n",
920                 date_to_string(dmstat->dt_ctime));
921
922         fprintf(stdout, "dt_blksize     %d\n", dmstat->dt_blksize);
923 #ifdef  __sgi
924         fprintf(stdout, "dt_blocks      %lld\n", dmstat->dt_blocks);
925 #else
926         fprintf(stdout, "dt_blocks      %d\n", dmstat->dt_blocks);
927 #endif
928
929 #if defined(__sgi) || defined(linux)
930         fprintf(stdout, "dt_xfs_igen    %d\n",  dmstat->dt_xfs_igen);
931         fprintf(stdout, "dt_xfs_xflags  %s\n",
932                 xflags_to_string(dmstat->dt_xfs_xflags));
933         fprintf(stdout, "dt_xfs_extsize %d\n", dmstat->dt_xfs_extsize);
934         fprintf(stdout, "dt_xfs_extents %d\n", dmstat->dt_xfs_extents);
935         fprintf(stdout, "dt_xfs_aextents %d\n", dmstat->dt_xfs_aextents);
936 #endif
937
938         fputc('\n', stdout);
939
940         /* Print all other fields. */
941
942         fprintf(stdout, "emask           %s\n",
943                 emask_to_string(dmstat->dt_emask));
944         fprintf(stdout, "nevents         %d\n", dmstat->dt_nevents);
945         fprintf(stdout, "pmanreg         %d\n", dmstat->dt_pmanreg);
946         fprintf(stdout, "pers            %d\n", dmstat->dt_pers);
947         fprintf(stdout, "dt_dtime        %s\n",
948                 date_to_string(dmstat->dt_dtime));
949         fprintf(stdout, "change          %d\n", dmstat->dt_change);
950 }
951
952
953 extern void
954 print_line(
955         dm_stat_t       *dmstat)
956 {
957         fprintf(stdout, "0x%x|",  dmstat->dt_dev);
958 #ifdef  __sgi
959         fprintf(stdout, "%llx|",  dmstat->dt_ino);
960 #else
961         fprintf(stdout, "%x|",  dmstat->dt_ino);
962 #endif
963         fprintf(stdout, "%s|", mode_to_string(dmstat->dt_mode));
964         fprintf(stdout, "0%o|", dmstat->dt_mode & S_MASK);
965         fprintf(stdout, "%d|",  dmstat->dt_nlink);
966         fprintf(stdout, "%d|",  dmstat->dt_uid);
967         fprintf(stdout, "%d|", dmstat->dt_gid);
968         fprintf(stdout, "0x%x|", dmstat->dt_rdev);
969 #ifdef  __sgi
970         fprintf(stdout, "%lld|", dmstat->dt_size);
971 #else
972         fprintf(stdout, "%d|", dmstat->dt_size);
973 #endif
974
975         fprintf(stdout, "%s|", date_to_string(dmstat->dt_atime));
976         fprintf(stdout, "%s|", date_to_string(dmstat->dt_mtime));
977         fprintf(stdout, "%s|", date_to_string(dmstat->dt_ctime));
978
979         fprintf(stdout, "%d|", dmstat->dt_blksize);
980 #ifdef  __sgi
981         fprintf(stdout, "%lld|", dmstat->dt_blocks);
982 #else
983         fprintf(stdout, "%d|", dmstat->dt_blocks);
984 #endif
985
986 #ifdef  __sgi
987         fprintf(stdout, "%d|",  dmstat->dt_xfs_igen);
988         fprintf(stdout, "%s|", xflags_to_string(dmstat->dt_xfs_xflags));
989         fprintf(stdout, "%d|", dmstat->dt_xfs_extsize);
990         fprintf(stdout, "%d|", dmstat->dt_xfs_extents);
991         fprintf(stdout, "%d|", dmstat->dt_xfs_aextents);
992 #endif
993
994         /* Print all other fields. */
995
996         fprintf(stdout, "%s|", emask_to_string(dmstat->dt_emask));
997         fprintf(stdout, "%d|", dmstat->dt_nevents);
998         fprintf(stdout, "%d|", dmstat->dt_pmanreg);
999         fprintf(stdout, "%d|", dmstat->dt_pers);
1000         fprintf(stdout, "%s|", date_to_string(dmstat->dt_dtime));
1001         fprintf(stdout, "%d", dmstat->dt_change);
1002
1003         fputc('\n', stdout);
1004 }