Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_play / sfs_c_mnt.c
1 #ifndef lint
2 static char sfs_c_mntSid[] = "@(#)sfs_c_mnt.c   2.1     97/10/23";
3 #endif
4
5 /*
6  *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
7  *      All rights reserved.
8  *              Standard Performance Evaluation Corporation (SPEC)
9  *              6585 Merchant Place, Suite 100
10  *              Warrenton, VA 20187
11  *
12  *      This product contains benchmarks acquired from several sources who
13  *      understand and agree with SPEC's goal of creating fair and objective
14  *      benchmarks to measure computer performance.
15  *
16  *      This copyright notice is placed here only to protect SPEC in the
17  *      event the source is misused in any manner that is contrary to the
18  *      spirit, the goals and the intent of SPEC.
19  *
20  *      The source code is provided to the user or company under the license
21  *      agreement for the SPEC Benchmark Suite for this product.
22  */
23
24 /*****************************************************************
25  *                                                               *
26  *      Copyright 1991,1992  Legato Systems, Inc.                *
27  *      Copyright 1991,1992  Auspex Systems, Inc.                *
28  *      Copyright 1991,1992  Data General Corporation            *
29  *      Copyright 1991,1992  Digital Equipment Corporation       *
30  *      Copyright 1991,1992  Interphase Corporation              *
31  *      Copyright 1991,1992  Sun Microsystems, Inc.              *
32  *                                                               *
33  *****************************************************************/
34
35 /*
36  * ---------------------- sfs_c_mnt.c ---------------------
37  *
38  *      The sfs child.  Routines to handle mount points.
39  *
40  *.Exported_Routines
41  *      void init_mount_point(int, char *, CLIENT *)
42  *
43  *.Local_Routines
44  *      int pseudo_mount(char *, int, char *, CLIENT *)
45  *
46  *.Revision_History
47  *      2-Jul-92        Teelucksingh    Added code for OSF/1
48  *                                      use of getmntinfo().
49  *      16-Dec-91       Wittle          Created.
50  */
51
52
53 /*
54  * -------------------------  Include Files  -------------------------
55  */
56
57 /*
58  * ANSI C headers
59  */
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <errno.h>
64 #include <time.h>
65 #include <signal.h>
66  
67 #include <sys/types.h>
68 #include <sys/stat.h> 
69
70 #include <fcntl.h>
71
72 #include <unistd.h>
73
74 #include "sfs_c_def.h"
75
76 struct hostent   *Server_hostent;
77
78 /*
79  * -------------------------  Constants  -------------------------
80  */
81
82 /*
83  * Number of times a load generating process will retry amount.
84  * Each load generating process also picks a client shifted
85  * mount start time, and executes a backoff on retry time on
86  * failure.
87  */
88 #define NUMBER_MOUNT_RETRIES    10
89
90 /*
91  * -------------------------  External Definitions  -------------------------
92  */
93
94 /* forward definitions for local routines */
95 CLIENT * lad_getmnt_hand(char *);
96 static int pseudo_mount(char *, int, char *, CLIENT *);
97
98 /*
99  * Mounts are retried when an RPC timeout occurs, in the mainline
100  * code. They are not retried by the RPC clnt_call routine, as the
101  * timeout values are set now.
102  */
103 static struct timeval Mount_timer = {  10,  0 };
104
105
106 /*
107  * -------------------------  Mount Point Routines  -------------------------
108  */
109
110
111 /*
112  * mount the testdir 'dirnum' under the parent directory 'parentdir'.
113  */
114 void
115 init_mount_point(
116     int         dirnum,
117     char *      parentdir,
118     CLIENT *    mount_client_ptr)
119 {
120     char        pnt_dir[SFS_MAXPATHLEN];      /* test dir component name */
121     char        testdirname[SFS_MAXPATHLEN];  /* test dir component name */
122     char        export_fsname[SFS_MAXPATHLEN]; /* "host:path" exported fs */
123     sfs_fh_type file_handle;
124     char        *fh_ptr;
125     char        *cp;
126     int         ret;
127     sfs_fh_data *fh_datap, *Ex_fh_datap;
128
129     fh_datap= calloc(1,sizeof(sfs_fh_data));
130     (void) memset((char *)fh_datap, 0, sizeof(sfs_fh_data));
131     (void) memset((char *)&file_handle, 0, sizeof(file_handle));
132     file_handle.fh_data = fh_datap;
133     file_handle.dir = &Export_dir;
134
135     Ex_fh_datap = (sfs_fh_data *) calloc(1,sizeof(sfs_fh_data));
136     Export_dir.fh_data = Ex_fh_datap;
137
138     (void) strcpy(pnt_dir, parentdir);
139
140     cp = strchr(pnt_dir, ':');
141     if (cp == NULL) {
142         (void) fprintf(stderr, "%s: malformed fsname %s\n",
143                         sfs_Myname, parentdir);
144         if (!Validate)
145             (void) generic_kill(0, SIGINT);
146         exit(86);
147     }
148
149     *cp++ = '\0';
150
151     /*
152      * Now we have the parent directory in the form:
153      *          host:host_path
154      *
155      * First we get the file handle for parent directory
156      *
157      * Verify that the server is running the correct version of
158      * the NFS protocol specification and then proceed to get
159      * the exported fh from the server.
160      */
161     (void) strcpy(testdirname, pnt_dir);
162     (void) strcat(testdirname, ":");
163     (void) strcat(testdirname, cp);
164     (void) strcpy(export_fsname, testdirname);
165
166     if (nfs_version == NFS_VERSION) {
167         (void) memset((char *) &Export_dir.fh2, '\0', sizeof (Export_dir.fh2));
168         fh_ptr = (char *)&Export_dir.fh2;
169     } else if (nfs_version == NFS_V3) {
170         (void) memset((char *) &Export_dir.fh3, '\0', sizeof (Export_dir.fh3));
171         fh_ptr = (char *)&Export_dir.fh3;
172     }
173
174     ret = pseudo_mount(export_fsname, nfs_version,
175                                         fh_ptr, mount_client_ptr);
176     if (ret < 0) {
177         if (ret == -2)  {
178             (void) fprintf(stderr,
179                 "%s: NFS Protocol Version %lu verification failed.\n",
180                 sfs_Myname, (uint32_t)nfs_version);
181         }
182         else  {
183             (void) fprintf(stderr, "%s: can't pseudo mount %s\n",
184                         sfs_Myname, export_fsname);
185         }
186         if (!Validate)
187             (void) generic_kill(0, SIGINT);
188         exit(87);
189     }
190
191     /*
192      * Setup initial state of export directory
193      */
194     Export_dir.state = Exists;
195     (void) strcpy(Export_dir.file_name, testdirname);
196     Export_dir.dir = &Export_dir;
197
198 #ifndef RFS
199     /*
200      * Check for and create the client directory. Stat it first, if not
201      * there then mkdir, if that fails with EEXIST we lost the race but
202      * that's OK.
203      */
204     if (Validate) {
205         (void) sprintf(testdirname, "%s", "validatedir");
206     } else {
207         (void) sprintf(testdirname, "CL%d", Client_num);
208     }
209
210     if ((ret = lad_lookup(&file_handle, testdirname)) == -1) {
211         if (!Validate)
212             (void) generic_kill(0, SIGINT);
213         exit(88);
214     }
215
216     if (ret == 1) {
217         /*
218          * Directory doesn't exist so create it
219          * if it already exists thats OK
220          */
221         if ((ret = lad_mkdir(&file_handle, testdirname)) == -1) {
222             if (!Validate)
223                 (void) generic_kill(0, SIGINT);
224             exit(89);
225         }
226         /*
227          * If someone else created this out from underneath us simply
228          * lookup the result and continue on.
229          */
230         if (ret != 0 && (ret = lad_lookup(&file_handle, testdirname)) == -1) {
231             if (!Validate)
232                 (void) generic_kill(0, SIGINT);
233             exit(90);
234         }
235     }
236
237     /* testdirname now exists, verify it is a directory and writeable */
238     if (!fh_isdir(&file_handle) ||
239                 (check_fh_access(&file_handle) == -1)) {
240         (void) fprintf(stderr,
241                 "%s: %s is either not a directory or not accessible\n",
242                         sfs_Myname, testdirname);
243         if (!Validate)
244             (void) generic_kill(0, SIGINT);
245         exit(91);
246     }
247
248     /*
249      * logically chdir into CL directory
250      */
251    /*  Export_dir = file_handle; Implied bcopy here */
252     (void) memmove(&Export_dir,&file_handle,sizeof(sfs_fh_type));
253     Export_dir.fh_data = Ex_fh_datap;
254     (void ) memmove(Export_dir.fh_data, file_handle.fh_data, 
255                         sizeof(sfs_fh_data));
256     (void) memset((char *)&file_handle, 0, sizeof(file_handle));
257     (void) memset((char *)fh_datap, 0, sizeof(sfs_fh_data));
258     file_handle.fh_data = fh_datap;
259     file_handle.dir = &Export_dir;
260
261     /*
262      * Validation only occurs one directory deep so we can exit early
263      */
264     if (Validate)
265         return;
266
267     (void) sprintf(testdirname, "testdir%d", dirnum);
268
269     if ((ret = lad_lookup(&file_handle, testdirname)) == -1) {
270         (void) generic_kill(0, SIGINT);
271         exit(92);
272     }
273
274     if (ret == 1) {
275         /*
276          * Directory doesn't exist so create it
277          */
278         if (lad_mkdir(&file_handle, testdirname) != 0) {
279             (void) fprintf(stderr, "%s: Unable to create %s\n",
280                         sfs_Myname, testdirname);
281             (void) generic_kill(0, SIGINT);
282             exit(93);
283         }
284     }
285
286     /* testdirname now exists, verify it is a directory and writeable */
287     if (!fh_isdir(&file_handle) ||
288                 (check_fh_access(&file_handle) == -1)) {
289         (void) fprintf(stderr,
290                 "%s: %s is either not a directory or not accessible\n",
291                         sfs_Myname, testdirname);
292         (void) generic_kill(0, SIGINT);
293         exit(94);
294     }
295
296     /*
297      * logically chdir into testdir directory
298      */
299     /* Export_dir = file_handle;*/
300     (void) memmove(&Export_dir, &file_handle, sizeof(struct sfs_fh_type));
301     Export_dir.fh_data = Ex_fh_datap; /* Put pointer back */
302     (void) memmove(Export_dir.fh_data, file_handle.fh_data, sizeof
303                         (sfs_fh_data));
304 #endif
305 } /* init_mount_point */
306
307 /*
308  * Get the filehandle for 'mount_fsname', and return it
309  * Returns NULL for error ... not mounted || no NFS client.
310  *
311  * Children should only call this routine 1 time.
312  */
313 CLIENT *
314 lad_getmnt_hand(
315     char *              mount_point)
316 {
317     char                mnt_pnt[SFS_MAXPATHLEN];    /* working buffer */
318     char                host[SFS_MAXPATHLEN];     /* host with exported fs */
319     static struct hostent       hp;
320     struct hostent      *thp;
321     CLIENT              *mount_client_ptr;      /* Mount client handle */
322     char                *cp;
323     int                 rpc_result;             /* rpc call result */
324     uint32_t            mount_vers = 0;
325
326     /*
327      * If the mount point is of the form host:path just use the explicit
328      * name instead of grovelling through the mount table.
329      */
330     (void) strcpy(mnt_pnt, mount_point);
331     cp = strchr(mnt_pnt, ':');
332     if (cp == NULL) {
333         (void) fprintf(stderr, "%s: malformed fsname %s\n",
334                         sfs_Myname, mount_point);
335         return(NULL);
336     }
337
338     *cp++ = '\0';
339     (void) strcpy(host, mnt_pnt);
340
341     /* Verify NFS Version */
342     rpc_result = callrpc(host,
343                         (uint32_t) NFS_PROGRAM,
344                         (uint32_t) nfs_version,
345                         (uint32_t) NFSPROC_NULL, (xdrproc_t) xdr_void,
346                         (char *) NULL, (xdrproc_t) xdr_void, (char *) NULL);
347     if (rpc_result != 0) {
348          clnt_perrno((enum clnt_stat)rpc_result);
349          (void) fprintf(stderr,
350 "\nUnable to contact NFS server %s.\n", host);
351          (void) fprintf(stderr,
352 "Verify NFS server daemon supporting version %u is running and\n",
353                 (uint32_t)nfs_version);
354          (void) fprintf(stderr, "registered with the portmapper.\n");
355         return(NULL);
356     }
357
358     /* Get host's address */
359     if ((thp = gethostbyname(host)) == NULL) {
360         /* Failure may be due to yellow pages, try again */
361         if ((thp = gethostbyname(host)) == NULL) {
362             (void) fprintf(stderr, "%s: %s not in hosts database\n",
363                             sfs_Myname, host);
364             return(NULL);
365         }
366     }
367
368     hp = *thp;
369     Server_hostent = &hp;
370
371     if (nfs_version == NFS_VERSION)
372         mount_vers = MOUNTVERS;
373     if (nfs_version == NFS_V3)
374         mount_vers = MOUNTVER3;
375
376     mount_client_ptr = lad_clnt_create(0, Server_hostent,
377                                         (uint32_t) MOUNTPROG,
378                                         mount_vers,
379                                         RPC_ANYSOCK, &Mount_timer);
380                 
381
382     if (mount_client_ptr == ((CLIENT*) NULL)) {
383         (void) fprintf(stderr,
384                         "%s: portmap/mountd %s server not responding",
385                         sfs_Myname, mount_point);
386         return(NULL);
387     }
388
389     mount_client_ptr->cl_auth = authunix_create_default();
390     return (mount_client_ptr);
391
392 } /* lad_getmnt_hand */
393
394
395 /*
396  * Get the filehandle for 'mount_fsname', and return it in 'fh_ptr'.
397  * Returns 0 for OK, -1 for error ... not mounted || no NFS client.
398  *
399  * Children should only call this routine 1 time.
400  */
401 static int
402 pseudo_mount(
403     char *              mount_fsname,
404     int                 version,
405     char *              fh_ptr,
406     CLIENT *            mount_client_ptr)
407 {
408     char *              host_ptr;               /* host with exported fs */
409     char *              path_ptr;               /* ptr to path for RPC */
410
411     struct fhstatus     fhs;                    /* status of mountd call */
412     nfs_fh3 *           fh_ptr3;
413     mountres3           mntres3;                /* status of mountd call */
414     char *              cp;
415     enum clnt_stat      rpc_stat;
416     int                 tries = 0;              /* Number of retries */
417                                 /* Space by 200ms intervals. */
418     int                 pacesleep = Child_num * 200;
419
420     /* Parse the fsname for host and path strings */
421     cp = strchr(mount_fsname, ':');
422
423     if (cp == NULL) {
424         (void) fprintf(stderr, "%s: malformed fsname %s\n",
425                         sfs_Myname, mount_fsname);
426         return(-1);
427     }
428
429     *cp++ = '\0';
430     host_ptr = mount_fsname;
431     path_ptr = cp;
432
433     /* Check host's address */
434     if (gethostbyname(host_ptr) == NULL) {
435         /* Failure may be due to yellow pages, try again */
436         if (gethostbyname(host_ptr) == NULL) {
437             (void) fprintf(stderr, "%s: %s not in hosts database\n",
438                             sfs_Myname, host_ptr);
439             return(-1);
440         }
441     }
442
443     if (DEBUG_CHILD_GENERAL) {
444         (void) fprintf(stderr, "%s: mount clnt_call\n", sfs_Myname);
445     }
446
447     /* get fhandle of remote path from host's mountd */
448
449 retry_mount:
450     /*
451      * Many children on many clients hammer a server with
452      * mounts. Crude fix is to pace them. Some run rule interpretations
453      * are to have *many* children on each client. This can
454      * cause problems.
455      */
456     (void) msec_sleep(pacesleep);
457
458     if (version == NFS_VERSION) {
459         (void) memset((char *) &fhs, '\0', sizeof (fhs));
460         rpc_stat = clnt_call(mount_client_ptr, MOUNTPROC_MNT, xdr_path,
461                         (char *) &path_ptr,xdr_fhstatus,(char *) &fhs,
462                         Mount_timer);
463     } else if (version == NFS_V3) {
464         (void) memset((char *) &mntres3, '\0', sizeof (mntres3));
465         rpc_stat = clnt_call(mount_client_ptr, MOUNTPROC_MNT, xdr_dirpath,
466                         (char *) &path_ptr, xdr_mntres3, (char *) &mntres3,
467                         Mount_timer);
468     } else
469         rpc_stat = RPC_PROGVERSMISMATCH;
470
471     errno = 0;
472     if (rpc_stat != RPC_SUCCESS) {
473
474         switch (rpc_stat) {
475
476             case RPC_TIMEDOUT:
477                 errno = ETIMEDOUT;
478                 (void) fprintf(stderr,
479                     "%s: mounting %s:%s server not responding: %s (%d)\n",
480                             sfs_Myname, host_ptr, path_ptr,
481                             strerror(errno), errno);
482                 if (tries++ < NUMBER_MOUNT_RETRIES) {
483                     /* Randomize the backoff on retry */
484                     pacesleep = pacesleep + (sfs_random() % 2000);
485                     goto retry_mount;
486                 }
487                 break;
488
489
490             case RPC_PMAPFAILURE:
491                 errno = ENETDOWN;       /* reasonable error */
492                 (void) fprintf(stderr,
493                             "%s: mounting %s portmap call failed: %s (%d)\n",
494                             sfs_Myname, host_ptr, strerror(errno), errno);
495                 break;
496
497             case RPC_PROGNOTREGISTERED:
498                 errno = ENETDOWN;       /* reasonable error */
499                 (void) fprintf(stderr,
500                             "%s: mounting %s nfsd not registered: %s (%d)\n",
501                             sfs_Myname, host_ptr, strerror(errno), errno);
502                 break;
503
504             case RPC_AUTHERROR:
505                 errno = EACCES;
506                 (void) fprintf(stderr,
507                         "%s: mounting %s authentication failed: %s (%d)\n",
508                         sfs_Myname, host_ptr, strerror(errno), errno);
509                 break;
510
511             default:
512                 errno = ENETDOWN;       /* reasonable error */
513                 (void) fprintf(stderr,
514                             "%s: mounting %s:%s failed: %s (%d)\n",
515                             sfs_Myname, host_ptr, path_ptr,
516                             strerror(errno), errno);
517                 break;
518         }
519
520         clnt_perror(mount_client_ptr, "");
521         return(-1);
522
523     } /* MOUNTPROC_MNT call failed */
524
525     if (version == NFS_VERSION) {
526         if (fhs.fhs_status != 0) {
527             if (fhs.fhs_status == EACCES) {
528                 (void) fprintf(stderr, "%s: mounting %s:%s - access denied\n",
529                            sfs_Myname, host_ptr, path_ptr);
530             } else {
531                 (void) fprintf(stderr,
532                             "%s: mounting %s:%s - bad fh status %d\n ",
533                             sfs_Myname, host_ptr, path_ptr, fhs.fhs_status);
534             }
535             return(-1);
536         } /* bad fhs status */
537
538         /*
539          * fill in the caller's file handle
540          */
541         (void) memmove(fh_ptr, (char *) &fhs.fhs_fh, NFS_FHSIZE);
542
543     } else if (version == NFS_V3) {
544
545         if (mntres3.fhs_status != MNT_OK) {
546             if (mntres3.fhs_status == MNT3ERR_ACCES) {
547                 (void) fprintf(stderr, "%s: mounting %s:%s - access denied\n",
548                            sfs_Myname, host_ptr, path_ptr);
549             } else {
550                 (void) fprintf(stderr,
551                             "%s: mounting %s:%s - bad fh status %d\n ",
552                     sfs_Myname, host_ptr, path_ptr, mntres3.fhs_status);
553             }
554             return(-1);
555         } /* bad fhs status */
556
557         /*
558          * fill in the caller's file handle
559          * space pointed by fhandle3_val is allocated through xdr_mntres3
560          */
561         fh_ptr3 = (nfs_fh3 *)fh_ptr;
562         fh_ptr3->fh3_length = mntres3.mntres3_u.mntinfo.fhandle.fhandle3_len;
563         (void) memmove((char *) fh_ptr3->fh3_u.data,
564                         (char *) mntres3.mntres3_u.mntinfo.fhandle.fhandle3_val,
565                         fh_ptr3->fh3_length);
566     }
567
568     return(0);
569
570 } /* pseudo_mount */
571
572
573 /* sfs_c_mnt.c */