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