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