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