7d009af2329f7d59745a1ee64498204cd2b08671
[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   (int);
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(0);
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   dm_response_t         response;
364   int                   respond, respcode;
365   dm_namesp_event_t     *msg_ne;
366 #if     !VERITAS_21
367     dm_mount_event_t    *msg_me;
368 #endif
369   void                  *hanp1, *hanp2, *namp1, *namp2;
370   u_int                 hlen1, hlen2, nlen1, nlen2;
371   char                  hans1[HANDLE_STR], hans2[HANDLE_STR], hans3[HANDLE_STR];
372   char                  nams1[MAXNAMELEN], nams2[MAXNAMELEN];
373
374   /*
375    * Set the defaults for responding to events
376    */
377   respond = 1;
378   response = DM_RESP_CONTINUE;
379   respcode = 0;
380
381   /***** USER EVENTS *****/
382
383   if (msg->ev_type == DM_EVENT_USER) {
384     char        *privp;
385     u_int       plen, i;
386
387     printf(HDR,
388                 "user", msg->ev_token, msg->ev_sequence);
389
390     /* print private data as ascii or hex if it exists DM_CONFIG_MAX_MESSAGE_DATA */
391
392     privp = DM_GET_VALUE(msg, ev_data, char *);
393     plen  = DM_GET_LEN  (msg, ev_data);
394     if (plen) {
395         for (i = 0; i < plen; i++) {
396                 if (!isprint(privp[i]) && !isspace(privp[i]))
397                         break;
398         }
399         if (i == plen - 1 && privp[i] == '\0') {
400           printf(VALS,
401                         "privdata", privp);
402         } else {
403           printf("\t%-15s ", "privdata");
404           for (i = 0; i < plen; i++) {
405             printf("%.2x", privp[i]);
406           }
407           printf("\n");
408         }
409     } else {
410         printf(VALS,
411                 "privdata", "<NONE>");
412     }
413
414     if (msg->ev_token == DM_INVALID_TOKEN)      /* async dm_send_msg event */
415       respond = 0;
416   }
417
418   /***** CANCEL EVENT *****/
419
420 /* Not implemented on SGI or Veritas */
421
422   else if (msg->ev_type == DM_EVENT_CANCEL) {
423     dm_cancel_event_t   *msg_ce;
424
425     msg_ce = DM_GET_VALUE(msg, ev_data, dm_cancel_event_t *);
426     printf(HDR VALD VALD,
427              "cancel", msg->ev_token, msg->ev_sequence,
428              "sequence",        msg_ce->ce_sequence,
429              "token",           msg_ce->ce_token);
430     respond = 0;
431   }
432
433   /***** DATA EVENTS *****/
434
435   else if (msg->ev_type == DM_EVENT_READ ||
436            msg->ev_type == DM_EVENT_WRITE ||
437            msg->ev_type == DM_EVENT_TRUNCATE) {
438     dm_data_event_t     *msg_de;
439
440     msg_de = DM_GET_VALUE(msg, ev_data, dm_data_event_t *);
441     hanp1  = DM_GET_VALUE(msg_de, de_handle, void *);
442     hlen1  = DM_GET_LEN  (msg_de, de_handle);
443     if (hanp1 && hlen1) {
444       hantoa(hanp1, hlen1, hans1);
445     } else {
446       sprintf(hans1, "<BAD HANDLE, hlen %d>", hlen1);
447     }
448
449     switch(msg->ev_type) {
450
451     case DM_EVENT_READ:
452       printf(HDR VALS VALLLD VALLLD,
453              "read", msg->ev_token, msg->ev_sequence,
454              "file handle",     hans1,
455              "offset",          msg_de->de_offset,
456              "length",          msg_de->de_length);
457       break;
458
459     case DM_EVENT_WRITE:
460       printf(HDR VALS VALLLD VALLLD,
461              "write", msg->ev_token, msg->ev_sequence,
462              "file handle",     hans1,
463              "offset",          msg_de->de_offset,
464              "length",          msg_de->de_length);
465       break;
466
467     case DM_EVENT_TRUNCATE:
468       printf(HDR VALS VALLLD VALLLD,
469              "truncate", msg->ev_token, msg->ev_sequence,
470              "file handle",     hans1,
471              "offset",          msg_de->de_offset,
472              "length",          msg_de->de_length);
473       break;
474     }
475   }
476
477   /***** DESTROY EVENT *****/
478
479   else if (msg->ev_type == DM_EVENT_DESTROY) {
480     dm_destroy_event_t  *msg_ds;
481     char                attrname[DM_ATTR_NAME_SIZE + 1];
482     u_char              *copy;
483     u_int               clen;
484     u_int               i;
485
486     msg_ds= DM_GET_VALUE(msg, ev_data, dm_destroy_event_t *);
487     hanp1  = DM_GET_VALUE(msg_ds, ds_handle, void *);
488     hlen1  = DM_GET_LEN  (msg_ds, ds_handle);
489     if (hanp1 && hlen1) {
490       hantoa(hanp1, hlen1, hans1);
491     } else {
492       sprintf(hans1, "<BAD HANDLE, hlen %d>", hlen1);
493     }
494     if (msg_ds->ds_attrname.an_chars[0] != '\0') {
495       strncpy(attrname, (char *)msg_ds->ds_attrname.an_chars, sizeof(attrname));
496     } else {
497       strcpy(attrname, "<NONE>");
498     }
499     printf(HDR VALS VALS,
500              "destroy", msg->ev_token, msg->ev_sequence,
501              "handle",          hans1,
502              "attrname",        attrname);
503     copy  = DM_GET_VALUE(msg_ds, ds_attrcopy, u_char *);
504     clen  = DM_GET_LEN  (msg_ds, ds_attrcopy);
505     if (copy && clen) {
506       printf("\t%-15s ", "attrcopy");
507       for (i = 0; i < clen; i++) {
508         printf("%.2x", copy[i]);
509       }
510       printf("\n");
511     } else {
512       printf(VALS, "attrcopy", "<NONE>");
513     }
514     respond = 0;
515   }
516
517   /***** MOUNT EVENT *****/
518
519         else if (msg->ev_type == DM_EVENT_MOUNT) {
520                 printf(HDR, "mount", msg->ev_token, msg->ev_sequence);
521 #if     !VERITAS_21
522                 msg_me = DM_GET_VALUE(msg, ev_data, dm_mount_event_t *);
523                 print_one_mount_event(msg_me);
524 #else   /* VERITAS_21 */
525                 msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
526                 print_one_mount_event(msg_ne);
527 #endif  /* VERITAS_21 */
528   }
529
530   /***** NAMESPACE EVENTS *****/
531
532   else {
533     char        *type;
534
535     msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
536     hanp1  = DM_GET_VALUE(msg_ne, ne_handle1, void *);
537     hlen1  = DM_GET_LEN  (msg_ne, ne_handle1);
538     hanp2  = DM_GET_VALUE(msg_ne, ne_handle2, void *);
539     hlen2  = DM_GET_LEN  (msg_ne, ne_handle2);
540     namp1  = DM_GET_VALUE(msg_ne, ne_name1, void *);
541     nlen1  = DM_GET_LEN  (msg_ne, ne_name1);
542     namp2  = DM_GET_VALUE(msg_ne, ne_name2, void *);
543     nlen2  = DM_GET_LEN  (msg_ne, ne_name2);
544
545     if (hanp1 && hlen1) {
546       hantoa(hanp1, hlen1, hans1);
547     }
548     if (hanp2 && hlen2) {
549       hantoa(hanp2, hlen2, hans2);
550     }
551     if (namp1 && nlen1) {
552       strncpy(nams1, namp1, nlen1);
553       if (nlen1 != sizeof(nams1))
554         nams1[nlen1] = '\0';
555     }
556     if (namp2 && nlen2) {
557       strncpy(nams2, namp2, nlen2);
558       if (nlen2 != sizeof(nams2))
559         nams2[nlen2] = '\0';
560     }
561
562     if (msg->ev_type == DM_EVENT_PREUNMOUNT ||
563         msg->ev_type == DM_EVENT_UNMOUNT) {
564       if (msg_ne->ne_mode == 0) {
565         type = "NOFORCE";
566 #if     !VERITAS_21
567       } else if (msg_ne->ne_mode == DM_UNMOUNT_FORCE) {
568 #else
569       } else if (msg_ne->ne_mode > 0) {
570 #endif
571         type = "FORCE";
572       } else {
573         type = "UNKNOWN";
574         pkt_error++;
575       }
576     } else if (msg->ev_type == DM_EVENT_CREATE ||
577                msg->ev_type == DM_EVENT_POSTCREATE ||
578                msg->ev_type == DM_EVENT_REMOVE ||
579                msg->ev_type == DM_EVENT_POSTREMOVE) {
580         if (format_mode(msg_ne->ne_mode, &type)) {
581           pkt_error++;
582         }
583     }
584
585     switch(msg->ev_type) {
586
587     case DM_EVENT_PREUNMOUNT:
588       printf(HDR VALS VALS VALS,
589              "preunmount", msg->ev_token, msg->ev_sequence,
590              "fs handle",       hans1,
591              "root dir",        hans2,
592              "unmount mode",    type);
593       break;
594
595     case DM_EVENT_UNMOUNT:
596       printf(HDR VALS VALS VALD,
597              "unmount", msg->ev_token, msg->ev_sequence,
598              "fs handle",       hans1,
599              "unmount mode",    type,
600              "retcode",         msg_ne->ne_retcode);
601       break;
602
603     case DM_EVENT_NOSPACE:
604       printf(HDR VALS,
605              "nospace", msg->ev_token, msg->ev_sequence,
606              "fs handle",       hans1);
607       response = DM_RESP_ABORT;
608       respcode = ENOSPC;
609       break;
610
611     case DM_EVENT_DEBUT:                /* not supported on SGI */
612       printf(HDR VALS,
613              "debut", msg->ev_token, msg->ev_sequence,
614              "object",          hans1);
615       break;
616
617     case DM_EVENT_CREATE:
618       printf(HDR VALS VALS VALS,
619              "create", msg->ev_token, msg->ev_sequence,
620              "parent dir",      hans1,
621              "name",            nams1,
622              "mode bits",       type);
623       break;
624
625     case DM_EVENT_POSTCREATE:
626       printf(HDR VALS VALS VALS VALS VALD,
627              "postcreate", msg->ev_token, msg->ev_sequence,
628              "parent dir",      hans1,
629              "new object",      hans2,
630              "name",            nams1,
631              "mode bits",       type,
632              "retcode",         msg_ne->ne_retcode);
633       respond = 0;
634       break;
635
636     case DM_EVENT_REMOVE:
637       printf(HDR VALS VALS VALS,
638              "remove", msg->ev_token, msg->ev_sequence,
639              "parent dir",      hans1,
640              "name",            nams1,
641              "mode bits",       type);
642       break;
643
644     case DM_EVENT_POSTREMOVE:
645       printf(HDR VALS VALS VALS VALD,
646              "postremove", msg->ev_token, msg->ev_sequence,
647              "parent dir",      hans1,
648              "name",            nams1,
649              "mode bits",       type,
650              "retcode",         msg_ne->ne_retcode);
651       respond = 0;
652       break;
653
654     case DM_EVENT_RENAME:
655       printf(HDR VALS VALS VALS VALS,
656              "rename", msg->ev_token, msg->ev_sequence,
657              "old parent",      hans1,
658              "new parent",      hans2,
659              "old name",        nams1,
660              "new name",        nams2);
661       break;
662
663     case DM_EVENT_POSTRENAME:
664       printf(HDR VALS VALS VALS VALS VALD,
665              "postrename", msg->ev_token, msg->ev_sequence,
666              "old parent",      hans1,
667              "new parent",      hans2,
668              "old name",        nams1,
669              "new name",        nams2,
670              "retcode",         msg_ne->ne_retcode);
671       respond = 0;
672       break;
673
674     case DM_EVENT_SYMLINK:
675       printf(HDR VALS VALS VALS,
676              "symlink", msg->ev_token, msg->ev_sequence,
677              "parent dir",      hans1,
678              "name",            nams1,
679              "contents",        nams2);
680       break;
681
682     case DM_EVENT_POSTSYMLINK:
683       printf(HDR VALS VALS VALS VALS VALD,
684              "postsymlink", msg->ev_token, msg->ev_sequence,
685              "parent dir",      hans1,
686              "new object",      hans2,
687              "name",            nams1,
688              "contents",        nams2,
689              "retcode",         msg_ne->ne_retcode);
690       respond = 0;
691       break;
692
693     case DM_EVENT_LINK:
694       printf(HDR VALS VALS VALS,
695              "link", msg->ev_token, msg->ev_sequence,
696              "parent dir",      hans1,
697              "source",          hans2,
698              "name",            nams1);
699       break;
700
701     case DM_EVENT_POSTLINK:
702       printf(HDR VALS VALS VALS VALD,
703              "postlink", msg->ev_token, msg->ev_sequence,
704              "parent dir",      hans1,
705              "source",          hans2,
706              "name",            nams1,
707              "retcode",         msg_ne->ne_retcode);
708       respond = 0;
709       break;
710
711     case DM_EVENT_ATTRIBUTE:
712       printf(HDR VALS,
713              "attribute", msg->ev_token, msg->ev_sequence,
714              "object",          hans1);
715       respond = 0;
716       break;
717
718     case DM_EVENT_CLOSE:        /* not supported on SGI */
719       printf(HDR VALS,
720              "close", msg->ev_token, msg->ev_sequence,
721              "object",          hans1);
722       respond = 0;
723       break;
724
725     default:
726       pkt_error++;
727       printf(HDR VALD,
728              "<UNKNOWN>", msg->ev_token, msg->ev_sequence,
729              "ev_type",         msg->ev_type);
730       if (msg->ev_token == DM_INVALID_TOKEN)
731         respond = 0;
732       break;
733     }
734   }
735
736   /*
737    * Now respond to those messages which require a response
738    */
739   if (respond) {
740     error = dm_respond_event(sid, msg->ev_token, response, respcode, 0, 0);
741     if (error) {
742       errno_msg("Can't respond to event");
743       return error;
744     }
745     if (Sleep) {
746       err_msg("Sleeping for %d seconds!\n", Sleep);
747       sleep(Sleep);
748     }
749   }
750
751   return 0;
752 }
753
754
755 /*
756         Convert a mode_t field into a printable string.
757
758         Returns non-zero if the mode_t is invalid.  The string is
759         returned in *ptr, whether there is an error or not.
760 */
761
762 static int
763 format_mode(
764         mode_t  mode,
765         char    **ptr)
766 {
767 static  char    modestr[100];
768         char    *typestr;
769         int     error = 0;
770
771         if     (S_ISFIFO(mode)) typestr = "FIFO";
772         else if(S_ISCHR (mode)) typestr = "Character Device";
773         else if(S_ISBLK (mode)) typestr = "Block Device";
774         else if(S_ISDIR (mode)) typestr = "Directory";
775         else if(S_ISREG (mode)) typestr = "Regular File";
776         else if(S_ISLNK (mode)) typestr = "Symbolic Link";
777         else if(S_ISSOCK(mode)) typestr = "Socket";
778         else {
779                 typestr = "<unknown type>"; 
780                 error++;
781         }
782
783         sprintf(modestr, "mode %06o: perm %c%c%c %c%c%c %c%c%c %c%c%c, type %s",
784                 mode,
785                 mode & S_ISUID ? 's':' ',
786                 mode & S_ISGID ? 'g':' ',
787                 mode & S_ISVTX ? 't':' ',
788                 mode & S_IRUSR ? 'r':'-',
789                 mode & S_IWUSR ? 'w':'-',
790                 mode & S_IXUSR ? 'x':'-',
791                 mode & S_IRGRP ? 'r':'-',
792                 mode & S_IWGRP ? 'w':'-',
793                 mode & S_IXGRP ? 'x':'-',
794                 mode & S_IROTH ? 'r':'-',
795                 mode & S_IWOTH ? 'w':'-',
796                 mode & S_IXOTH ? 'x':'-',
797                 typestr);
798         *ptr = modestr;
799         return(error);
800 }
801
802
803 static int
804 get_fs_handle(
805         char    *fsname,
806         void    **fs_hanpp,
807         size_t  *fs_hlenp)
808 {
809         char    hans[HANDLE_STR];
810
811         if (dm_path_to_fshandle(fsname, fs_hanpp, fs_hlenp) == -1) {
812                 errno_msg("Can't get filesystem handle");
813                 return 1;
814         }
815         if (Verbose) {
816                 hantoa(*fs_hanpp, *fs_hlenp, hans);
817                 err_msg("File system handle for %s: %s\n", fsname, hans);
818         }
819         return 0;
820 }
821
822
823 /*
824         Set the event disposition for this filesystem to include all valid
825         DMAPI events so that we receive all events for this filesystem.
826         Also set DM_EVENT_MOUNT disposition for the global handle.
827         It does not make sense to specify DM_EVENT_USER in the disposition
828         mask since a session is always unconditionally registered for these
829         events.
830
831         Returns non-zero on error.
832 */
833
834 static int
835 set_disposition(
836         dm_sessid_t      sid,
837         void            *fs_hanp,
838         size_t           fs_hlen)
839 {
840         dm_eventset_t   eventlist;
841
842         if (Verbose) {
843                 err_msg("Setting event disposition to send all "
844                         "events to this session\n");
845         }
846
847         /* DM_EVENT_MOUNT must be sent in a separate request using the global
848            handle.  If we ever support more than one filesystem at a time, this
849            request should be moved out of this routine to a place where it is
850            issued just once.
851         */
852
853         DMEV_ZERO(eventlist);
854         DMEV_SET(DM_EVENT_MOUNT, eventlist);
855
856         if (dm_set_disp(sid, DM_GLOBAL_HANP, DM_GLOBAL_HLEN, DM_NO_TOKEN,
857                         &eventlist, DM_EVENT_MAX) == -1) {
858                 errno_msg("Can't set event disposition for mount");
859                 return(1);
860         }
861
862         DMEV_ZERO(eventlist);
863
864         /* File system administration events. */
865
866         DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist);
867         DMEV_SET(DM_EVENT_UNMOUNT, eventlist);
868         DMEV_SET(DM_EVENT_NOSPACE, eventlist);
869
870         /* While DM_EVENT_DEBUT is optional, it appears that the spec always
871            lets it be specified in a dm_set_disp call; its just that the
872            event will never be seen on some platforms.
873         */
874
875         DMEV_SET(DM_EVENT_DEBUT, eventlist);
876
877
878         /* Namespace events. */
879
880         DMEV_SET(DM_EVENT_CREATE, eventlist);
881         DMEV_SET(DM_EVENT_POSTCREATE, eventlist);
882         DMEV_SET(DM_EVENT_REMOVE, eventlist);
883         DMEV_SET(DM_EVENT_POSTREMOVE, eventlist);
884         DMEV_SET(DM_EVENT_RENAME, eventlist);
885         DMEV_SET(DM_EVENT_POSTRENAME, eventlist);
886         DMEV_SET(DM_EVENT_LINK, eventlist);
887         DMEV_SET(DM_EVENT_POSTLINK, eventlist);
888         DMEV_SET(DM_EVENT_SYMLINK, eventlist);
889         DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist);
890
891         /* Managed region data events. */
892
893         DMEV_SET(DM_EVENT_READ, eventlist);
894         DMEV_SET(DM_EVENT_WRITE, eventlist);
895         DMEV_SET(DM_EVENT_TRUNCATE, eventlist);
896
897         /* Metadata events. */
898
899         DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist);
900 #if     ! defined ( __sgi ) && ! defined ( VERITAS_21 ) && !defined(linux)
901         DMEV_SET(DM_EVENT_CANCEL, eventlist);   /* not supported on SGI */
902 #endif
903 #if !defined( __sgi) && !defined(linux)
904         DMEV_SET(DM_EVENT_CLOSE, eventlist);    /* not supported on SGI */
905 #endif
906         DMEV_SET(DM_EVENT_DESTROY, eventlist);
907
908         /* Pseudo-events. */
909
910         /* DM_EVENT_USER - always enabled - causes EINVAL if specified */
911
912         if (dm_set_disp(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
913                         &eventlist, DM_EVENT_MAX) == -1) {
914                 errno_msg("Can't set event disposition for filesystem");
915                 return(1);
916         }
917         return(0);
918 }
919
920
921 /*
922         Enable event generation on each valid filesystem-based DMAPI event
923         within the given file system.
924
925         Returns non-zero on errors.
926 */
927
928 static int
929 set_events(
930         dm_sessid_t      sid,
931         void            *fs_hanp,
932         size_t           fs_hlen)
933 {
934         dm_eventset_t   eventlist;
935
936         if (Verbose) {
937                 err_msg("Setting event list to enable all events "
938                         "for this file system\n");
939         }
940         DMEV_ZERO(eventlist);
941
942         /* File system administration events. */
943
944         /* DM_EVENT_MOUNT - always enabled on the global handle - causes
945            EINVAL if specified.
946         */
947         DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist);
948         DMEV_SET(DM_EVENT_UNMOUNT, eventlist);
949         DMEV_SET(DM_EVENT_NOSPACE, eventlist);
950         /* DM_EVENT_DEBUT - always enabled - causes EINVAL if specified. */
951
952         /* Namespace events. */
953
954         DMEV_SET(DM_EVENT_CREATE, eventlist);
955         DMEV_SET(DM_EVENT_POSTCREATE, eventlist);
956         DMEV_SET(DM_EVENT_REMOVE, eventlist);
957         DMEV_SET(DM_EVENT_POSTREMOVE, eventlist);
958         DMEV_SET(DM_EVENT_RENAME, eventlist);
959         DMEV_SET(DM_EVENT_POSTRENAME, eventlist);
960         DMEV_SET(DM_EVENT_LINK, eventlist);
961         DMEV_SET(DM_EVENT_POSTLINK, eventlist);
962         DMEV_SET(DM_EVENT_SYMLINK, eventlist);
963         DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist);
964
965          /* Managed region data events.  These are not settable by
966             dm_set_eventlist on a filesystem basis.   They are meant
967             to be set using dm_set_region on regular files only.
968             However, in the SGI implementation, they are filesystem-settable.
969             Since this is useful for testing purposes, do it.
970         */
971
972         /* DM_EVENT_READ */
973         /* DM_EVENT_WRITE */
974         /* DM_EVENT_TRUNCATE */
975
976         /* Metadata events. */
977
978         DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist);
979 #if     ! defined ( __sgi ) && ! defined ( VERITAS_21 ) && ! defined(linux)
980         DMEV_SET(DM_EVENT_CANCEL, eventlist);   /* not supported on SGI */
981 #endif
982 #if !defined( __sgi) && !defined(linux)
983         DMEV_SET(DM_EVENT_CLOSE, eventlist);    /* not supported on SGI */
984 #endif
985         DMEV_SET(DM_EVENT_DESTROY, eventlist);
986
987         /* Pseudo-events. */
988
989         /* DM_EVENT_USER - always enabled - causes EINVAL if specified */
990
991         if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
992                         &eventlist, DM_EVENT_MAX) == -1) {
993                 errno_msg("Can't set event list");
994                 return(1);
995         }
996         return(0);
997 }
998
999
1000 /*
1001         Disable monitoring for all events in the DMAPI for the given
1002         file system.  This is done before exiting so that future
1003         operations won't hang waiting for their events to be handled.
1004
1005         Returns non-zero on errors.
1006 */
1007
1008 static int
1009 clear_events(
1010         dm_sessid_t      sid,
1011         void            *fs_hanp,
1012         size_t           fs_hlen)
1013 {
1014         dm_eventset_t   eventlist;
1015
1016         if (Verbose) {
1017                 err_msg("Clearing event list to disable all events "
1018                         "for this filesystem\n");
1019         }
1020         DMEV_ZERO(eventlist);
1021
1022         if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
1023                         &eventlist, DM_EVENT_MAX) == -1) {
1024                 errno_msg("Can't clear event list");
1025                 return(1);
1026         }
1027         return(0);
1028 }
1029
1030
1031 /*
1032  * Respond to any events which haven't been handled yet.
1033  * dm_getall_tokens provides a list of tokens for the outstanding events.
1034  * dm_find_eventmsg uses the token to lookup the corresponding message.
1035  * The message is passed to handle_message() for normal response processing.
1036  */
1037 int
1038 finish_responding(
1039                   dm_sessid_t   sid)
1040 {
1041   int           error = 0;
1042   u_int         nbytes, ntokens = 0, ret_ntokens, i;
1043   dm_token_t    *tokenbuf = NULL;
1044   size_t        buflen, ret_buflen;
1045   char          *msgbuf = NULL;
1046   dm_eventmsg_t *msg;
1047
1048   if (Verbose)
1049     err_msg("Responding to any outstanding delivered event messages\n");
1050
1051   /*
1052    * Initial sizes for the token and message buffers
1053    */
1054   ret_buflen = 16 * (sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t)
1055                      + HANDLE_LEN);
1056   ret_ntokens = 16;
1057
1058   /*
1059    * The E2BIG dance...
1060    * Take a guess at how large to make the buffer, starting with ret_ntokens.
1061    * If the routine returns E2BIG, use the returned size and try again.
1062    * If we're already using the returned size, double it and try again.
1063    */
1064   do {
1065     ntokens = (ntokens != ret_ntokens) ? ret_ntokens : ntokens*2;
1066     nbytes = ntokens * (sizeof(dm_token_t) + sizeof(dm_vardata_t));
1067     tokenbuf = malloc(nbytes);
1068     if (tokenbuf == NULL) {
1069       err_msg("Can't malloc %d bytes for tokenbuf\n", nbytes);
1070       error = 1;
1071       goto out;
1072     }
1073     error = dm_getall_tokens(sid, ntokens, tokenbuf, &ret_ntokens);
1074   } while (error && errno == E2BIG);
1075
1076   if (error) {
1077     errno_msg("Can't get all outstanding tokens");
1078     goto out;
1079   }
1080
1081   for (i = 0; i < ret_ntokens; i++) {
1082     if (Verbose)
1083       err_msg("Responding to outstanding event for token %d\n",(int)*tokenbuf);
1084
1085     /*
1086      * The E2BIG dance reprise...
1087      */
1088     do {
1089       buflen = (buflen != ret_buflen) ? ret_buflen : buflen * 2;
1090       msgbuf = malloc(buflen);
1091       if (msgbuf == NULL) {
1092         err_msg("Can't malloc %d bytes for msgbuf\n", buflen);
1093         error = 1;
1094         goto out;
1095       }
1096       error = dm_find_eventmsg(sid, *tokenbuf, buflen, msgbuf, &ret_buflen);
1097     } while (error && errno == E2BIG);
1098     if (error) {
1099       errno_msg("Can't find the event message for token %d", (int)*tokenbuf);
1100       goto out;
1101     }
1102
1103     msg = (dm_eventmsg_t *) msgbuf;
1104     while (msg != NULL) {
1105       error = handle_message(sid, msg);
1106       if (error)
1107         goto out;
1108       msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *);
1109     }
1110
1111     tokenbuf++;
1112   }
1113
1114  out:
1115   if (tokenbuf)
1116     free(tokenbuf);
1117   if (msgbuf)
1118     free(msgbuf);
1119   return error;
1120 }
1121
1122
1123 /*
1124  * Establish an exit handler since we run in an infinite loop
1125  */
1126 int
1127 establish_handler(void)
1128 {
1129   struct sigaction      act;
1130
1131   /*
1132    * Set up signals so that we can wait for spawned children
1133    */
1134   act.sa_handler = exit_handler;
1135   act.sa_flags   = 0;
1136   sigemptyset(&act.sa_mask);
1137
1138   (void)sigaction(SIGHUP, &act, NULL);
1139   (void)sigaction(SIGINT, &act, NULL);
1140   (void)sigaction(SIGQUIT, &act, NULL);
1141   (void)sigaction(SIGTERM, &act, NULL);
1142   (void)sigaction(SIGUSR1, &act, NULL);
1143   (void)sigaction(SIGUSR1, &act, NULL);
1144   (void)sigaction(SIGUSR2, &act, NULL);
1145
1146   return(0);
1147 }
1148
1149
1150 /*
1151  * Exit gracefully
1152  *
1153  * Stop events from being generated for the given file system
1154  * Respond to any events that were delivered but unanswered
1155  *  (the event loop may have been in the middle of taking care of the event)
1156  * Try getting any undelivered events but don't block if none are there
1157  *  (the file system may have generated an event after we killed dm_get_events)
1158  * Shutdown the session using the global "sid" variable.
1159  */
1160 void
1161 exit_handler(int x)
1162 {
1163   int           error;
1164   void          *fs_hanp;
1165   size_t        fs_hlen;
1166
1167   if (Verbose)
1168     printf("\n"),
1169     err_msg("Exiting...\n");
1170
1171   error = get_fs_handle(fsname, &fs_hanp, &fs_hlen);
1172
1173   if (!error) {
1174     error = clear_events(sid, fs_hanp, fs_hlen);
1175     if (error)
1176       /* just keep going */ ;
1177   }
1178
1179   error = finish_responding(sid);
1180   if (error)
1181     /* just keep going */ ;
1182
1183   err_msg("Processing any undelivered event messages\n");
1184   event_loop(sid, 0 /*waitflag*/);
1185
1186   err_msg("Shutting down the session\n");
1187   if (sid != 0) {
1188     error = dm_destroy_session(sid);
1189     if (error == -1) {
1190       errno_msg("Can't shut down session - use 'mrmean -kv' to clean up!");
1191     }
1192   }
1193
1194   exit(0);
1195 }