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