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