1/*
2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1989 Jan-Simon Pendry
4 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1989 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. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *
36 * File: am-utils/fsinfo/wr_atab.c
37 *
38 */
39
40#ifdef HAVE_CONFIG_H
41# include <config.h>
42#endif /* HAVE_CONFIG_H */
43#include <am_defs.h>
44#include <fsi_data.h>
45#include <fsinfo.h>
46
47
48/*
49 * Write a sequence of automount mount map entries
50 */
51static int
52write_amount_info(FILE *af, automount *ap,  u_int sk)
53{
54  int errors = 0;
55
56  if (ap->a_mount) {
57    /*
58     * A pseudo-directory.
59     * This can also be a top-level directory, in which
60     * case the type:=auto is not wanted...
61     *
62     * type:=auto;fs:=${map};pref:=whatever/
63     */
64    automount *ap2;
65    if (strlen(ap->a_name) > sk) {
66      fprintf(af, "%s type:=auto;fs:=${map};pref:=%s/\n",
67	      ap->a_name + sk, ap->a_name + sk);
68    }
69    ITER(ap2, automount, ap->a_mount)
70      errors += write_amount_info(af, ap2, sk);
71  } else if (ap->a_hardwiredfs) {
72
73    /*
74     * A hardwired filesystem "hostname:path"
75     * rhost:=hostname;rfs:=path
76     */
77    char *key = ap->a_name + sk;
78    char *hostname = ap->a_hardwiredfs;
79    char *path = strrchr(hostname, (int) ':');
80
81    if (path == NULL) {
82      fprintf(stderr, "%s: %s not an NFS filesystem\n", ap->a_name, ap->a_hardwiredfs);
83      errors++;
84    } else {
85      *path = '\0';
86      path++;
87
88      /*
89       * Output the map key
90       */
91      fputs(key, af);
92      fprintf(af, " rhost:=%s", hostname);
93      fprintf(af, ";rfs:=%s", path);
94      if (ap->a_opts && !STREQ(ap->a_opts, "")) {
95	fprintf(af, ";%s", ap->a_opts);
96      }
97      fputc('\n', af);
98      path--;
99      *path = ':';
100    }
101  } else if (ap->a_mounted) {
102
103    /*
104     * A mounted partition
105     * type:=link [ link entries ] type:=nfs [ nfs entries ]
106     */
107    dict_data *dd;
108    dict_ent *de = ap->a_mounted;
109    int done_type_link = 0;
110    char *key = ap->a_name + sk;
111
112    /*
113     * Output the map key
114     */
115    fputs(key, af);
116
117    /*
118     * First output any Link locations that would not
119     * otherwise be correctly mounted.  These refer
120     * to filesystem which are not mounted in the same
121     * place which the automounter would use.
122     */
123    ITER(dd, dict_data, &de->de_q) {
124      fsi_mount *mp = (fsi_mount *) dd->dd_data;
125      /*
126       * If the mount point and the exported volname are the
127       * same then this filesystem will be recognized by
128       * the restart code - so we don't need to put out a
129       * special rule for it.
130       */
131      if (mp->m_dk->d_host->h_lochost) {
132	char amountpt[1024];
133	compute_automount_point(amountpt, sizeof(amountpt),
134				mp->m_dk->d_host, mp->m_exported->m_volname);
135	if (!STREQ(mp->m_dk->d_mountpt, amountpt)) {
136	  /*
137	   * ap->a_volname is the name of the aliased volume
138	   * mp->m_name is the mount point of the filesystem
139	   * mp->m_volname is the volume name of the filesystems
140	   */
141
142	  /*
143	   * Find length of key and volume names
144	   */
145	  int avlen = strlen(ap->a_volname);
146	  int mnlen = strlen(mp->m_volname);
147
148	  /*
149	   * Make sure a -type:=link is output once
150	   */
151	  if (!done_type_link) {
152	    done_type_link = 1;
153	    fputs(" -type:=link", af);
154	  }
155
156	  /*
157	   * Output a selector for the hostname,
158	   * the device from which to mount and
159	   * where to mount.  This will correspond
160	   * to the values output for the fstab.
161	   */
162	  if (mp->m_dk->d_host->h_lochost)
163	    fprintf(af, " host==%s", mp->m_dk->d_host->h_lochost);
164	  else
165	    fprintf(af, " hostd==%s", mp->m_dk->d_host->h_hostname);
166	  fprintf(af, ";fs:=%s", mp->m_name);
167
168	  /*
169	   * ... and a sublink if needed
170	   */
171	  if (mnlen < avlen) {
172	    char *sublink = ap->a_volname + mnlen + 1;
173	    fprintf(af, "/%s", sublink);
174	  }
175	  fputs(" ||", af);
176	}
177      }
178    }
179
180    /*
181     * Next do the NFS locations
182     */
183    if (done_type_link)
184      fputs(" -", af);
185
186    ITER(dd, dict_data, &de->de_q) {
187      fsi_mount *mp = (fsi_mount *) dd->dd_data;
188      int namelen = mp->m_name_len;
189      int exp_namelen = mp->m_exported->m_name_len;
190      int volnlen = strlen(ap->a_volname);
191      int mvolnlen = strlen(mp->m_volname);
192
193      fputc(' ', af);
194
195      /*
196       * Output any selectors
197       */
198      if (mp->m_sel)
199	fprintf(af, "%s;", mp->m_sel);
200
201      /*
202       * Print host and volname of exported filesystem
203       */
204      fprintf(af, "rhost:=%s",
205	      mp->m_dk->d_host->h_lochost ?
206	      mp->m_dk->d_host->h_lochost :
207	      mp->m_dk->d_host->h_hostname);
208      fprintf(af, ";rfs:=%s", mp->m_exported->m_volname);
209      if (ap->a_opts && !STREQ(ap->a_opts, "")) {
210	fprintf(af, ";%s", ap->a_opts);
211      }
212
213      /*
214       * Now determine whether a sublink is required.
215       */
216      if (exp_namelen < namelen || mvolnlen < volnlen) {
217	char sublink[1024];
218	sublink[0] = '\0';
219	if (exp_namelen < namelen) {
220	  xstrlcat(sublink, mp->m_name + exp_namelen + 1, sizeof(sublink));
221	  if (mvolnlen < volnlen)
222	    xstrlcat(sublink, "/", sizeof(sublink));
223	}
224	if (mvolnlen < volnlen)
225	  xstrlcat(sublink, ap->a_volname + mvolnlen + 1, sizeof(sublink));
226
227	fprintf(af, ";sublink:=%s", sublink);
228      }
229    }
230    fputc('\n', af);
231  } else if (ap->a_symlink) {
232
233    /*
234     * A specific link.
235     *
236     * type:=link;fs:=whatever
237     */
238    fprintf(af, "%s type:=link;fs:=%s\n", ap->a_name + sk, ap->a_symlink);
239  }
240
241  return errors;
242}
243
244
245/*
246 * Write a single automount configuration file
247 */
248static int
249write_amount( qelem *q, char *def)
250{
251  automount *ap;
252  int errors = 0;
253  int direct = 0;
254
255  /*
256   * Output all indirect maps
257   */
258  ITER(ap, automount, q) {
259    FILE *af;
260    char *p;
261
262    /*
263     * If there is no a_mount node then this is really
264     * a direct mount, so just keep a count and continue.
265     * Direct mounts are output into a special file during
266     * the second pass below.
267     */
268    if (!ap->a_mount) {
269      direct++;
270      continue;
271    }
272
273    p = strrchr(ap->a_name, '/');
274    if (!p)
275      p = ap->a_name;
276    else
277      p++;
278
279    af = pref_open(mount_pref, p, gen_hdr, ap->a_name);
280    if (af) {
281      show_new(ap->a_name);
282      fputs("/defaults ", af);
283      if (*def)
284	fprintf(af, "%s;", def);
285      fputs("type:=nfs\n", af);
286      errors += write_amount_info(af, ap, strlen(ap->a_name) + 1);
287      errors += pref_close(af);
288    }
289  }
290
291  /*
292   * Output any direct map entries which were found during the
293   * previous pass over the data.
294   */
295  if (direct) {
296    FILE *af = pref_open(mount_pref, "direct.map", info_hdr, "direct mount");
297
298    if (af) {
299      show_new("direct mounts");
300      fputs("/defaults ", af);
301      if (*def)
302	fprintf(af, "%s;", def);
303      fputs("type:=nfs\n", af);
304      ITER(ap, automount, q)
305      if (!ap->a_mount)
306	  errors += write_amount_info(af, ap, 1);
307      errors += pref_close(af);
308    }
309  }
310  return errors;
311}
312
313
314/*
315 * Write all the needed automount configuration files
316 */
317int
318write_atab(qelem *q)
319{
320  int errors = 0;
321
322  if (mount_pref) {
323    auto_tree *tp;
324    show_area_being_processed("write automount", 5);
325    ITER(tp, auto_tree, q)
326      errors += write_amount(tp->t_mount, tp->t_defaults);
327  }
328
329  return errors;
330}
331