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