1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 1997-2014 Erez Zadok
5 * Copyright (c) 2005 Daniel P. Ottavio
6 * Copyright (c) 1990 Jan-Simon Pendry
7 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
8 * Copyright (c) 1990 The Regents of the University of California.
9 * All rights reserved.
10 *
11 * This code is derived from software contributed to Berkeley by
12 * Jan-Simon Pendry at Imperial College, London.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *
39 * File: am-utils/amd/sun_map.c
40 *
41 */
42
43#ifdef HAVE_CONFIG_H
44# include <config.h>
45#endif /* HAVE_CONFIG_H */
46#include <am_defs.h>
47#include <amd.h>
48#include <sun_map.h>
49
50
51
52/*
53 * Add a data pointer to the end of the list.
54 */
55void
56sun_list_add(struct sun_list *list, qelem *item)
57{
58  if (list->last == NULL) {
59    list->last = item;
60    list->first = item;
61    item->q_back = NULL;
62  }
63  else {
64    list->last->q_forw = item;
65    item->q_back = list->last;
66    list->last = item;
67  }
68
69  item->q_forw = NULL;
70}
71
72
73/*
74 * Sun2Amd conversion routines
75 */
76
77/*
78 * AMD entry keywords
79 */
80#define AMD_OPTS_KW      "addopts:="     /* add entry options */
81#define AMD_RHOST_KW     "rhost:="       /* remote host */
82#define AMD_RFS_KW       "rfs:="         /* remote file system */
83#define AMD_FS_KW        "fs:="          /* local file system */
84#define AMD_DEV_KW       "dev:="         /* device */
85#define AMD_TYPE_NFS_KW  "type:=nfs;"    /* fs type nfs */
86#define AMD_TYPE_AUTO_KW "type:=auto;"   /* fs type auto */
87#define AMD_TYPE_CDFS_KW "type:=cdfs;"   /* fs type cd */
88#define AMD_MAP_FS_KW    "fs:=${map};"   /* set the mount map as current map */
89#define AMD_MAP_PREF_KW  "pref:=${key}/" /* set the mount map as current map */
90
91/*
92 * A set of string Sun fstypes.
93 */
94#define SUN_NFS_TYPE     "nfs"
95#define SUN_HSFS_TYPE    "hsfs" /* CD fs */
96#define SUN_AUTOFS_TYPE  "autofs"
97#define SUN_CACHEFS_TYPE "cachefs"
98
99#define SUN_KEY_SUB      "&"         /* Sun key substitution */
100
101/* a set a Sun variable substitutions for map entries */
102#define SUN_ARCH         "$ARCH"     /* host architecture */
103#define SUN_CPU          "$CPU"      /* processor type */
104#define SUN_HOST         "$HOST"     /* host name */
105#define SUN_OSNAME       "$OSNAME"   /* OS name */
106#define SUN_OSREL        "$OSREL"    /* OS release */
107#define SUN_OSVERS       "$OSVERS"   /* OS version */
108#define SUN_NATISA       "$NATISA"   /* native instruction set */
109
110/* a set of Amd variable substitutions */
111#define AMD_ARCH         "${arch}"   /* host architecture */
112#define AMD_HOST         "${host}"   /* host name */
113#define AMD_OSNAME       "${os}"     /* OS name */
114#define AMD_OSVER        "${osver}"  /* OS version */
115
116
117/*
118 * Return a copy of src that has all occurrences of 'str' replaced
119 * with sub.
120 *
121 * param src - the original string
122 * param str - string that is the replaced with str
123 * param sub - string that replaces an occurrences of 'delim'
124 *
125 * return - new string with str substitutions, NULL on error
126 */
127static char *
128sun_strsub(const char *src, const char *str, const char *sub)
129{
130
131  char *retval = NULL, *str_start, *str_end, *src_end;
132  size_t total_size, first_half, second_half, sub_size;
133
134  /* assign pointers to the start and end of str */
135  if ((str_start = strstr(src, str)) == NULL) {
136    return retval;
137  }
138  str_end = (strlen(str) - 1) + str_start;
139
140  /* assign to the end of the src. */
141  src_end = (strlen(src) - 1) + (char*)src;
142
143  /* size from the beginning of src to the start of str */
144  first_half = (size_t)(str_start - src);
145
146  /* size from the end of str to the end of src */
147  second_half = (size_t)(src_end - str_end);
148
149  sub_size = strlen(sub);
150
151  total_size = (first_half + sub_size + second_half + 1);
152
153  retval = (char*)xmalloc(total_size);
154  memset(retval, 0, total_size);
155
156  /*
157   * Put together the string such that the first half is copied
158   * followed the sub and second half.
159   *
160   * We use strncpy instead of xstrlcpy because we are intentionally
161   * causing truncation and we don't want this to cause errors in the
162   * log.
163   */
164  (void)strncpy(retval, src, first_half);
165  (void)strncat(retval, sub, sub_size);
166  (void)strncat(retval, str_end + 1, second_half);
167
168  if (strstr(retval, str) != NULL) {
169    /*
170     * If there is another occurrences of str call this function
171     * recursively.
172     */
173    char* tmp;
174    if ((tmp = sun_strsub(retval, str, sub)) != NULL) {
175      XFREE(retval);
176      retval = tmp;
177    }
178  }
179  return retval;
180}
181
182
183/*
184 * Return a new string that is a copy of str, all occurrences of a Sun
185 * variable substitutions are replaced by there equivalent Amd
186 * substitutions.
187 *
188 * param str - source string
189 *
190 * return - A new string with the expansions, NULL if str does not
191 * exist in src or error.
192 */
193static char *
194sun_expand2amd(const char *str)
195{
196
197  char *retval = NULL, *tmp = NULL, *tmp2 = NULL;
198  const char *pos;
199
200  /*
201   * Iterator through the string looking for '$' chars.  For each '$'
202   * found try to replace it with Sun variable substitutions.  If we
203   * find a '$' that is not a substation each of the i.e $blah than
204   * each of the replace attempt will fail and we'll move on to the
205   * next char.
206   */
207  tmp = xstrdup(str);
208  for (pos = str; *pos != '\0'; pos++) {
209    if (*pos != '$') {
210      continue;
211    }
212    if (tmp2 != NULL) {
213      XFREE(tmp);
214      tmp = tmp2;
215    }
216
217    /*
218     * If a 'replace' does not return NULL than a variable was
219     * successfully substituted.
220     */
221
222    /* architecture */
223    if ((tmp2 = sun_strsub(tmp, SUN_ARCH, AMD_ARCH)) != NULL) {
224      continue;
225    }
226    /* cpu - there is not POSIX uname for cpu so just use machine */
227    if ((tmp2 = sun_strsub(tmp, SUN_CPU, AMD_ARCH)) != NULL) {
228      continue;
229    }
230    /* hostname */
231    if ((tmp2 = sun_strsub(tmp, SUN_HOST, AMD_HOST)) != NULL) {
232      continue;
233    }
234    /* os name */
235    if ((tmp2 = sun_strsub(tmp, SUN_OSNAME, AMD_OSNAME)) != NULL) {
236      continue;
237    }
238    /*
239     * os release - Amd doesn't hava a OS release var just usr os
240     * version or now.
241     */
242    if ((tmp2 = sun_strsub(tmp, SUN_OSREL, AMD_OSVER)) != NULL) {
243      continue;
244    }
245    /* os version */
246    if ((tmp2 = sun_strsub(tmp, SUN_OSVERS, AMD_OSVER)) != NULL) {
247      continue;
248    }
249    /* native instruction set - there is no POSIX natisa so just use system */
250    if ((tmp2 = sun_strsub(tmp, SUN_NATISA, AMD_ARCH)) != NULL) {
251      continue;
252    }
253  }
254  if (tmp2 == NULL) {
255    retval = tmp;
256  }
257  else {
258    retval = tmp2;
259    XFREE(tmp);
260  }
261
262  return retval;
263}
264
265
266/*
267 * This is a wrapper function for appending Amd entry information to a
268 * buffer.  Any Sun variable substitutions will be converted into Amd
269 * equivalents.
270 *
271 * param dest   - destination buffer
272 * param deslen - destination buffer length
273 * param key    - entry key, this might be needed for key substitutions
274 * param str    - string to append
275 */
276static void
277sun_append_str(char *dest,
278	       size_t destlen,
279	       const char *key,
280	       const char *str)
281{
282  char *sub = NULL, *sub2 = NULL, *out = NULL;
283
284  /* By default we are going to just write the original string. */
285  out = (char*)str;
286
287  /*
288   * Resolve variable substitutions in two steps; 1) replace any key
289   * map substitutions with the entry key 2) expand any variable
290   * substitutions i.e $HOST.
291   *
292   * Try to replace the key substitution '&'. If this function returns
293   * with a new string, one or more key subs. where replaced with the
294   * entry key.
295   */
296  if ((sub = sun_strsub(str, SUN_KEY_SUB, "${key}")) != NULL) {
297    out = sub;
298    /*
299     * Try to convert any variable substitutions. If this function
300     * returns a new string one or more var subs where expanded.
301     */
302    if ((sub2 = sun_expand2amd(sub)) != NULL) {
303      out = sub2;
304    }
305  }
306  /*
307   * Try to convert any variable substitutions. If this function
308   * returns a new string one or more var subs where expanded.
309   */
310  else if (out != NULL && (sub = sun_expand2amd(out)) != NULL) {
311    out = sub;
312  }
313
314  if (out != NULL) {
315    xstrlcat(dest, out, destlen);
316  }
317  XFREE(sub);
318  XFREE(sub2);
319}
320
321
322/*
323 * Convert the list of Sun mount options to Amd mount options.  The
324 * result is concatenated to dest.
325 *
326 * param dest     - destination buffer
327 * param destlen  - destination buffer length
328 * param key      - automount key
329 * param opt_list - list of Sun mount options
330 */
331static void
332sun_opts2amd(char *dest,
333	     size_t destlen,
334	     const char *key,
335	     const struct sun_opt *opt_list)
336{
337  const struct sun_opt *opt;
338
339  xstrlcat(dest, AMD_OPTS_KW, destlen);
340
341  /* Iterate through each option and append it to the buffer. */
342  for(opt = opt_list; opt != NULL; opt = NEXT(struct sun_opt, opt)) {
343    sun_append_str(dest, destlen, key, opt->str);
344    /* If there are more options add some commas. */
345    if (NEXT(struct sun_opt, opt) != NULL) {
346      xstrlcat(dest, ",", destlen);
347    }
348  }
349  xstrlcat(dest, ";", destlen);
350}
351
352
353/*
354 * Convert the list of Sun mount locations to a list of Amd mount
355 * locations.  The result is concatenated to dest.
356 *
357 * param dest       - destination buffer
358 * param destlen    - destination buffer length
359 * param key        - automount key
360 * param local_list - list of Sun mount locations
361 */
362static void
363sun_locations2amd(char *dest,
364		  size_t destlen,
365		  const char *key,
366		  const struct sun_location *local_list)
367{
368  const struct sun_location *local;
369  const struct sun_host *host;
370
371  for (local = local_list;
372       local != NULL;
373       local = NEXT(struct sun_location,local)) {
374    /*
375     * Check to see if the list of hosts is empty.  Some mount types
376     * i.e cd-rom may have mount location with no host.
377     */
378    if (local->host_list != NULL) {
379      /* Write each host that belongs to this location. */
380      for (host = local->host_list;
381	   host != NULL;
382	   host = NEXT(struct sun_host, host)) {
383	/* set fstype NFS */
384	xstrlcat(dest, AMD_TYPE_NFS_KW, destlen);
385	/* add rhost key word */
386	xstrlcat(dest, AMD_RHOST_KW, destlen);
387	/* add host name */
388	sun_append_str(dest, destlen, key, host->name);
389	xstrlcat(dest, ";", destlen);
390	/* add remote fs key word */
391	xstrlcat(dest, AMD_RFS_KW, destlen);
392	/* add local path */
393	sun_append_str(dest, destlen, key, local->path);
394	if (NEXT(struct sun_host, host) != NULL) {
395	  xstrlcat(dest, ";", destlen);
396	  xstrlcat(dest, " ", destlen);
397	}
398      }
399    }
400    else {
401      /* no host location */
402      xstrlcat(dest, AMD_FS_KW, destlen);
403      sun_append_str(dest, destlen, key, local->path);
404    }
405    if (NEXT(struct sun_location, local) != NULL) {
406      /* add a space to separate each location */
407      xstrlcat(dest, " ", destlen);
408    }
409  }
410}
411
412
413/*
414 * Convert a Sun HSFS mount point to an Amd.  The result is
415 * concatenated intp dest.
416 *
417 * param dest    - destination buffer
418 * param destlen - destination buffer length
419 * param key     - automount key
420 * param s_entry - Sun entry
421 */
422static void
423sun_hsfs2amd(char *dest,
424	     size_t destlen,
425	     const char *key,
426	     const struct sun_entry *s_entry)
427{
428  /* set fstype CDFS */
429  xstrlcat(dest, AMD_TYPE_CDFS_KW, destlen);
430  /* set the cdrom device */
431  xstrlcat(dest, AMD_DEV_KW, destlen);
432  /* XXX: For now just assume that there is only one device. */
433  xstrlcat(dest, s_entry->location_list->path, destlen);
434}
435
436
437/*
438 * Convert a Sun NFS automount entry to an Amd.  The result is concatenated
439 * into dest.
440 *
441 * param dest    - destination buffer
442 * param destlen - destination buffer length
443 * param key     - automount key
444 * param s_entry - Sun entry
445 */
446static void
447sun_nfs2amd(char *dest,
448	    size_t destlen,
449	    const char *key,
450	    const struct sun_entry *s_entry)
451{
452  if (s_entry->location_list != NULL) {
453    /* write out the list of mountpoint locations */
454    sun_locations2amd(dest, destlen, key, s_entry->location_list);
455  }
456}
457
458
459/*
460 * Convert a Sun multi-mount point entry to an Amd.  This is done
461 * using the Amd type auto.  Each auto entry is separated with a \n.
462 *
463 * param dest    - destination buffer
464 * param destlen - destination buffer length
465 * param key     - automount key
466 * param s_entry - Sun entry
467 */
468static void
469sun_multi2amd(char *dest,
470	      size_t destlen,
471	      const char *key,
472	      const struct sun_entry *s_entry)
473{
474  const struct sun_mountpt *mountpt;
475
476  /* We need to setup a auto fs Amd automount point. */
477  xstrlcat(dest, AMD_TYPE_AUTO_KW, destlen);
478  xstrlcat(dest, AMD_MAP_FS_KW, destlen);
479  xstrlcat(dest, AMD_MAP_PREF_KW, destlen);
480
481  /* write the mountpts to dest */
482  for (mountpt = s_entry->mountpt_list;
483       mountpt != NULL;
484       mountpt = NEXT(struct sun_mountpt, mountpt)) {
485    xstrlcat(dest, "\n", destlen);
486    /* write the key */
487    xstrlcat(dest, key, destlen);
488    /* write the mount path */
489    sun_append_str(dest, destlen, key, mountpt->path);
490    /* space */
491    xstrlcat(dest, " ", destlen);
492    /* Write all the host locations for this mount point. */
493    sun_locations2amd(dest, destlen, key, mountpt->location_list);
494  }
495}
496
497
498/*
499 * Convert the sun_entry into an Amd equivalent string.
500 *
501 * param key     - automount key
502 * param s_entry - Sun style automap entry
503 *
504 * return - Amd entry on succes, NULL on error
505 */
506char *
507sun_entry2amd(const char *key, const char *s_entry_str)
508{
509  char *retval = NULL;
510  char line_buff[INFO_MAX_LINE_LEN];
511  int ws;
512  struct sun_entry *s_entry = NULL;
513
514  /* The key should not be NULL. */
515  if (key == NULL) {
516    plog(XLOG_ERROR,"Sun key value was null");
517    goto err;
518  }
519  /* The Sun entry string should never be NULL. */
520  if (s_entry_str == NULL) {
521    plog(XLOG_ERROR,"Sun entry value was null");
522    goto err;
523  }
524
525  /* Make sure there are no trailing white spaces or '\n'. */
526  xstrlcpy(line_buff, s_entry_str, sizeof(line_buff));
527  ws = strlen(line_buff) - 1;
528  while (ws >= 0 && (isspace((unsigned char)line_buff[ws]) || line_buff[ws] == '\n')) {
529    line_buff[ws--] = '\0';
530  }
531
532  /* Parse the sun entry line. */
533  s_entry = sun_map_parse_read(line_buff);
534  if (s_entry == NULL) {
535    plog(XLOG_ERROR,"could not parse Sun style map");
536    goto err;
537  }
538
539  memset(line_buff, 0, sizeof(line_buff));
540
541  if (s_entry->opt_list != NULL) {
542    /* write the mount options to the buffer  */
543    sun_opts2amd(line_buff, sizeof(line_buff), key, s_entry->opt_list);
544  }
545
546  /* Check if this is a multi-mount entry. */
547  if (s_entry->mountpt_list != NULL) {
548    /* multi-mount point */
549    sun_multi2amd(line_buff, sizeof(line_buff), key, s_entry);
550    retval = xstrdup(line_buff);
551  }
552  else {
553    /* single mount point */
554    if (s_entry->fstype != NULL) {
555      if (NSTREQ(s_entry->fstype, SUN_NFS_TYPE, strlen(SUN_NFS_TYPE))) {
556	/* NFS Type */
557	sun_nfs2amd(line_buff, sizeof(line_buff), key, s_entry);
558	retval = xstrdup(line_buff);
559      }
560      else if (NSTREQ(s_entry->fstype, SUN_HSFS_TYPE, strlen(SUN_HSFS_TYPE))) {
561	/* HSFS Type (CD fs) */
562	sun_hsfs2amd(line_buff, sizeof(line_buff), key, s_entry);
563	retval = xstrdup(line_buff);
564      }
565      /*
566       * XXX: The following fstypes are not yet supported.
567       */
568      else if (NSTREQ(s_entry->fstype, SUN_AUTOFS_TYPE, strlen(SUN_AUTOFS_TYPE))) {
569	/* AutoFS Type */
570	plog(XLOG_ERROR, "Sun fstype %s is currently not supported by Amd.",
571	     s_entry->fstype);
572	goto err;
573
574      }
575      else if (NSTREQ(s_entry->fstype, SUN_CACHEFS_TYPE, strlen(SUN_CACHEFS_TYPE))) {
576	/* CacheFS Type */
577	plog(XLOG_ERROR, "Sun fstype %s is currently not supported by Amd.",
578	     s_entry->fstype);
579	goto err;
580      }
581      else {
582	plog(XLOG_ERROR, "Sun fstype %s is currently not supported by Amd.",
583	     s_entry->fstype);
584	goto err;
585      }
586    }
587    else {
588      plog(XLOG_INFO, "No SUN fstype specified defaulting to NFS.");
589      sun_nfs2amd(line_buff, sizeof(line_buff), key, s_entry);
590      retval = xstrdup(line_buff);
591    }
592  }
593
594 err:
595  XFREE(s_entry);
596  return retval;
597}
598