1/*	$NetBSD: pawd.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997-2014 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *
38 * File: am-utils/amq/pawd.c
39 *
40 */
41
42/*
43 * pawd is similar to pwd, except that it returns more "natural" versions of
44 * pathnames for directories automounted with the amd automounter.  If any
45 * arguments are given, the "more natural" form of the given pathnames are
46 * printed.
47 *
48 * Paul Anderson (paul@ed.lfcs)
49 *
50 */
51
52#ifdef HAVE_CONFIG_H
53# include <config.h>
54#endif /* HAVE_CONFIG_H */
55#include <am_defs.h>
56#include <amq.h>
57
58
59/* statics */
60static char *localhost = "localhost";
61static char transform[MAXPATHLEN];
62
63
64#ifdef HAVE_CNODEID
65static char *
66cluster_server(void)
67{
68# ifdef HAVE_EXTERN_GETCCENT
69  struct cct_entry *cp;
70# endif /* HAVE_EXTERN_GETCCENT */
71
72  if (cnodeid() == 0)
73    return localhost;
74
75# ifdef HAVE_EXTERN_GETCCENT
76  while ((cp = getccent()))
77    if (cp->cnode_type == 'r')
78      return cp->cnode_name;
79# endif /* HAVE_EXTERN_GETCCENT */
80
81  return localhost;
82}
83#endif /* HAVE_CNODEID */
84
85
86/* DISK_HOME_HACK added by gdmr */
87#ifdef DISK_HOME_HACK
88static char *
89hack_name(char *dir)
90{
91  char partition[MAXPATHLEN];
92  char username[MAXPATHLEN];
93  char hesiod_lookup[MAXPATHLEN];
94  char *to, *ch, *hes_name, *dot;
95  char **hes;
96
97#ifdef DEBUG
98  fprintf(stderr, "hack_name(%s)\n", dir);
99#endif /* DEBUG */
100
101  if (dir[0] == '/' && dir[1] == 'a' && dir[2] == '/') {
102    /* Could be /a/server/disk/home/partition/user... */
103    ch = dir + 3;
104    while (*ch && *ch != '/') ch++;  /* Skip server */
105    if (!NSTREQ(ch, "/disk/home/", 11))
106      return NULL;		/* Nope */
107    /* Looking promising, next should be the partition name */
108    ch += 11;
109    to = partition;
110    while (*ch && *ch != '/') *to++ = *ch++;
111    to = '\0';
112    if (!(*ch))
113      return NULL;		/* Off the end */
114    /* Now the username */
115    ch++;
116    to = username;
117    while (*ch && *ch != '/') *to++ = *ch++;
118    to = '\0';
119#ifdef DEBUG
120    fprintf(stderr, "partition %s, username %s\n", partition, username);
121#endif /* DEBUG */
122
123    xsnprintf(hesiod_lookup, sizeof(hesiod_lookup),
124	      "%s.homes-remote", username);
125    hes = hes_resolve(hesiod_lookup, "amd");
126    if (!hes)
127      return NULL;
128#ifdef DEBUG
129    fprintf(stderr, "hesiod -> <%s>\n", *hes);
130#endif /* DEBUG */
131    hes_name = strstr(*hes, "/homes/remote/");
132    if (!hes_name) return NULL;
133    hes_name += 14;
134#ifdef DEBUG
135    fprintf(stderr, "hesiod -> <%s>\n", hes_name);
136#endif /* DEBUG */
137    dot = hes_name;
138    while (*dot && *dot != '.') dot++;
139    *dot = '\0';
140#ifdef DEBUG
141    fprintf(stderr, "hesiod -> <%s>\n", hes_name);
142#endif /* DEBUG */
143
144    if (strcmp(partition, hes_name)) return NULL;
145#ifdef DEBUG
146    fprintf(stderr, "A match, munging....\n");
147#endif /* DEBUG */
148    xstrlcpy(transform, "/home/", sizeof(transform));
149    xstrlcat(transform, username, sizeof(transform));
150    if (*ch)
151      xstrlcat(transform, ch, sizeof(transform));
152#ifdef DEBUG
153    fprintf(stderr, "Munged to <%s>\n", transform);
154#endif /* DEBUG */
155    return transform;
156  }
157  return NULL;
158}
159#endif /* DISK_HOME_HACK */
160
161
162/*
163 * The routine transform_dir(path) transforms pathnames of directories
164 * mounted with the amd automounter to produce a more "natural" version.
165 * The automount table is obtained from the local amd via the rpc interface
166 * and reverse lookups are repeatedly performed on the directory name
167 * substituting the name of the automount link for the value of the link
168 * whenever it occurs as a prefix of the directory name.
169 */
170static char *
171transform_dir(char *dir)
172{
173#ifdef DISK_HOME_HACK
174  char *ch;
175#endif /* DISK_HOME_HACK */
176  char *server;
177  struct sockaddr_in server_addr;
178  int s = RPC_ANYSOCK;
179  CLIENT *clnt;
180  struct hostent *hp;
181  struct timeval tmo = {10, 0};
182  char *dummystr;
183  amq_string *spp;
184
185#ifdef DISK_HOME_HACK
186  if (ch = hack_name(dir))
187    return ch;
188#endif /* DISK_HOME_HACK */
189
190#ifdef HAVE_CNODEID
191  server = cluster_server();
192#else /* not HAVE_CNODEID */
193  server = localhost;
194#endif /* not HAVE_CNODEID */
195
196  if ((hp = gethostbyname(server)) == NULL)
197    return dir;
198  memset(&server_addr, 0, sizeof(server_addr));
199  /* as per POSIX, sin_len need not be set (used internally by kernel) */
200  server_addr.sin_family = AF_INET;
201  server_addr.sin_addr = *(struct in_addr *) hp->h_addr;
202
203  clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, tmo, &s);
204  if (clnt == NULL)
205    clnt = clnttcp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, &s, 0, 0);
206  if (clnt == NULL)
207    return dir;
208
209  xstrlcpy(transform, dir, sizeof(transform));
210  dummystr = transform;
211  spp = amqproc_pawd_1((amq_string *) &dummystr, clnt);
212  if (spp && *spp && **spp) {
213    xstrlcpy(transform, *spp, sizeof(transform));
214    XFREE(*spp);
215  }
216  clnt_destroy(clnt);
217  return transform;
218}
219
220
221/* getawd() is a substitute for getwd() which transforms the path */
222static char *
223getawd(char *path, size_t l)
224{
225#ifdef HAVE_GETCWD
226  char *wd = getcwd(path, MAXPATHLEN);
227#else /* not HAVE_GETCWD */
228  char *wd = getwd(path);
229#endif /* not HAVE_GETCWD */
230
231  if (wd == NULL) {
232    return NULL;
233  }
234  xstrlcpy(path, transform_dir(wd), l);
235  return path;
236}
237
238
239int
240main(int argc, char *argv[])
241{
242  char tmp_buf[MAXPATHLEN], *wd;
243
244  if (argc == 1) {
245    wd = getawd(tmp_buf, sizeof(tmp_buf));
246    if (wd == NULL) {
247      fprintf(stderr, "pawd: %s\n", tmp_buf);
248      exit(1);
249    } else {
250      fprintf(stdout, "%s\n", wd);
251    }
252  } else {
253    while (--argc) {
254      wd = transform_dir(*++argv);
255      fprintf(stdout, "%s\n", wd);
256    }
257  }
258  exit(0);
259}
260