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