// SPDX-License-Identifier: WTFPL #include #include #include #include #include #include #include #include char **_argv; static int _cmdname_sub(char *out, const char *path, const char *name) { int path_len, name_len; char tmp[PATH_MAX]; struct stat sb; path_len = (path == NULL) ? 0 : (strlen(path) + 1); /* with '/' */ name_len = (name == NULL) ? 0 : strlen(name); if (path_len + name_len >= sizeof(tmp)) abort(); if (path_len) { memcpy(tmp, path, path_len - 1); tmp[path_len - 1] = '/'; } if (name_len) memcpy(tmp + path_len, name, name_len); tmp[path_len + name_len] = '\0'; if (tmp[0] == '/') memcpy(out, tmp, path_len + name_len + 1); else realpath(tmp, out); return stat(out, &sb); } static char *_cmdname_tokenize(char *str, char **next) { char *p; if (*str == '\0') return NULL; if ((p = strchr(str, ':')) == NULL) { *next = str + strlen(str); } else { *p = '\0'; *next = p + 1; } return str; } char *_cmdname(char *name) { int save_errno, envpath_len; char *path, *envpath, *result = NULL; char *p, *pp; save_errno = errno; if ((*_argv[0] == '.' || *_argv[0] == '/') && !_cmdname_sub(name, NULL, _argv[0])) { result = name; goto fin; } if ((envpath = getenv("PATH")) == NULL) goto fin; envpath_len = strlen(envpath) + 1; path = alloca(envpath_len); memcpy(path, envpath, envpath_len); for (p = _cmdname_tokenize(path, &pp); p != NULL; p = _cmdname_tokenize(pp, &pp)) { if (!_cmdname_sub(name, *p == '\0' ? "." : p, getprogname())) { result = name; goto fin; } } fin: errno = save_errno; return result; } char *_cmdname_nbsd(char *name) { int save_errno; int result; save_errno = errno; result = readlink("/proc/self/exe", name, PATH_MAX); if (result == -1) { /* try another way for BSD */ result = readlink("/proc/curproc/exe", name, PATH_MAX); } errno = save_errno; /* fall back to argv[0] if readlink doesn't work */ if (result == -1 || result == PATH_MAX) return strcpy(name, _argv[0]); /* readlink does not add a NUL so we need to do it ourselves */ name[result] = '\0'; return name; } int main(int argc, char *argv[]) { char name0[PATH_MAX], name1[PATH_MAX]; _argv = argv; printf("%s\n", _cmdname_nbsd(name1)); printf("%s\n", _cmdname(name0)); return 0; }