diff --git a/fs/vfs/main.c b/fs/vfs/main.c index 43420b9b0e6e15abe2553fb1e5d958b0b563566a..4bc5a5155dad13f2d0b98e2267d52976eb45a0d3 100755 --- a/fs/vfs/main.c +++ b/fs/vfs/main.c @@ -646,6 +646,12 @@ int __lxstat(int ver, const char *pathname, struct stat *st) } LFS64(__lxstat); +int lstat(const char *pathname, struct stat *st) +{ + return __lxstat(1, pathname, st); +} +LFS64(lstat); + int __statfs(const char *pathname, struct statfs *buf) { struct task *t = main_task; diff --git a/include/osv/mutex.h b/include/osv/mutex.h index 5e00a105da5cbf5922ac99f73506b3e1e62ff1b4..3913e8204472e0b2d3e00abd52e1e85a44610974 100644 --- a/include/osv/mutex.h +++ b/include/osv/mutex.h @@ -2,6 +2,7 @@ #define MUTEX_H_ #include <stdbool.h> +#include <string.h> #ifdef __cplusplus extern "C" { @@ -32,6 +33,7 @@ void mutex_unlock(mutex_t* m); static __always_inline void mutex_init(mutex_t* m) { + memset(m, 0, sizeof(*m)); } static __always_inline void mutex_destroy(mutex_t* m) diff --git a/libc/build.mak b/libc/build.mak index 95d8dab907d755968aae3efc1bba197337d33766..c6a7c23adf8a45c8d2b91fa73e4bd18c748a76b8 100644 --- a/libc/build.mak +++ b/libc/build.mak @@ -6,7 +6,6 @@ libc += internal/libc.o libc += internal/__lock.o libc += internal/shgetc.o -libc += ctype/__ctype_b_loc.o libc += ctype/__ctype_get_mb_cur_max.o libc += ctype/__ctype_tolower_loc.o libc += ctype/__ctype_toupper_loc.o @@ -44,6 +43,15 @@ libc += ctype/wcswidth.o libc += ctype/wctrans.o libc += ctype/wcwidth.o +libc += env/__environ.o +libc += env/clearenv.o +libc += env/getenv.o +libc += env/putenv.o +libc += env/setenv.o +libc += env/unsetenv.o + +libc += ctype/__ctype_b_loc.o + libc += errno/strerror.o libc += exit/assert.o @@ -329,6 +337,7 @@ libc += misc/getopt_long.o libc += misc/getresuid.o libc += misc/getresgid.o libc += misc/getsubopt.o +libc += misc/realpath.o libc += misc/setdomainname.o libc += multibyte/btowc.o diff --git a/libc/env/__environ.c b/libc/env/__environ.c new file mode 100644 index 0000000000000000000000000000000000000000..37d5160c04d4cbd3c001ac51685acd2364749dba --- /dev/null +++ b/libc/env/__environ.c @@ -0,0 +1,9 @@ +#include "libc.h" + +static char *__initial_environ = NULL; + +#undef environ +char **__environ = &__initial_environ; +weak_alias(__environ, ___environ); +weak_alias(__environ, _environ); +weak_alias(__environ, environ); diff --git a/libc/env/clearenv.c b/libc/env/clearenv.c new file mode 100644 index 0000000000000000000000000000000000000000..a2475ce76cef3be53299676568fb6f414d4a1a03 --- /dev/null +++ b/libc/env/clearenv.c @@ -0,0 +1,9 @@ +#include <stdlib.h> + +extern char **__environ; + +int clearenv() +{ + __environ[0] = 0; + return 0; +} diff --git a/libc/env/getenv.c b/libc/env/getenv.c new file mode 100644 index 0000000000000000000000000000000000000000..5317efdbf258645764bbef32fbc7b70972a2db64 --- /dev/null +++ b/libc/env/getenv.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "libc.h" + +char *getenv(const char *name) +{ + int i; + size_t l = strlen(name); + + if (!__environ || !*name || strchr(name, '=')) return NULL; + for (i=0; __environ[i] && (strncmp(name, __environ[i], l) + || __environ[i][l] != '='); i++); + if (__environ[i]) return __environ[i] + l+1; + return NULL; +} diff --git a/libc/env/putenv.c b/libc/env/putenv.c new file mode 100644 index 0000000000000000000000000000000000000000..d141db138893c55f3c13575f794817d75b001b7f --- /dev/null +++ b/libc/env/putenv.c @@ -0,0 +1,59 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +extern char **__environ; +char **__env_map; + +int __putenv(char *s, int a) +{ + int i=0, j=0; + char *z = strchr(s, '='); + char **newenv = 0; + char **newmap = 0; + static char **oldenv; + + if (!z) return unsetenv(s); + if (z==s) return -1; + for (; __environ[i] && memcmp(s, __environ[i], z-s+1); i++); + if (a) { + if (!__env_map) { + __env_map = calloc(2, sizeof(char *)); + if (__env_map) __env_map[0] = s; + } else { + for (; __env_map[j] && __env_map[j] != __environ[i]; j++); + if (!__env_map[j]) { + newmap = realloc(__env_map, sizeof(char *)*(j+2)); + if (newmap) { + __env_map = newmap; + __env_map[j] = s; + __env_map[j+1] = NULL; + } + } else { + free(__env_map[j]); + } + } + } + if (!__environ[i]) { + newenv = malloc(sizeof(char *)*(i+2)); + if (!newenv) { + if (a && __env_map) __env_map[j] = 0; + return -1; + } + memcpy(newenv, __environ, sizeof(char *)*i); + newenv[i] = s; + newenv[i+1] = 0; + __environ = newenv; + free(oldenv); + oldenv = __environ; + } + + __environ[i] = s; + return 0; +} + +int putenv(char *s) +{ + return __putenv(s, 0); +} diff --git a/libc/env/setenv.c b/libc/env/setenv.c new file mode 100644 index 0000000000000000000000000000000000000000..c2c25444cbbd069c1eb99cd9f9ec8a57be0d18ce --- /dev/null +++ b/libc/env/setenv.c @@ -0,0 +1,31 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +int __putenv(char *s, int a); + +int setenv(const char *var, const char *value, int overwrite) +{ + char *s; + int l1, l2; + + if (!var || !*var || strchr(var, '=')) { + errno = EINVAL; + return -1; + } + if (!overwrite && getenv(var)) return 0; + + l1 = strlen(var); + l2 = strlen(value); + s = malloc(l1+l2+2); + memcpy(s, var, l1); + s[l1] = '='; + memcpy(s+l1+1, value, l2); + s[l1+l2+1] = 0; + if (__putenv(s, 1)) { + free(s); + errno = ENOMEM; + return -1; + } + return 0; +} diff --git a/libc/env/unsetenv.c b/libc/env/unsetenv.c new file mode 100644 index 0000000000000000000000000000000000000000..7493d97084dd4480b2589464d56791c6ab917926 --- /dev/null +++ b/libc/env/unsetenv.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +extern char **__environ; +extern char **__env_map; + +int unsetenv(const char *name) +{ + int i, j; + size_t l = strlen(name); + + if (!*name || strchr(name, '=')) { + errno = EINVAL; + return -1; + } +again: + for (i=0; __environ[i] && (memcmp(name, __environ[i], l) || __environ[i][l] != '='); i++); + if (__environ[i]) { + if (__env_map) { + for (j=0; __env_map[j] && __env_map[j] != __environ[i]; j++); + free (__env_map[j]); + for (; __env_map[j]; j++) + __env_map[j] = __env_map[j+1]; + } + for (; __environ[i]; i++) + __environ[i] = __environ[i+1]; + goto again; + } + return 0; +} diff --git a/libc/internal/libc.h b/libc/internal/libc.h index 6d48bcb0963ab7e925eddc89cfd820a311bde390..3deff59ee9ad8922435990989c23969b7c1303dd 100644 --- a/libc/internal/libc.h +++ b/libc/internal/libc.h @@ -37,6 +37,9 @@ void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY; #define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1)) #define UNLOCK(x) (libc.threads_minus_1 ? (__unlock(x),1) : ((void)(x),1)) +extern char **__environ; +#define environ __environ + #undef weak_alias #define weak_alias(old, new) \ extern __typeof(old) new __attribute__((weak, alias(#old))) diff --git a/libc/libc.cc b/libc/libc.cc index 9cce265e9f1c43187a4ee81d56057795f7fb3588..dce126c40057fa3a65e5d73e534489e8fde25d73 100644 --- a/libc/libc.cc +++ b/libc/libc.cc @@ -26,47 +26,6 @@ int* __errno_location() return &errno; } -char* realpath(const char* path, char* resolved_path) -{ - // assumes cwd == / - std::vector<std::string> components; - std::string spath = path; - boost::split(components, spath, [] (char c) { return c == '/'; }); - std::vector<std::string> tmp; - for (auto c : components) { - if (c == "" || c == ".") { - continue; - } else if (c == "..") { - if (!tmp.empty()) { - tmp.pop_back(); - } - } else { - tmp.push_back(c); - } - } - std::string ret; - for (auto c : tmp) { - ret += "/" + c; - } - ret = ret.substr(0, PATH_MAX - 1); - if (!resolved_path) { - resolved_path = static_cast<char*>(malloc(ret.size() + 1)); - } - strcpy(resolved_path, ret.c_str()); - return resolved_path; -} - -char* getenv(const char* name) -{ - // no environment - return NULL; -} - -int putenv(char* string) -{ - return 0; // no environent -} - int getrlimit(int resource, struct rlimit *rlim) { auto set = [=] (rlim_t r) { rlim->rlim_cur = rlim->rlim_max = r; }; diff --git a/libc/manifest.txt b/libc/manifest.txt index c205b49598df4a4d0311ef87943a92787762dca0..b91e89200c16fde5b7855f02268e330ef52df99a 100644 --- a/libc/manifest.txt +++ b/libc/manifest.txt @@ -5,6 +5,7 @@ All the files under the following directories are imported from musl: errno string ctype + env exit internal locale @@ -18,12 +19,17 @@ All the files under the following directories are imported from musl: time unistd -With the exceptions of: +With the following exceptions: + +1) written locally largely based on musl code: stdio/__fprintf_chk.c string/rawmemchr.c -which were written locally largely based on musl code. +2) imported from FreeBSD: + + misc/realpath.c + All imports are from musl.git commit f05f59b804f83ff8443ba8c549d6be3ba79e71a6 and have various local modification to deal with OSv specifics or our diff --git a/libc/misc/realpath.c b/libc/misc/realpath.c new file mode 100644 index 0000000000000000000000000000000000000000..8fe0e9ec14ee66dd2d3065bcdb3513d5b294b7aa --- /dev/null +++ b/libc/misc/realpath.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> + * + * 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. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/stat.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <osv/prex.h> /* for strlcpy / strlcat */ + +/* + * Find the real name of path, by removing all ".", ".." and symlink + * components. Returns (resolved) on success, or (NULL) on failure, + * in which case the path which caused trouble is left in (resolved). + */ +char * +realpath(const char * __restrict path, char * __restrict resolved) +{ + struct stat sb; + char *p, *q, *s; + size_t left_len, resolved_len; + unsigned symlinks; + int m, slen; + char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; + + if (path == NULL) { + errno = EINVAL; + return (NULL); + } + if (path[0] == '\0') { + errno = ENOENT; + return (NULL); + } + if (resolved == NULL) { + resolved = malloc(PATH_MAX); + if (resolved == NULL) + return (NULL); + m = 1; + } else + m = 0; + symlinks = 0; + if (path[0] == '/') { + resolved[0] = '/'; + resolved[1] = '\0'; + if (path[1] == '\0') + return (resolved); + resolved_len = 1; + left_len = strlcpy(left, path + 1, sizeof(left)); + } else { + if (getcwd(resolved, PATH_MAX) == NULL) { + if (m) + free(resolved); + else { + resolved[0] = '.'; + resolved[1] = '\0'; + } + return (NULL); + } + resolved_len = strlen(resolved); + left_len = strlcpy(left, path, sizeof(left)); + } + if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + + /* + * Iterate over path components in `left'. + */ + while (left_len != 0) { + /* + * Extract the next path component and adjust `left' + * and its length. + */ + p = strchr(left, '/'); + s = p ? p : left + left_len; + if (s - left >= sizeof(next_token)) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + memcpy(next_token, left, s - left); + next_token[s - left] = '\0'; + left_len -= s - left; + if (p != NULL) + memmove(left, s + 1, left_len + 1); + if (resolved[resolved_len - 1] != '/') { + if (resolved_len + 1 >= PATH_MAX) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + resolved[resolved_len++] = '/'; + resolved[resolved_len] = '\0'; + } + if (next_token[0] == '\0') { + /* + * Handle consequential slashes. The path + * before slash shall point to a directory. + * + * Only the trailing slashes are not covered + * by other checks in the loop, but we verify + * the prefix for any (rare) "//" or "/\0" + * occurence to not implement lookahead. + */ + if (lstat(resolved, &sb) != 0) { + if (m) + free(resolved); + return (NULL); + } + if (!S_ISDIR(sb.st_mode)) { + if (m) + free(resolved); + errno = ENOTDIR; + return (NULL); + } + continue; + } + else if (strcmp(next_token, ".") == 0) + continue; + else if (strcmp(next_token, "..") == 0) { + /* + * Strip the last path component except when we have + * single "/" + */ + if (resolved_len > 1) { + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + continue; + } + + /* + * Append the next path component and lstat() it. + */ + resolved_len = strlcat(resolved, next_token, PATH_MAX); + if (resolved_len >= PATH_MAX) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + if (lstat(resolved, &sb) != 0) { + if (m) + free(resolved); + return (NULL); + } + if (S_ISLNK(sb.st_mode)) { + if (symlinks++ > MAXSYMLINKS) { + if (m) + free(resolved); + errno = ELOOP; + return (NULL); + } + slen = readlink(resolved, symlink, sizeof(symlink) - 1); + if (slen < 0) { + if (m) + free(resolved); + return (NULL); + } + symlink[slen] = '\0'; + if (symlink[0] == '/') { + resolved[1] = 0; + resolved_len = 1; + } else if (resolved_len > 1) { + /* Strip the last path component. */ + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + + /* + * If there are any path components left, then + * append them to symlink. The result is placed + * in `left'. + */ + if (p != NULL) { + if (symlink[slen - 1] != '/') { + if (slen + 1 >= sizeof(symlink)) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + symlink[slen] = '/'; + symlink[slen + 1] = 0; + } + left_len = strlcat(symlink, left, + sizeof(symlink)); + if (left_len >= sizeof(left)) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + } + left_len = strlcpy(left, symlink, sizeof(left)); + } + } + + /* + * Remove trailing slash except when the resolved pathname + * is a single "/". + */ + if (resolved_len > 1 && resolved[resolved_len - 1] == '/') + resolved[resolved_len - 1] = '\0'; + return (resolved); +}