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