]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/amd/amd/autil.c
This commit was generated by cvs2svn to compensate for changes in r168305,
[FreeBSD/FreeBSD.git] / contrib / amd / amd / autil.c
1 /*
2  * Copyright (c) 1997-2004 Erez Zadok
3  * Copyright (c) 1990 Jan-Simon Pendry
4  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry at Imperial College, London.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgment:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *      %W% (Berkeley) %G%
40  *
41  * $Id: autil.c,v 1.4.2.6 2004/01/06 03:15:16 ezk Exp $
42  *
43  */
44
45 /*
46  * utilities specified to amd, taken out of the older amd/util.c.
47  */
48
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <amd.h>
54
55 int NumChild = 0;               /* number of children of primary amd */
56 static char invalid_keys[] = "\"'!;@ \t\n";
57
58 #ifdef HAVE_TRANSPORT_TYPE_TLI
59 # define PARENT_USLEEP_TIME     100000 /* 0.1 seconds */
60 #endif /* HAVE_TRANSPORT_TYPE_TLI */
61
62
63 char *
64 strealloc(char *p, char *s)
65 {
66   int len = strlen(s) + 1;
67
68   p = (char *) xrealloc((voidp) p, len);
69
70   strcpy(p, s);
71 #ifdef DEBUG_MEM
72   malloc_verify();
73 #endif /* DEBUG_MEM */
74   return p;
75 }
76
77
78 char **
79 strsplit(char *s, int ch, int qc)
80 {
81   char **ivec;
82   int ic = 0;
83   int done = 0;
84
85   ivec = (char **) xmalloc((ic + 1) * sizeof(char *));
86
87   while (!done) {
88     char *v;
89
90     /*
91      * skip to split char
92      */
93     while (*s && (ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch))
94       *s++ = '\0';
95
96     /*
97      * End of string?
98      */
99     if (!*s)
100       break;
101
102     /*
103      * remember start of string
104      */
105     v = s;
106
107     /*
108      * skip to split char
109      */
110     while (*s && !(ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch)) {
111       if (*s++ == qc) {
112         /*
113          * Skip past string.
114          */
115         s++;
116         while (*s && *s != qc)
117           s++;
118         if (*s == qc)
119           s++;
120       }
121     }
122
123     if (!*s)
124       done = 1;
125     *s++ = '\0';
126
127     /*
128      * save string in new ivec slot
129      */
130     ivec[ic++] = v;
131     ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *));
132 #ifdef DEBUG
133     amuDebug(D_STR)
134       plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
135 #endif /* DEBUG */
136   }
137
138 #ifdef DEBUG
139   amuDebug(D_STR)
140     plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
141 #endif /* DEBUG */
142
143   ivec[ic] = 0;
144
145   return ivec;
146 }
147
148
149 /*
150  * Strip off the trailing part of a domain
151  * to produce a short-form domain relative
152  * to the local host domain.
153  * Note that this has no effect if the domain
154  * names do not have the same number of
155  * components.  If that restriction proves
156  * to be a problem then the loop needs recoding
157  * to skip from right to left and do partial
158  * matches along the way -- ie more expensive.
159  */
160 static void
161 domain_strip(char *otherdom, char *localdom)
162 {
163   char *p1, *p2;
164
165   if ((p1 = strchr(otherdom, '.')) &&
166       (p2 = strchr(localdom, '.')) &&
167       STREQ(p1 + 1, p2 + 1))
168     *p1 = '\0';
169 }
170
171
172 /*
173  * Normalize a host name
174  */
175 void
176 host_normalize(char **chp)
177 {
178   /*
179    * Normalize hosts is used to resolve host name aliases
180    * and replace them with the standard-form name.
181    * Invoked with "-n" command line option.
182    */
183   if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) {
184     struct hostent *hp;
185     clock_valid = 0;
186     hp = gethostbyname(*chp);
187     if (hp && hp->h_addrtype == AF_INET) {
188 #ifdef DEBUG
189       dlog("Hostname %s normalized to %s", *chp, hp->h_name);
190 #endif /* DEBUG */
191       *chp = strealloc(*chp, (char *) hp->h_name);
192     }
193   }
194   domain_strip(*chp, hostd);
195 }
196
197
198
199 /*
200  * Keys are not allowed to contain " ' ! or ; to avoid
201  * problems with macro expansions.
202  */
203 int
204 valid_key(char *key)
205 {
206   while (*key)
207     if (strchr(invalid_keys, *key++))
208       return FALSE;
209   return TRUE;
210 }
211
212
213 void
214 forcibly_timeout_mp(am_node *mp)
215 {
216   mntfs *mf = mp->am_mnt;
217   /*
218    * Arrange to timeout this node
219    */
220   if (mf && ((mp->am_flags & AMF_ROOT) ||
221              (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) {
222     if (mf->mf_flags & MFF_UNMOUNTING)
223       plog(XLOG_WARNING, "node %s is currently being unmounted, ignoring timeout request", mp->am_path);
224     else
225       plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
226   } else {
227     plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
228     mp->am_flags &= ~AMF_NOTIMEOUT;
229     mp->am_ttl = clocktime();
230     reschedule_timeout_mp();
231   }
232 }
233
234
235 void
236 mf_mounted(mntfs *mf)
237 {
238   int quoted;
239   int wasmounted = mf->mf_flags & MFF_MOUNTED;
240
241   if (!wasmounted) {
242     /*
243      * If this is a freshly mounted
244      * filesystem then update the
245      * mntfs structure...
246      */
247     mf->mf_flags |= MFF_MOUNTED;
248     mf->mf_error = 0;
249
250     /*
251      * Do mounted callback
252      */
253     if (mf->mf_ops->mounted) {
254       (*mf->mf_ops->mounted) (mf);
255     }
256     mf->mf_fo = 0;
257   }
258
259   /*
260    * Log message
261    */
262   quoted = strchr(mf->mf_info, ' ') != 0;
263   plog(XLOG_INFO, "%s%s%s %s fstype %s on %s",
264        quoted ? "\"" : "",
265        mf->mf_info,
266        quoted ? "\"" : "",
267        wasmounted ? "referenced" : "mounted",
268        mf->mf_ops->fs_type, mf->mf_mount);
269 }
270
271
272 void
273 am_mounted(am_node *mp)
274 {
275   mntfs *mf = mp->am_mnt;
276
277   mf_mounted(mf);
278
279   /*
280    * Patch up path for direct mounts
281    */
282   if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &amfs_direct_ops)
283     mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
284
285   /*
286    * Check whether this mount should be cached permanently
287    */
288   if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
289     mntent_t mnt;
290     mnt.mnt_opts = mf->mf_mopts;
291
292     if (mf->mf_mopts && hasmntopt(&mnt, "unmount"))
293       mp->am_flags &= ~AMF_NOTIMEOUT;
294     else
295       mp->am_flags |= AMF_NOTIMEOUT;
296   } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
297     mp->am_flags |= AMF_NOTIMEOUT;
298   } else {
299     mntent_t mnt;
300     if (mf->mf_mopts) {
301       mnt.mnt_opts = mf->mf_mopts;
302       if (hasmntopt(&mnt, "nounmount"))
303         mp->am_flags |= AMF_NOTIMEOUT;
304       if (hasmntopt(&mnt, "unmount"))
305         mp->am_flags &= ~AMF_NOTIMEOUT;
306       if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
307         mp->am_timeo = gopt.am_timeo;
308     }
309   }
310
311   /*
312    * If this node is a symlink then
313    * compute the length of the returned string.
314    */
315   if (mp->am_fattr.na_type == NFLNK)
316     mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
317
318   /*
319    * Record mount time
320    */
321   mp->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime = clocktime();
322   new_ttl(mp);
323
324   /*
325    * Update mtime of parent node
326    */
327   if (mp->am_parent && mp->am_parent->am_mnt)
328     mp->am_parent->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime;
329
330   /*
331    * Now, if we can, do a reply to our NFS client here
332    * to speed things up.
333    */
334   quick_reply(mp, 0);
335
336   /*
337    * Update stats
338    */
339   amd_stats.d_mok++;
340 }
341
342
343 int
344 mount_node(am_node *mp)
345 {
346   mntfs *mf = mp->am_mnt;
347   int error = 0;
348
349   mf->mf_flags |= MFF_MOUNTING;
350   error = (*mf->mf_ops->mount_fs) (mp);
351
352   mf = mp->am_mnt;
353   if (error >= 0)
354     mf->mf_flags &= ~MFF_MOUNTING;
355   if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) {
356     /* ...but see ifs_mount */
357     am_mounted(mp);
358   }
359
360   return error;
361 }
362
363
364 void
365 am_unmounted(am_node *mp)
366 {
367   mntfs *mf = mp->am_mnt;
368
369   if (!foreground)              /* firewall - should never happen */
370     return;
371
372   /*
373    * Do unmounted callback
374    */
375   if (mf->mf_ops->umounted)
376     (*mf->mf_ops->umounted) (mp);
377
378   /*
379    * Update mtime of parent node
380    */
381   if (mp->am_parent && mp->am_parent->am_mnt)
382     mp->am_parent->am_fattr.na_mtime.nt_seconds = clocktime();
383
384   free_map(mp);
385 }
386
387
388 /*
389  * Fork the automounter
390  *
391  * TODO: Need a better strategy for handling errors
392  */
393 static int
394 dofork(void)
395 {
396   int pid;
397
398 top:
399   pid = fork();
400
401   if (pid < 0) {                /* fork error, retry in 1 second */
402     sleep(1);
403     goto top;
404   }
405   if (pid == 0) {               /* child process (foreground==false) */
406     am_set_mypid();
407     foreground = 0;
408   } else {                      /* parent process, has one more child */
409     NumChild++;
410   }
411
412   return pid;
413 }
414
415
416 int
417 background(void)
418 {
419   int pid = dofork();
420
421   if (pid == 0) {
422 #ifdef DEBUG
423     dlog("backgrounded");
424 #endif /* DEBUG */
425     foreground = 0;
426   }
427   return pid;
428 }