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