/* $NetBSD: pawd.c,v 1.2 2003/07/15 09:01:18 itojun Exp $ */ /* * Copyright (c) 1997-2003 Erez Zadok * Copyright (c) 1990 Jan-Simon Pendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry at Imperial College, London. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Id: pawd.c,v 1.10 2002/12/27 22:43:54 ezk Exp * */ /* * pawd is similar to pwd, except that it returns more "natural" versions of * pathnames for directories automounted with the amd automounter. If any * arguments are given, the "more natural" form of the given pathnames are * printed. * * Paul Anderson (paul@ed.lfcs) * */ #ifdef HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include /* statics */ static char *localhost="localhost"; static char newdir[MAXPATHLEN]; static char transform[MAXPATHLEN]; static int find_mt(amq_mount_tree *mt, char *dir) { while (mt) { if (STREQ(mt->mt_type, "link") || STREQ(mt->mt_type, "nfs") || STREQ(mt->mt_type, "nfsl")) { int len = strlen(mt->mt_mountpoint); if (NSTREQ(mt->mt_mountpoint, dir, len) && ((dir[len] == '\0') || (dir[len] == '/'))) { char tmp_buf[MAXPATHLEN]; strlcpy(tmp_buf, mt->mt_directory, sizeof(tmp_buf)); strlcat(tmp_buf, &dir[len], sizeof(tmp_buf)); strlcpy(newdir, tmp_buf, sizeof(newdir)); return 1; } } if (find_mt(mt->mt_next,dir)) return 1; mt = mt->mt_child; } return 0; } static int find_mlp(amq_mount_tree_list *mlp, char *dir) { int i; for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { if (find_mt(mlp->amq_mount_tree_list_val[i], dir)) return 1; } return 0; } #ifdef HAVE_CNODEID static char * cluster_server(void) { # ifdef HAVE_EXTERN_GETCCENT struct cct_entry *cp; # endif /* HAVE_EXTERN_GETCCENT */ if (cnodeid() == 0) return localhost; # ifdef HAVE_EXTERN_GETCCENT while ((cp = getccent())) if (cp->cnode_type == 'r') return cp->cnode_name; # endif /* HAVE_EXTERN_GETCCENT */ return localhost; } #endif /* HAVE_CNODEID */ /* DISK_HOME_HACK added by gdmr */ #ifdef DISK_HOME_HACK static char * hack_name(char *dir) { char partition[MAXPATHLEN]; char username[MAXPATHLEN]; char hesiod_lookup[MAXPATHLEN]; char *to, *ch, *hes_name, *dot; char **hes; #ifdef DEBUG fprintf(stderr, "hack_name(%s)\n", dir); #endif /* DEBUG */ if (dir[0] == '/' && dir[1] == 'a' && dir[2] == '/') { /* Could be /a/server/disk/home/partition/user... */ ch = dir + 3; while (*ch && *ch != '/') ch++; /* Skip server */ if (!NSTREQ(ch, "/disk/home/", 11)) return NULL; /* Nope */ /* Looking promising, next should be the partition name */ ch += 11; to = partition; while (*ch && *ch != '/') *to++ = *ch++; to = '\0'; if (!(*ch)) return NULL; /* Off the end */ /* Now the username */ ch++; to = username; while (*ch && *ch != '/') *to++ = *ch++; to = '\0'; #ifdef DEBUG fprintf(stderr, "partition %s, username %s\n", partition, username); #endif /* DEBUG */ snprintf(hesiod_lookup, sizeof(hesiod_lookup), "%s.homes-remote", username); hes = hes_resolve(hesiod_lookup, "amd"); if (!hes) return NULL; #ifdef DEBUG fprintf(stderr, "hesiod -> <%s>\n", *hes); #endif /* DEBUG */ hes_name = strstr(*hes, "/homes/remote/"); if (!hes_name) return NULL; hes_name += 14; #ifdef DEBUG fprintf(stderr, "hesiod -> <%s>\n", hes_name); #endif /* DEBUG */ dot = hes_name; while (*dot && *dot != '.') dot++; *dot = '\0'; #ifdef DEBUG fprintf(stderr, "hesiod -> <%s>\n", hes_name); #endif /* DEBUG */ if (strcmp(partition, hes_name)) return NULL; #ifdef DEBUG fprintf(stderr, "A match, munging....\n"); #endif /* DEBUG */ strlcpy(transform, "/home/", sizeof(transform)); strlcat(transform, username, sizeof(transform)); if (*ch) strlcat(transform, ch, sizeof(transform)); #ifdef DEBUG fprintf(stderr, "Munged to <%s>\n", transform); #endif /* DEBUG */ return transform; } return NULL; } #endif /* DISK_HOME_HACK */ /* * The routine transform_dir(path) transforms pathnames of directories * mounted with the amd automounter to produce a more "natural" version. * The automount table is obtained from the local amd via the rpc interface * and reverse lookups are repeatedly performed on the directory name * substituting the name of the automount link for the value of the link * whenever it occurs as a prefix of the directory name. */ static char * transform_dir(char *dir) { #ifdef DISK_HOME_HACK char *ch; #endif /* DISK_HOME_HACK */ char *server; struct sockaddr_in server_addr; int s = RPC_ANYSOCK; CLIENT *clnt; struct hostent *hp; amq_mount_tree_list *mlp; struct timeval tmo = {10, 0}; #ifdef DISK_HOME_HACK if (ch = hack_name(dir)) return ch; #endif /* DISK_HOME_HACK */ #ifdef HAVE_CNODEID server = cluster_server(); #else /* not HAVE_CNODEID */ server = localhost; #endif /* not HAVE_CNODEID */ if ((hp = gethostbyname(server)) == 0) return dir; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr = *(struct in_addr *) hp->h_addr; clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, tmo, &s); if (clnt == 0) return dir; strlcpy(transform, dir, sizeof(transform)); while ((mlp = amqproc_export_1((voidp)0, clnt)) && find_mlp(mlp,transform) ) { strlcpy(transform, newdir, sizeof(transform)); } return transform; } /* getawd() is a substitute for getwd() which transforms the path */ static char * getawd(char *path, size_t l) { #ifdef HAVE_GETCWD char *wd = getcwd(path, MAXPATHLEN+1); #else /* not HAVE_GETCWD */ char *wd = getwd(path); #endif /* not HAVE_GETCWD */ if (wd == NULL) { return NULL; } strlcpy(path, transform_dir(wd), l); return path; } int main(int argc, char *argv[]) { char tmp_buf[MAXPATHLEN], *wd; if (argc == 1) { wd = getawd(tmp_buf, sizeof(tmp_buf)); if (wd == NULL) { fprintf(stderr, "pawd: %s\n", tmp_buf); exit(1); } else { fprintf(stdout, "%s\n", wd); } } else { while (--argc) { wd = transform_dir(*++argv); fprintf(stdout, "%s\n", wd); } } exit(0); }