summaryrefslogtreecommitdiff
path: root/usr/src/lib/libast/common/preroot/getpreroot.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libast/common/preroot/getpreroot.c')
-rw-r--r--usr/src/lib/libast/common/preroot/getpreroot.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/usr/src/lib/libast/common/preroot/getpreroot.c b/usr/src/lib/libast/common/preroot/getpreroot.c
new file mode 100644
index 0000000000..a35915d52d
--- /dev/null
+++ b/usr/src/lib/libast/common/preroot/getpreroot.c
@@ -0,0 +1,165 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* A copy of the License is available at *
+* http://www.opensource.org/licenses/cpl1.0.txt *
+* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* David Korn <dgk@research.att.com> *
+* Phong Vo <kpv@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * AT&T Bell Laboratories
+ * return the real absolute pathname of the preroot dir for cmd
+ * if cmd==0 then current preroot path returned
+ */
+
+#include <ast.h>
+#include <preroot.h>
+
+#if FS_PREROOT
+
+#include <ast_dir.h>
+#include <ls.h>
+#include <error.h>
+#include <stdio.h>
+
+#ifndef ERANGE
+#define ERANGE E2BIG
+#endif
+
+#define ERROR(e) {errno=e;goto error;}
+
+char*
+getpreroot(char* path, const char* cmd)
+{
+ register int c;
+ register FILE* fp;
+ register char* p;
+ char buf[PATH_MAX];
+
+ if (!path) path = buf;
+ if (cmd)
+ {
+ sfsprintf(buf, sizeof(buf), "set x `%s= %s - </dev/null 2>&1`\nwhile :\ndo\nshift\ncase $# in\n[012]) break ;;\nesac\ncase \"$1 $2\" in\n\"+ %s\") echo $3; exit ;;\nesac\ndone\necho\n", PR_SILENT, cmd, PR_COMMAND);
+ if (!(fp = popen(buf, "rug"))) return(0);
+ for (p = path; (c = getc(fp)) != EOF && c != '\n'; *p++ = c);
+ *p = 0;
+ pclose(fp);
+ if (path == p) return(0);
+ return(path == buf ? strdup(path) : path);
+ }
+ else
+ {
+ char* d;
+ DIR* dirp = 0;
+ int namlen;
+ int euid;
+ int ruid;
+ struct dirent* entry;
+ struct stat* cur;
+ struct stat* par;
+ struct stat* tmp;
+ struct stat curst;
+ struct stat parst;
+ struct stat tstst;
+ char dots[PATH_MAX];
+
+ cur = &curst;
+ par = &parst;
+ if ((ruid = getuid()) != (euid = geteuid())) setuid(ruid);
+ if (stat(PR_REAL, cur) || stat("/", par) || cur->st_dev == par->st_dev && cur->st_ino == par->st_ino) ERROR(ENOTDIR);
+
+ /*
+ * like getcwd() but starting at the preroot
+ */
+
+ d = dots;
+ *d++ = '/';
+ p = path + PATH_MAX - 1;
+ *p = 0;
+ for (;;)
+ {
+ tmp = cur;
+ cur = par;
+ par = tmp;
+ if ((d - dots) > (PATH_MAX - 4)) ERROR(ERANGE);
+ *d++ = '.';
+ *d++ = '.';
+ *d = 0;
+ if (!(dirp = opendir(dots))) ERROR(errno);
+#if !_dir_ok || _mem_dd_fd_DIR
+ if (fstat(dirp->dd_fd, par)) ERROR(errno);
+#else
+ if (stat(dots, par)) ERROR(errno);
+#endif
+ *d++ = '/';
+ if (par->st_dev == cur->st_dev)
+ {
+ if (par->st_ino == cur->st_ino)
+ {
+ closedir(dirp);
+ *--p = '/';
+ if (ruid != euid) setuid(euid);
+ if (path == buf) return(strdup(p));
+ if (path != p)
+ {
+ d = path;
+ while (*d++ = *p++);
+ }
+ return(path);
+ }
+#ifdef D_FILENO
+ while (entry = readdir(dirp))
+ if (D_FILENO(entry) == cur->st_ino)
+ {
+ namlen = D_NAMLEN(entry);
+ goto found;
+ }
+#endif
+
+ /*
+ * this fallthrough handles logical naming
+ */
+
+ rewinddir(dirp);
+ }
+ do
+ {
+ if (!(entry = readdir(dirp))) ERROR(ENOENT);
+ namlen = D_NAMLEN(entry);
+ if ((d - dots) > (PATH_MAX - 1 - namlen)) ERROR(ERANGE);
+ memcpy(d, entry->d_name, namlen + 1);
+ if (stat(dots, &tstst)) ERROR(errno);
+ } while (tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
+ found:
+ if (*p) *--p = '/';
+ if ((p -= namlen) <= (path + 1)) ERROR(ERANGE);
+ memcpy(p, entry->d_name, namlen);
+ closedir(dirp);
+ dirp = 0;
+ }
+ error:
+ if (dirp) closedir(dirp);
+ if (ruid != euid) setuid(euid);
+ }
+ return(0);
+}
+
+#else
+
+NoN(getpreroot)
+
+#endif