f2e67a99d4cd6c2ddffd2cb8abbd5c75ca6e4e32
[xfstests-dev.git] / dmapi / src / suite1 / cmd / print_event.c
1
2
3 /*
4  * eventloop.c
5  *
6  * Joseph Jackson
7  * 25-Jun-1996
8  *
9  * Monitor all events for a file system.
10  * When one arrives, print a message with all the details.
11  * If the message is synchronous, always reply with DM_RESP_CONTINUE
12  * (This program doesn't perform any real file system or HSM work.)
13  *
14  * This is a simplification of the "migin.c" example program.
15  * The original code was by Peter Lawthers:
16  *   This code was written by Peter Lawthers, and placed in the public
17  *   domain for use by DMAPI implementors and app writers.
18  */
19
20 #include <ctype.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #include <sys/resource.h>
28 #include <sys/wait.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31
32 #include <lib/hsm.h>
33
34   /*
35    * Define some standard formats for the printf statements below.
36    */
37
38 #define HDR  "%s: token %d sequence %d\n"
39 #define VALS "\t%-15s %s\n"
40 #define VALD "\t%-15s %d\n"
41 #ifdef  __sgi
42 #define VALLLD "\t%-15s %lld\n"
43 #else
44 #define VALLLD "\t%-15s %ld\n"
45 #endif
46
47 extern int       optind;
48 extern int       errno;
49
50 void             usage          (char *);
51 int              main           (int, char **);
52 static  void     event_loop     (dm_sessid_t, int);
53 int              handle_message (dm_sessid_t, dm_eventmsg_t *);
54 static  int     format_mode(mode_t mode, char **ptr);
55 static  int     get_fs_handle   (char *, void **, size_t *);
56 static  int     set_disposition(dm_sessid_t, void *, size_t);
57 static  int     set_events      (dm_sessid_t, void *, size_t);
58 static  int     clear_events    (dm_sessid_t, void *, size_t);
59 int              finish_responding(dm_sessid_t);
60 int              establish_handler(void);
61 void             exit_handler   (void);
62
63 #define MAXNAMELEN 256
64
65 /*
66  * Keep these global so the exit_handler and err_msg routines can get to them
67  */
68 char            *Progname;
69 int              Sleep = 0;
70 int              Verbose;
71 dm_sessid_t      sid = 0;
72 dm_sessid_t      oldsid = 0;
73 char             *fsname;
74
75
76 void
77 usage(
78       char *prog)
79 {
80   fprintf(stderr, "Usage: %s ", prog);
81   fprintf(stderr, " <-S oldsid> <-v verbose> ");
82   fprintf(stderr, "filesystem \n");
83 }
84
85
86 int
87 main(
88      int        argc,
89      char       *argv[])
90 {
91
92   int            c;
93   int            error;
94   void          *fs_hanp;
95   size_t                 fs_hlen;
96
97
98 /*  Progname  = argv[0];*/ Progname = "print_event";
99   fsname  = NULL;
100
101   while ((c = getopt(argc, argv, "vs:S:")) != EOF) {
102     switch (c) {
103     case 's':
104       Sleep = atoi(optarg);
105       break;
106     case 'S':
107       oldsid = atoi(optarg);
108       break;
109     case 'v':
110       Verbose = 1;
111       break;
112     case '?':
113     default:
114       usage(Progname);
115       exit(1);
116     }
117   }
118   if (optind >= argc) {
119     usage(Progname);
120     exit(1);
121   }
122   fsname = argv[optind];
123   if (fsname == NULL) {
124     usage(Progname);
125     exit(1);
126   }
127
128   /*
129    * Establish an exit handler
130    */
131   error = establish_handler();
132   if (error)
133     exit(1);
134
135   /*
136    * Init the dmapi, and get a filesystem handle so
137    * we can set up our events
138    */
139
140   if (oldsid) {
141         sid = oldsid;
142   } else {
143         error = setup_dmapi(&sid);
144         if (error)
145                 exit(1);
146   }
147
148   error = get_fs_handle(fsname, &fs_hanp, &fs_hlen);
149   if (error)
150     goto cleanup;
151
152   /*
153    * Set the event disposition so that our session will receive
154    * all the events for the given file system
155    */
156   error = set_disposition(sid, fs_hanp, fs_hlen);
157   if (error)
158     goto cleanup;
159
160   /*
161    * Enable monitoring for all events in the given file system
162    */
163   error = set_events(sid, fs_hanp, fs_hlen);
164   if (error)
165     goto cleanup;
166
167   /*
168    * Now sit in an infinite loop, reporting on any events that occur.
169    * The program is exited after a signal through exit_handler().
170    */
171   printf("\n");
172   event_loop(sid, 1 /*waitflag*/);
173
174   /*
175    * If we get here, cleanup after the event_loop failure
176    */
177  cleanup:
178   exit_handler();
179   return(1);
180 }
181
182
183 /*
184  * Main event loop processing
185  *
186  * The waitflag argument is set to 1 when we call this from main().
187  *  In this case, continuously process incoming events,
188  *  blocking if there are none available.
189  * In the exit_handler(), call this routine with waitflag=0.
190  *  Just try to read the events once in this case with no blocking.
191  */
192
193 static void
194 event_loop(
195         dm_sessid_t     sid,
196         int             waitflag)
197 {
198         void            *msgbuf;
199         size_t          bufsize;
200         int             error;
201         dm_eventmsg_t   *msg;
202         int             count;
203
204         /*
205          * We take a swag at a buffer size. If it's wrong, we can
206          * always resize it
207          */
208
209         bufsize = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN;
210         bufsize *= 50;
211         msgbuf  = (void *)malloc(bufsize);
212         if (msgbuf == NULL) {
213                 err_msg("Can't allocate memory for buffer");
214                 return;
215         }
216
217         for (;;) {
218                 error = dm_get_events(sid, ALL_AVAIL_MSGS,
219                         waitflag ? DM_EV_WAIT:0, bufsize, msgbuf, &bufsize);
220                 if (error) {
221                         if (errno == EAGAIN) {
222                                 if (waitflag)
223                                         continue;
224                                 break;
225                         }
226                         if (errno == E2BIG) {
227                                 free(msgbuf);
228                                 msgbuf = (void *)malloc(bufsize);
229                                 if (msgbuf == NULL) {
230                                         err_msg("Can't resize msg buffer");
231                                         return;
232                                 }
233                                 continue;
234                         }
235                         errno_msg("Error getting events from DMAPI (%d)", errno);
236                         break;
237                 }
238
239                 /*
240                  * Walk through the message buffer, pull out each individual
241                  * message, and dispatch the messages to handle_message(),
242                  * which will respond to the events.
243                  */
244
245                 count = 0;
246                 msg = (dm_eventmsg_t *)msgbuf;
247                 while (msg != NULL ) {
248                         count++;
249                         error = handle_message(sid, msg);
250                         if (error) {
251                                 free(msgbuf);
252                                 return;
253                         }
254                         msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *);
255                 }
256                 if (count != 1 && Verbose) {
257                         err_msg("Found %d events in one call to "
258                                 "dm_get_events\n", count);
259                 }
260         }
261         if (msgbuf != NULL)
262                 free(msgbuf);
263 }
264
265
266 void
267 print_one_mount_event(
268         void            *msg)
269 {
270         void            *hanp1, *hanp2, *hanp3;
271         size_t          hlen1, hlen2, hlen3;
272         char            hans1[HANDLE_STR], hans2[HANDLE_STR], hans3[HANDLE_STR];
273         void            *namp1, *namp2;
274         size_t          nlen1, nlen2;
275         char            nams1[MAXNAMELEN], nams2[MAXNAMELEN];
276         mode_t          mode;
277
278 #if     VERITAS_21
279         dm_namesp_event_t  *msg_ne = (dm_namesp_event_t *)msg;
280
281 /*
282         msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
283 */
284         hanp1  = DM_GET_VALUE(msg_ne, ne_handle1, void *);
285         hlen1  = DM_GET_LEN  (msg_ne, ne_handle1);
286         hanp2  = DM_GET_VALUE(msg_ne, ne_handle2, void *);
287         hlen2  = DM_GET_LEN  (msg_ne, ne_handle2);
288         namp1  = DM_GET_VALUE(msg_ne, ne_name1, void *);
289         nlen1  = DM_GET_LEN  (msg_ne, ne_name1);
290         namp2  = DM_GET_VALUE(msg_ne, ne_name2, void *);
291         nlen2  = DM_GET_LEN  (msg_ne, ne_name2);
292         hanp3  = NULL;
293         hlen3  = 0;
294         mode   = msg_ne->ne_mode;
295 #else
296         dm_mount_event_t  *msg_me = (dm_mount_event_t *)msg;
297
298         hanp1 = DM_GET_VALUE(msg_me, me_handle1, void *);
299         hlen1 = DM_GET_LEN(msg_me, me_handle1);
300         hanp2 = DM_GET_VALUE(msg_me, me_handle2, void *);
301         hlen2 = DM_GET_LEN(msg_me, me_handle2);
302         namp1  = DM_GET_VALUE(msg_me, me_name1, void *);
303         nlen1 = DM_GET_LEN(msg_me, me_name1);
304         namp2 = DM_GET_VALUE(msg_me, me_name2, void *);
305         nlen2 = DM_GET_LEN(msg_me, me_name2);
306         hanp3 = DM_GET_VALUE(msg_me, me_roothandle, void *);
307         hlen3 = DM_GET_LEN(msg_me, me_roothandle);
308         mode  = msg_me->me_mode;
309 #endif  /* VERITAS_21 */
310
311         if (hanp1 && hlen1) {
312                 hantoa(hanp1, hlen1, hans1);
313         } else {
314                 sprintf(hans1, "<BAD HANDLE, hlen %d>", hlen1);
315         }
316         if (hanp2 && hlen2) {
317                 hantoa(hanp2, hlen2, hans2);
318         } else {
319                 sprintf(hans2, "<BAD HANDLE, hlen %d>", hlen2);
320         }
321         if (hanp3 && hlen3) {
322                 hantoa(hanp3, hlen3, hans3);
323         } else {
324                 sprintf(hans3, "<BAD HANDLE, hlen %d>", hlen3);
325         }
326         if (namp1 && nlen1) {
327                 strncpy(nams1, namp1, nlen1);
328                 if (nlen1 != sizeof(nams1))
329                         nams1[nlen1] = '\0';
330         } else {
331                 sprintf(nams1, "<BAD STRING, nlen %d>", nlen1);
332         }
333         if (namp2 && nlen2) {
334                 strncpy(nams2, namp2, nlen2);
335                 if (nlen2 != sizeof(nams2))
336                         nams2[nlen2] = '\0';
337         } else {
338                 sprintf(nams2, "<BAD STRING, nlen %d>", nlen2);
339         }
340
341         printf(VALS VALS VALS VALS VALS VALD,
342              "fs handle",       hans1,
343              "mtpt handle",     hans2,
344              "mtpt path",       nams1,
345              "media desig",     nams2,
346              "root handle",     hans3,
347              "mode",            mode);
348 }
349
350
351 /*
352  * First, weed out the events which return interesting structures.
353  * If it's not one of those, unpack the dm_namesp_event structure
354  * and display the contents.
355  */
356 int
357 handle_message(
358                dm_sessid_t      sid,
359                dm_eventmsg_t    *msg)
360 {
361   int                   pkt_error = 0;
362   int                   error;
363   int                   respond, response, respcode;
364   dm_namesp_event_t     *msg_ne;
365 #if     !VERITAS_21
366     dm_mount_event_t    *msg_me;
367 #endif
368   void                  *hanp1, *hanp2, *namp1, *namp2;
369   u_int                 hlen1, hlen2, nlen1, nlen2;
370   char                  hans1[HANDLE_STR], hans2[HANDLE_STR], hans3[HANDLE_STR];
371   char                  nams1[MAXNAMELEN], nams2[MAXNAMELEN];
372
373   /*
374    * Set the defaults for responding to events
375    */
376   respond = 1;
377   response = DM_RESP_CONTINUE;
378   respcode = 0;
379
380   /***** USER EVENTS *****/
381
382   if (msg->ev_type == DM_EVENT_USER) {
383     char        *privp;
384     u_int       plen, i;
385
386     printf(HDR,
387                 "user", msg->ev_token, msg->ev_sequence);
388
389     /* print private data as ascii or hex if it exists DM_CONFIG_MAX_MESSAGE_DATA */
390
391     privp = DM_GET_VALUE(msg, ev_data, char *);
392     plen  = DM_GET_LEN  (msg, ev_data);
393     if (plen) {
394         for (i = 0; i < plen; i++) {
395                 if (!isprint(privp[i]) && !isspace(privp[i]))
396                         break;
397         }
398         if (i == plen - 1 && privp[i] == '\0') {
399           printf(VALS,
400                         "privdata", privp);
401         } else {
402           printf("\t%-15s ", "privdata");
403           for (i = 0; i < plen; i++) {
404             printf("%.2x", privp[i]);
405           }
406           printf("\n");
407         }
408     } else {
409         printf(VALS,
410                 "privdata", "<NONE>");
411     }
412
413     if (msg->ev_token == DM_INVALID_TOKEN)      /* async dm_send_msg event */
414       respond = 0;
415   }
416
417   /***** CANCEL EVENT *****/
418
419 /* Not implemented on SGI or Veritas */
420
421   else if (msg->ev_type == DM_EVENT_CANCEL) {
422     dm_cancel_event_t   *msg_ce;
423
424     msg_ce = DM_GET_VALUE(msg, ev_data, dm_cancel_event_t *);
425     printf(HDR VALD VALD,
426              "cancel", msg->ev_token, msg->ev_sequence,
427              "sequence",        msg_ce->ce_sequence,
428              "token",           msg_ce->ce_token);
429     respond = 0;
430   }
431
432   /***** DATA EVENTS *****/
433
434   else if (msg->ev_type == DM_EVENT_READ ||
435            msg->ev_type == DM_EVENT_WRITE ||
436            msg->ev_type == DM_EVENT_TRUNCATE) {
437     dm_data_event_t     *msg_de;
438
439     msg_de = DM_GET_VALUE(msg, ev_data, dm_data_event_t *);
440     hanp1  = DM_GET_VALUE(msg_de, de_handle, void *);
441     hlen1  = DM_GET_LEN  (msg_de, de_handle);
442     if (hanp1 && hlen1) {
443       hantoa(hanp1, hlen1, hans1);
444     } else {
445       sprintf(hans1, "<BAD HANDLE, hlen %d>", hlen1);
446     }
447
448     switch(msg->ev_type) {
449
450     case DM_EVENT_READ:
451       printf(HDR VALS VALLLD VALLLD,
452              "read", msg->ev_token, msg->ev_sequence,
453              "file handle",     hans1,
454              "offset",          msg_de->de_offset,
455              "length",          msg_de->de_length);
456       break;
457
458     case DM_EVENT_WRITE:
459       printf(HDR VALS VALLLD VALLLD,
460              "write", msg->ev_token, msg->ev_sequence,
461              "file handle",     hans1,
462              "offset",          msg_de->de_offset,
463              "length",          msg_de->de_length);
464       break;
465
466     case DM_EVENT_TRUNCATE:
467       printf(HDR VALS VALLLD VALLLD,
468              "truncate", msg->ev_token, msg->ev_sequence,
469              "file handle",     hans1,
470              "offset",          msg_de->de_offset,
471              "length",          msg_de->de_length);
472       break;
473     }
474   }
475
476   /***** DESTROY EVENT *****/
477
478   else if (msg->ev_type == DM_EVENT_DESTROY) {
479     dm_destroy_event_t  *msg_ds;
480     char                attrname[DM_ATTR_NAME_SIZE + 1];
481     u_char              *copy;
482     u_int               clen;
483     u_int               i;
484
485     msg_ds= DM_GET_VALUE(msg, ev_data, dm_destroy_event_t *);
486     hanp1  = DM_GET_VALUE(msg_ds, ds_handle, void *);
487     hlen1  = DM_GET_LEN  (msg_ds, ds_handle);
488     if (hanp1 && hlen1) {
489       hantoa(hanp1, hlen1, hans1);
490     } else {
491       sprintf(hans1, "<BAD HANDLE, hlen %d>", hlen1);
492     }
493     if (msg_ds->ds_attrname.an_chars[0] != '\0') {
494       strncpy(attrname, (char *)msg_ds->ds_attrname.an_chars, sizeof(attrname));
495     } else {
496       strcpy(attrname, "<NONE>");
497     }
498     printf(HDR VALS VALS,
499              "destroy", msg->ev_token, msg->ev_sequence,
500              "handle",          hans1,
501              "attrname",        attrname);
502     copy  = DM_GET_VALUE(msg_ds, ds_attrcopy, u_char *);
503     clen  = DM_GET_LEN  (msg_ds, ds_attrcopy);
504     if (copy && clen) {
505       printf("\t%-15s ", "attrcopy");
506       for (i = 0; i < clen; i++) {
507         printf("%.2x", copy[i]);
508       }
509       printf("\n");
510     } else {
511       printf(VALS, "attrcopy", "<NONE>");
512     }
513     respond = 0;
514   }
515
516   /***** MOUNT EVENT *****/
517
518         else if (msg->ev_type == DM_EVENT_MOUNT) {
519                 printf(HDR, "mount", msg->ev_token, msg->ev_sequence);
520 #if     !VERITAS_21
521                 msg_me = DM_GET_VALUE(msg, ev_data, dm_mount_event_t *);
522                 print_one_mount_event(msg_me);
523 #else   /* VERITAS_21 */
524                 msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
525                 print_one_mount_event(msg_ne);
526 #endif  /* VERITAS_21 */
527   }
528
529   /***** NAMESPACE EVENTS *****/
530
531   else {
532     char        *type;
533
534     msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
535     hanp1  = DM_GET_VALUE(msg_ne, ne_handle1, void *);
536     hlen1  = DM_GET_LEN  (msg_ne, ne_handle1);
537     hanp2  = DM_GET_VALUE(msg_ne, ne_handle2, void *);
538     hlen2  = DM_GET_LEN  (msg_ne, ne_handle2);
539     namp1  = DM_GET_VALUE(msg_ne, ne_name1, void *);
540     nlen1  = DM_GET_LEN  (msg_ne, ne_name1);
541     namp2  = DM_GET_VALUE(msg_ne, ne_name2, void *);
542     nlen2  = DM_GET_LEN  (msg_ne, ne_name2);
543
544     if (hanp1 && hlen1) {
545       hantoa(hanp1, hlen1, hans1);
546     }
547     if (hanp2 && hlen2) {
548       hantoa(hanp2, hlen2, hans2);
549     }
550     if (namp1 && nlen1) {
551       strncpy(nams1, namp1, nlen1);
552       if (nlen1 != sizeof(nams1))
553         nams1[nlen1] = '\0';
554     }
555     if (namp2 && nlen2) {
556       strncpy(nams2, namp2, nlen2);
557       if (nlen2 != sizeof(nams2))
558         nams2[nlen2] = '\0';
559     }
560
561     if (msg->ev_type == DM_EVENT_PREUNMOUNT ||
562         msg->ev_type == DM_EVENT_UNMOUNT) {
563       if (msg_ne->ne_mode == 0) {
564         type = "NOFORCE";
565 #if     !VERITAS_21
566       } else if (msg_ne->ne_mode == DM_UNMOUNT_FORCE) {
567 #else
568       } else if (msg_ne->ne_mode > 0) {
569 #endif
570         type = "FORCE";
571       } else {
572         type = "UNKNOWN";
573         pkt_error++;
574       }
575     } else if (msg->ev_type == DM_EVENT_CREATE ||
576                msg->ev_type == DM_EVENT_POSTCREATE ||
577                msg->ev_type == DM_EVENT_REMOVE ||
578                msg->ev_type == DM_EVENT_POSTREMOVE) {
579         if (format_mode(msg_ne->ne_mode, &type)) {
580           pkt_error++;
581         }
582     }
583
584     switch(msg->ev_type) {
585
586     case DM_EVENT_PREUNMOUNT:
587       printf(HDR VALS VALS VALS,
588              "preunmount", msg->ev_token, msg->ev_sequence,
589              "fs handle",       hans1,
590              "root dir",        hans2,
591              "unmount mode",    type);
592       break;
593
594     case DM_EVENT_UNMOUNT:
595       printf(HDR VALS VALS VALD,
596              "unmount", msg->ev_token, msg->ev_sequence,
597              "fs handle",       hans1,
598              "unmount mode",    type,
599              "retcode",         msg_ne->ne_retcode);
600       break;
601
602     case DM_EVENT_NOSPACE:
603       printf(HDR VALS,
604              "nospace", msg->ev_token, msg->ev_sequence,
605              "fs handle",       hans1);
606       response = DM_RESP_ABORT;
607       respcode = ENOSPC;
608       break;
609
610     case DM_EVENT_DEBUT:                /* not supported on SGI */
611       printf(HDR VALS,
612              "debut", msg->ev_token, msg->ev_sequence,
613              "object",          hans1);
614       break;
615
616     case DM_EVENT_CREATE:
617       printf(HDR VALS VALS VALS,
618              "create", msg->ev_token, msg->ev_sequence,
619              "parent dir",      hans1,
620              "name",            nams1,
621              "mode bits",       type);
622       break;
623
624     case DM_EVENT_POSTCREATE:
625       printf(HDR VALS VALS VALS VALS VALD,
626              "postcreate", msg->ev_token, msg->ev_sequence,
627              "parent dir",      hans1,
628              "new object",      hans2,
629              "name",            nams1,
630              "mode bits",       type,
631              "retcode",         msg_ne->ne_retcode);
632       respond = 0;
633       break;
634
635     case DM_EVENT_REMOVE:
636       printf(HDR VALS VALS VALS,
637              "remove", msg->ev_token, msg->ev_sequence,
638              "parent dir",      hans1,
639              "name",            nams1,
640              "mode bits",       type);
641       break;
642
643     case DM_EVENT_POSTREMOVE:
644       printf(HDR VALS VALS VALS VALD,
645              "postremove", msg->ev_token, msg->ev_sequence,
646              "parent dir",      hans1,
647              "name",            nams1,
648              "mode bits",       type,
649              "retcode",         msg_ne->ne_retcode);
650       respond = 0;
651       break;
652
653     case DM_EVENT_RENAME:
654       printf(HDR VALS VALS VALS VALS,
655              "rename", msg->ev_token, msg->ev_sequence,
656              "old parent",      hans1,
657              "new parent",      hans2,
658              "old name",        nams1,
659              "new name",        nams2);
660       break;
661
662     case DM_EVENT_POSTRENAME:
663       printf(HDR VALS VALS VALS VALS VALD,
664              "postrename", msg->ev_token, msg->ev_sequence,
665              "old parent",      hans1,
666              "new parent",      hans2,
667              "old name",        nams1,
668              "new name",        nams2,
669              "retcode",         msg_ne->ne_retcode);
670       respond = 0;
671       break;
672
673     case DM_EVENT_SYMLINK:
674       printf(HDR VALS VALS VALS,
675              "symlink", msg->ev_token, msg->ev_sequence,
676              "parent dir",      hans1,
677              "name",            nams1,
678              "contents",        nams2);
679       break;
680
681     case DM_EVENT_POSTSYMLINK:
682       printf(HDR VALS VALS VALS VALS VALD,
683              "postsymlink", msg->ev_token, msg->ev_sequence,
684              "parent dir",      hans1,
685              "new object",      hans2,
686              "name",            nams1,
687              "contents",        nams2,
688              "retcode",         msg_ne->ne_retcode);
689       respond = 0;
690       break;
691
692     case DM_EVENT_LINK:
693       printf(HDR VALS VALS VALS,
694              "link", msg->ev_token, msg->ev_sequence,
695              "parent dir",      hans1,
696              "source",          hans2,
697              "name",            nams1);
698       break;
699
700     case DM_EVENT_POSTLINK:
701       printf(HDR VALS VALS VALS VALD,
702              "postlink", msg->ev_token, msg->ev_sequence,
703              "parent dir",      hans1,
704              "source",          hans2,
705              "name",            nams1,
706              "retcode",         msg_ne->ne_retcode);
707       respond = 0;
708       break;
709
710     case DM_EVENT_ATTRIBUTE:
711       printf(HDR VALS,
712              "attribute", msg->ev_token, msg->ev_sequence,
713              "object",          hans1);
714       respond = 0;
715       break;
716
717     case DM_EVENT_CLOSE:        /* not supported on SGI */
718       printf(HDR VALS,
719              "close", msg->ev_token, msg->ev_sequence,
720              "object",          hans1);
721       respond = 0;
722       break;
723
724     default:
725       pkt_error++;
726       printf(HDR VALD,
727              "<UNKNOWN>", msg->ev_token, msg->ev_sequence,
728              "ev_type",         msg->ev_type);
729       if (msg->ev_token == DM_INVALID_TOKEN)
730         respond = 0;
731       break;
732     }
733   }
734
735   /*
736    * Now respond to those messages which require a response
737    */
738   if (respond) {
739     error = dm_respond_event(sid, msg->ev_token, response, respcode, 0, 0);
740     if (error) {
741       errno_msg("Can't respond to event");
742       return error;
743     }
744     if (Sleep) {
745       err_msg("Sleeping for %d seconds!\n", Sleep);
746       sleep(Sleep);
747     }
748   }
749
750   return 0;
751 }
752
753
754 /*
755         Convert a mode_t field into a printable string.
756
757         Returns non-zero if the mode_t is invalid.  The string is
758         returned in *ptr, whether there is an error or not.
759 */
760
761 static int
762 format_mode(
763         mode_t  mode,
764         char    **ptr)
765 {
766 static  char    modestr[100];
767         char    *typestr;
768         int     error = 0;
769
770         if     (S_ISFIFO(mode)) typestr = "FIFO";
771         else if(S_ISCHR (mode)) typestr = "Character Device";
772         else if(S_ISBLK (mode)) typestr = "Block Device";
773         else if(S_ISDIR (mode)) typestr = "Directory";
774         else if(S_ISREG (mode)) typestr = "Regular File";
775         else if(S_ISLNK (mode)) typestr = "Symbolic Link";
776         else if(S_ISSOCK(mode)) typestr = "Socket";
777         else {
778                 typestr = "<unknown type>"; 
779                 error++;
780         }
781
782         sprintf(modestr, "mode %06o: perm %c%c%c %c%c%c %c%c%c %c%c%c, type %s",
783                 mode,
784                 mode & S_ISUID ? 's':' ',
785                 mode & S_ISGID ? 'g':' ',
786                 mode & S_ISVTX ? 't':' ',
787                 mode & S_IRUSR ? 'r':'-',
788                 mode & S_IWUSR ? 'w':'-',
789                 mode & S_IXUSR ? 'x':'-',
790                 mode & S_IRGRP ? 'r':'-',
791                 mode & S_IWGRP ? 'w':'-',
792                 mode & S_IXGRP ? 'x':'-',
793                 mode & S_IROTH ? 'r':'-',
794                 mode & S_IWOTH ? 'w':'-',
795                 mode & S_IXOTH ? 'x':'-',
796                 typestr);
797         *ptr = modestr;
798         return(error);
799 }
800
801
802 static int
803 get_fs_handle(
804         char    *fsname,
805         void    **fs_hanpp,
806         size_t  *fs_hlenp)
807 {
808         char    hans[HANDLE_STR];
809
810         if (dm_path_to_fshandle(fsname, fs_hanpp, fs_hlenp) == -1) {
811                 errno_msg("Can't get filesystem handle");
812                 return 1;
813         }
814         if (Verbose) {
815                 hantoa(*fs_hanpp, *fs_hlenp, hans);
816                 err_msg("File system handle for %s: %s\n", fsname, hans);
817         }
818         return 0;
819 }
820
821
822 /*
823         Set the event disposition for this filesystem to include all valid
824         DMAPI events so that we receive all events for this filesystem.
825         Also set DM_EVENT_MOUNT disposition for the global handle.
826         It does not make sense to specify DM_EVENT_USER in the disposition
827         mask since a session is always unconditionally registered for these
828         events.
829
830         Returns non-zero on error.
831 */
832
833 static int
834 set_disposition(
835         dm_sessid_t      sid,
836         void            *fs_hanp,
837         size_t           fs_hlen)
838 {
839         dm_eventset_t   eventlist;
840
841         if (Verbose) {
842                 err_msg("Setting event disposition to send all "
843                         "events to this session\n");
844         }
845
846         /* DM_EVENT_MOUNT must be sent in a separate request using the global
847            handle.  If we ever support more than one filesystem at a time, this
848            request should be moved out of this routine to a place where it is
849            issued just once.
850         */
851
852         DMEV_ZERO(eventlist);
853         DMEV_SET(DM_EVENT_MOUNT, eventlist);
854
855         if (dm_set_disp(sid, DM_GLOBAL_HANP, DM_GLOBAL_HLEN, DM_NO_TOKEN,
856                         &eventlist, DM_EVENT_MAX) == -1) {
857                 errno_msg("Can't set event disposition for mount");
858                 return(1);
859         }
860
861         DMEV_ZERO(eventlist);
862
863         /* File system administration events. */
864
865         DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist);
866         DMEV_SET(DM_EVENT_UNMOUNT, eventlist);
867         DMEV_SET(DM_EVENT_NOSPACE, eventlist);
868
869         /* While DM_EVENT_DEBUT is optional, it appears that the spec always
870            lets it be specified in a dm_set_disp call; its just that the
871            event will never be seen on some platforms.
872         */
873
874         DMEV_SET(DM_EVENT_DEBUT, eventlist);
875
876
877         /* Namespace events. */
878
879         DMEV_SET(DM_EVENT_CREATE, eventlist);
880         DMEV_SET(DM_EVENT_POSTCREATE, eventlist);
881         DMEV_SET(DM_EVENT_REMOVE, eventlist);
882         DMEV_SET(DM_EVENT_POSTREMOVE, eventlist);
883         DMEV_SET(DM_EVENT_RENAME, eventlist);
884         DMEV_SET(DM_EVENT_POSTRENAME, eventlist);
885         DMEV_SET(DM_EVENT_LINK, eventlist);
886         DMEV_SET(DM_EVENT_POSTLINK, eventlist);
887         DMEV_SET(DM_EVENT_SYMLINK, eventlist);
888         DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist);
889
890         /* Managed region data events. */
891
892         DMEV_SET(DM_EVENT_READ, eventlist);
893         DMEV_SET(DM_EVENT_WRITE, eventlist);
894         DMEV_SET(DM_EVENT_TRUNCATE, eventlist);
895
896         /* Metadata events. */
897
898         DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist);
899 #if 0
900 #if     ! defined ( __sgi ) && ! defined ( VERITAS_21 )
901         DMEV_SET(DM_EVENT_CANCEL, eventlist);   /* not supported on SGI */
902 #endif
903 #ifndef __sgi
904         DMEV_SET(DM_EVENT_CLOSE, eventlist);    /* not supported on SGI */
905 #endif
906 #endif
907         DMEV_SET(DM_EVENT_DESTROY, eventlist);
908
909         /* Pseudo-events. */
910
911         /* DM_EVENT_USER - always enabled - causes EINVAL if specified */
912
913         if (dm_set_disp(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
914                         &eventlist, DM_EVENT_MAX) == -1) {
915                 errno_msg("Can't set event disposition for filesystem");
916                 return(1);
917         }
918         return(0);
919 }
920
921
922 /*
923         Enable event generation on each valid filesystem-based DMAPI event
924         within the given file system.
925
926         Returns non-zero on errors.
927 */
928
929 static int
930 set_events(
931         dm_sessid_t      sid,
932         void            *fs_hanp,
933         size_t           fs_hlen)
934 {
935         dm_eventset_t   eventlist;
936
937         if (Verbose) {
938                 err_msg("Setting event list to enable all events "
939                         "for this file system\n");
940         }
941         DMEV_ZERO(eventlist);
942
943         /* File system administration events. */
944
945         /* DM_EVENT_MOUNT - always enabled on the global handle - causes
946            EINVAL if specified.
947         */
948         DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist);
949         DMEV_SET(DM_EVENT_UNMOUNT, eventlist);
950         DMEV_SET(DM_EVENT_NOSPACE, eventlist);
951         /* DM_EVENT_DEBUT - always enabled - causes EINVAL if specified. */
952
953         /* Namespace events. */
954
955         DMEV_SET(DM_EVENT_CREATE, eventlist);
956         DMEV_SET(DM_EVENT_POSTCREATE, eventlist);
957         DMEV_SET(DM_EVENT_REMOVE, eventlist);
958         DMEV_SET(DM_EVENT_POSTREMOVE, eventlist);
959         DMEV_SET(DM_EVENT_RENAME, eventlist);
960         DMEV_SET(DM_EVENT_POSTRENAME, eventlist);
961         DMEV_SET(DM_EVENT_LINK, eventlist);
962         DMEV_SET(DM_EVENT_POSTLINK, eventlist);
963         DMEV_SET(DM_EVENT_SYMLINK, eventlist);
964         DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist);
965
966          /* Managed region data events.  These are not settable by
967             dm_set_eventlist on a filesystem basis.   They are meant
968             to be set using dm_set_region on regular files only.
969             However, in the SGI implementation, they are filesystem-settable.
970             Since this is useful for testing purposes, do it.
971         */
972
973         /* DM_EVENT_READ */
974         /* DM_EVENT_WRITE */
975         /* DM_EVENT_TRUNCATE */
976
977         /* Metadata events. */
978
979         DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist);
980 #if 0
981 #if     ! defined ( __sgi ) && ! defined ( VERITAS_21 )
982         DMEV_SET(DM_EVENT_CANCEL, eventlist);   /* not supported on SGI */
983 #endif
984 #ifndef __sgi
985         DMEV_SET(DM_EVENT_CLOSE, eventlist);    /* not supported on SGI */
986 #endif
987 #endif
988         DMEV_SET(DM_EVENT_DESTROY, eventlist);
989
990         /* Pseudo-events. */
991
992         /* DM_EVENT_USER - always enabled - causes EINVAL if specified */
993
994         if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
995                         &eventlist, DM_EVENT_MAX) == -1) {
996                 errno_msg("Can't set event list");
997                 return(1);
998         }
999         return(0);
1000 }
1001
1002
1003 /*
1004         Disable monitoring for all events in the DMAPI for the given
1005         file system.  This is done before exiting so that future
1006         operations won't hang waiting for their events to be handled.
1007
1008         Returns non-zero on errors.
1009 */
1010
1011 static int
1012 clear_events(
1013         dm_sessid_t      sid,
1014         void            *fs_hanp,
1015         size_t           fs_hlen)
1016 {
1017         dm_eventset_t   eventlist;
1018
1019         if (Verbose) {
1020                 err_msg("Clearing event list to disable all events "
1021                         "for this filesystem\n");
1022         }
1023         DMEV_ZERO(eventlist);
1024
1025         if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
1026                         &eventlist, DM_EVENT_MAX) == -1) {
1027                 errno_msg("Can't clear event list");
1028                 return(1);
1029         }
1030         return(0);
1031 }
1032
1033
1034 /*
1035  * Respond to any events which haven't been handled yet.
1036  * dm_getall_tokens provides a list of tokens for the outstanding events.
1037  * dm_find_eventmsg uses the token to lookup the corresponding message.
1038  * The message is passed to handle_message() for normal response processing.
1039  */
1040 int
1041 finish_responding(
1042                   dm_sessid_t   sid)
1043 {
1044   int           error = 0;
1045   u_int         nbytes, ntokens = 0, ret_ntokens, i;
1046   dm_token_t    *tokenbuf = NULL;
1047   size_t        buflen, ret_buflen;
1048   char          *msgbuf = NULL;
1049   dm_eventmsg_t *msg;
1050
1051   if (Verbose)
1052     err_msg("Responding to any outstanding delivered event messages\n");
1053
1054   /*
1055    * Initial sizes for the token and message buffers
1056    */
1057   ret_buflen = 16 * (sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t)
1058                      + HANDLE_LEN);
1059   ret_ntokens = 16;
1060
1061   /*
1062    * The E2BIG dance...
1063    * Take a guess at how large to make the buffer, starting with ret_ntokens.
1064    * If the routine returns E2BIG, use the returned size and try again.
1065    * If we're already using the returned size, double it and try again.
1066    */
1067   do {
1068     ntokens = (ntokens != ret_ntokens) ? ret_ntokens : ntokens*2;
1069     nbytes = ntokens * (sizeof(dm_token_t) + sizeof(dm_vardata_t));
1070     tokenbuf = malloc(nbytes);
1071     if (tokenbuf == NULL) {
1072       err_msg("Can't malloc %d bytes for tokenbuf\n", nbytes);
1073       error = 1;
1074       goto out;
1075     }
1076     error = dm_getall_tokens(sid, ntokens, tokenbuf, &ret_ntokens);
1077   } while (error && errno == E2BIG);
1078
1079   if (error) {
1080     errno_msg("Can't get all outstanding tokens");
1081     goto out;
1082   }
1083
1084   for (i = 0; i < ret_ntokens; i++) {
1085     if (Verbose)
1086       err_msg("Responding to outstanding event for token %d\n",(int)*tokenbuf);
1087
1088     /*
1089      * The E2BIG dance reprise...
1090      */
1091     do {
1092       buflen = (buflen != ret_buflen) ? ret_buflen : buflen * 2;
1093       msgbuf = malloc(buflen);
1094       if (msgbuf == NULL) {
1095         err_msg("Can't malloc %d bytes for msgbuf\n", buflen);
1096         error = 1;
1097         goto out;
1098       }
1099       error = dm_find_eventmsg(sid, *tokenbuf, buflen, msgbuf, &ret_buflen);
1100     } while (error && errno == E2BIG);
1101     if (error) {
1102       errno_msg("Can't find the event message for token %d", (int)*tokenbuf);
1103       goto out;
1104     }
1105
1106     msg = (dm_eventmsg_t *) msgbuf;
1107     while (msg != NULL) {
1108       error = handle_message(sid, msg);
1109       if (error)
1110         goto out;
1111       msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *);
1112     }
1113
1114     tokenbuf++;
1115   }
1116
1117  out:
1118   if (tokenbuf)
1119     free(tokenbuf);
1120   if (msgbuf)
1121     free(msgbuf);
1122   return error;
1123 }
1124
1125
1126 /*
1127  * Establish an exit handler since we run in an infinite loop
1128  */
1129 int
1130 establish_handler(void)
1131 {
1132   struct sigaction      act;
1133
1134   /*
1135    * Set up signals so that we can wait for spawned children
1136    */
1137   act.sa_handler = exit_handler;
1138   act.sa_flags   = 0;
1139   sigemptyset(&act.sa_mask);
1140
1141   (void)sigaction(SIGHUP, &act, NULL);
1142   (void)sigaction(SIGINT, &act, NULL);
1143   (void)sigaction(SIGQUIT, &act, NULL);
1144   (void)sigaction(SIGTERM, &act, NULL);
1145   (void)sigaction(SIGUSR1, &act, NULL);
1146   (void)sigaction(SIGUSR1, &act, NULL);
1147   (void)sigaction(SIGUSR2, &act, NULL);
1148
1149   return(0);
1150 }
1151
1152
1153 /*
1154  * Exit gracefully
1155  *
1156  * Stop events from being generated for the given file system
1157  * Respond to any events that were delivered but unanswered
1158  *  (the event loop may have been in the middle of taking care of the event)
1159  * Try getting any undelivered events but don't block if none are there
1160  *  (the file system may have generated an event after we killed dm_get_events)
1161  * Shutdown the session using the global "sid" variable.
1162  */
1163 void
1164 exit_handler(void)
1165 {
1166   int           error;
1167   void          *fs_hanp;
1168   size_t        fs_hlen;
1169
1170   if (Verbose)
1171     printf("\n"),
1172     err_msg("Exiting...\n");
1173
1174   error = get_fs_handle(fsname, &fs_hanp, &fs_hlen);
1175
1176   if (!error) {
1177     error = clear_events(sid, fs_hanp, fs_hlen);
1178     if (error)
1179       /* just keep going */ ;
1180   }
1181
1182   error = finish_responding(sid);
1183   if (error)
1184     /* just keep going */ ;
1185
1186   err_msg("Processing any undelivered event messages\n");
1187   event_loop(sid, 0 /*waitflag*/);
1188
1189   err_msg("Shutting down the session\n");
1190   if (sid != NULL) {
1191     error = dm_destroy_session(sid);
1192     if (error == -1) {
1193       errno_msg("Can't shut down session - use 'mrmean -kv' to clean up!");
1194     }
1195   }
1196
1197   exit(0);
1198 }