/* ** OSSP path - Filesystem Path Manipulation ** Copyright (c) 2002 Ralf S. Engelschall ** Copyright (c) 2002 The OSSP Project ** Copyright (c) 2002 Cable & Wireless Deutschland ** ** This file is part of OSSP path, a filesystem path manipulation library ** which can be found at http://www.ossp.org/pkg/lib/path/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** 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. ** ** path_self.c: resolve path to current program */ #include #include #include #include #include #include "path.h" #define PATH_DEFAULT "/bin:/sbin:/usr/bin:/usr/sbin:." path_rc_t path_self(char *res_buf, size_t res_size, const char *argv0) { char *path; size_t l; struct stat sb; char *cpB, *cpE; size_t argv0_len; if (res_buf == NULL || res_size == 0 || argv0 == NULL) return PATH_ERR_ARG; /* determine length of argv[0] */ argv0_len = strlen(argv0); /* short-circuit if argv[0] already contains an absolute path */ if (argv0[0] == '/') { if (argv0_len > res_size-1) return PATH_ERR_MEM; memcpy(res_buf, argv0, argv0_len); res_buf[argv0_len] = '\0'; if (path_resolve(res_buf, res_size, res_buf) == NULL) return PATH_ERR_SYS; return PATH_OK; } /* short-circuit if argv[0] already contains a relative path */ if (argv0[0] == '.') { if (getcwd(res_buf, res_size) == NULL) return PATH_ERR_SYS; l = strlen(res_buf); if (res_buf[l-1] == '/') l--; if (l+1+argv0_len+1 > res_size) return PATH_ERR_MEM; res_buf[l++] = '/'; memcpy(res_buf+l, argv0, argv0_len); res_buf[l+argv0_len] = '\0'; if (path_resolve(res_buf, res_size, res_buf) == NULL) return PATH_ERR_SYS; return PATH_OK; } /* else search for /proc entries (at least possible under Linux and FreeBSD) */ if ((l = readlink("/proc/self/exe", res_buf, res_size-1)) == -1) l = readlink("/proc/curproc/file", res_buf, res_size-1); if (l > 0) { if (res_buf[l-1] == '\0') l--; res_buf[l] = '\0'; if (strcmp(res_buf, "unknown") != 0) if (path_resolve(res_buf, res_size, res_buf) == NULL) return PATH_ERR_SYS; } /* else search argv[0] in $PATH */ if ((path = getenv("PATH")) == NULL) path = PATH_DEFAULT; cpE = path; cpB = cpE; while (*cpE != '\0') { if ((cpE = strchr(cpB, ':')) == NULL) cpE = strchr(cpB, '\0'); if ((l = cpE-cpB) > 0) { if (cpB[l-1] == '/') l--; if (l+1+argv0_len+1 <= res_size) { memcpy(res_buf, cpB, l); res_buf[l++] = '/'; memcpy(res_buf+l, argv0, argv0_len); res_buf[l+argv0_len] = '\0'; if (stat(res_buf, &sb) == 0) { if (path_resolve(res_buf, res_size, res_buf) == NULL) return PATH_ERR_SYS; return PATH_OK; } } } if (*cpE == '\0') break; cpB = cpE+1; } return PATH_ERR_NFD; }