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