1/*
2 * Copyright (c) 1997-2014 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. 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/amq/pawd.c
37 *
38 */
39
40/*
41 * pawd is similar to pwd, except that it returns more "natural" versions of
42 * pathnames for directories automounted with the amd automounter.  If any
43 * arguments are given, the "more natural" form of the given pathnames are
44 * printed.
45 *
46 * Paul Anderson (paul@ed.lfcs)
47 *
48 */
49
50#ifdef HAVE_CONFIG_H
51# include <config.h>
52#endif /* HAVE_CONFIG_H */
53#include <am_defs.h>
54#include <amq.h>
55
56
57/* statics */
58static char *localhost = "localhost";
59static char transform[MAXPATHLEN];
60
61
62#ifdef HAVE_CNODEID
63static char *
64cluster_server(void)
65{
66# ifdef HAVE_EXTERN_GETCCENT
67  struct cct_entry *cp;
68# endif /* HAVE_EXTERN_GETCCENT */
69
70  if (cnodeid() == 0)
71    return localhost;
72
73# ifdef HAVE_EXTERN_GETCCENT
74  while ((cp = getccent()))
75    if (cp->cnode_type == 'r')
76      return cp->cnode_name;
77# endif /* HAVE_EXTERN_GETCCENT */
78
79  return localhost;
80}
81#endif /* HAVE_CNODEID */
82
83
84/* DISK_HOME_HACK added by gdmr */
85#ifdef DISK_HOME_HACK
86static char *
87hack_name(char *dir)
88{
89  char partition[MAXPATHLEN];
90  char username[MAXPATHLEN];
91  char hesiod_lookup[MAXPATHLEN];
92  char *to, *ch, *hes_name, *dot;
93  char **hes;
94
95#ifdef DEBUG
96  fprintf(stderr, "hack_name(%s)\n", dir);
97#endif /* DEBUG */
98
99  if (dir[0] == '/' && dir[1] == 'a' && dir[2] == '/') {
100    /* Could be /a/server/disk/home/partition/user... */
101    ch = dir + 3;
102    while (*ch && *ch != '/') ch++;  /* Skip server */
103    if (!NSTREQ(ch, "/disk/home/", 11))
104      return NULL;		/* Nope */
105    /* Looking promising, next should be the partition name */
106    ch += 11;
107    to = partition;
108    while (*ch && *ch != '/') *to++ = *ch++;
109    to = '\0';
110    if (!(*ch))
111      return NULL;		/* Off the end */
112    /* Now the username */
113    ch++;
114    to = username;
115    while (*ch && *ch != '/') *to++ = *ch++;
116    to = '\0';
117#ifdef DEBUG
118    fprintf(stderr, "partition %s, username %s\n", partition, username);
119#endif /* DEBUG */
120
121    xsnprintf(hesiod_lookup, sizeof(hesiod_lookup),
122	      "%s.homes-remote", username);
123    hes = hes_resolve(hesiod_lookup, "amd");
124    if (!hes)
125      return NULL;
126#ifdef DEBUG
127    fprintf(stderr, "hesiod -> <%s>\n", *hes);
128#endif /* DEBUG */
129    hes_name = strstr(*hes, "/homes/remote/");
130    if (!hes_name) return NULL;
131    hes_name += 14;
132#ifdef DEBUG
133    fprintf(stderr, "hesiod -> <%s>\n", hes_name);
134#endif /* DEBUG */
135    dot = hes_name;
136    while (*dot && *dot != '.') dot++;
137    *dot = '\0';
138#ifdef DEBUG
139    fprintf(stderr, "hesiod -> <%s>\n", hes_name);
140#endif /* DEBUG */
141
142    if (strcmp(partition, hes_name)) return NULL;
143#ifdef DEBUG
144    fprintf(stderr, "A match, munging....\n");
145#endif /* DEBUG */
146    xstrlcpy(transform, "/home/", sizeof(transform));
147    xstrlcat(transform, username, sizeof(transform));
148    if (*ch)
149      xstrlcat(transform, ch, sizeof(transform));
150#ifdef DEBUG
151    fprintf(stderr, "Munged to <%s>\n", transform);
152#endif /* DEBUG */
153    return transform;
154  }
155  return NULL;
156}
157#endif /* DISK_HOME_HACK */
158
159
160/*
161 * The routine transform_dir(path) transforms pathnames of directories
162 * mounted with the amd automounter to produce a more "natural" version.
163 * The automount table is obtained from the local amd via the rpc interface
164 * and reverse lookups are repeatedly performed on the directory name
165 * substituting the name of the automount link for the value of the link
166 * whenever it occurs as a prefix of the directory name.
167 */
168static char *
169transform_dir(char *dir)
170{
171#ifdef DISK_HOME_HACK
172  char *ch;
173#endif /* DISK_HOME_HACK */
174  char *server;
175  struct sockaddr_in server_addr;
176  int s = RPC_ANYSOCK;
177  CLIENT *clnt;
178  struct hostent *hp;
179  struct timeval tmo = {10, 0};
180  char *dummystr;
181  amq_string *spp;
182
183#ifdef DISK_HOME_HACK
184  if (ch = hack_name(dir))
185    return ch;
186#endif /* DISK_HOME_HACK */
187
188#ifdef HAVE_CNODEID
189  server = cluster_server();
190#else /* not HAVE_CNODEID */
191  server = localhost;
192#endif /* not HAVE_CNODEID */
193
194  if ((hp = gethostbyname(server)) == NULL)
195    return dir;
196  memset(&server_addr, 0, sizeof(server_addr));
197  /* as per POSIX, sin_len need not be set (used internally by kernel) */
198  server_addr.sin_family = AF_INET;
199  server_addr.sin_addr = *(struct in_addr *) hp->h_addr;
200
201  clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, tmo, &s);
202  if (clnt == NULL)
203    clnt = clnttcp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, &s, 0, 0);
204  if (clnt == NULL)
205    return dir;
206
207  xstrlcpy(transform, dir, sizeof(transform));
208  dummystr = transform;
209  spp = amqproc_pawd_1((amq_string *) &dummystr, clnt);
210  if (spp && *spp && **spp) {
211    xstrlcpy(transform, *spp, sizeof(transform));
212    XFREE(*spp);
213  }
214  clnt_destroy(clnt);
215  return transform;
216}
217
218
219/* getawd() is a substitute for getwd() which transforms the path */
220static char *
221getawd(char *path, size_t l)
222{
223#ifdef HAVE_GETCWD
224  char *wd = getcwd(path, MAXPATHLEN);
225#else /* not HAVE_GETCWD */
226  char *wd = getwd(path);
227#endif /* not HAVE_GETCWD */
228
229  if (wd == NULL) {
230    return NULL;
231  }
232  xstrlcpy(path, transform_dir(wd), l);
233  return path;
234}
235
236
237int
238main(int argc, char *argv[])
239{
240  char tmp_buf[MAXPATHLEN], *wd;
241
242  if (argc == 1) {
243    wd = getawd(tmp_buf, sizeof(tmp_buf));
244    if (wd == NULL) {
245      fprintf(stderr, "pawd: %s\n", tmp_buf);
246      exit(1);
247    } else {
248      fprintf(stdout, "%s\n", wd);
249    }
250  } else {
251    while (--argc) {
252      wd = transform_dir(*++argv);
253      fprintf(stdout, "%s\n", wd);
254    }
255  }
256  exit(0);
257}
258