| /*************************************************************************** |
| * _ _ ____ _ |
| * Project ___| | | | _ \| | |
| * / __| | | | |_) | | |
| * | (__| |_| | _ <| |___ |
| * \___|\___/|_| \_\_____| |
| * |
| * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. |
| * |
| * This software is licensed as described in the file COPYING, which |
| * you should have received as part of this distribution. The terms |
| * are also available at https://curl.se/docs/copyright.html. |
| * |
| * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| * copies of the Software, and permit persons to whom the Software is |
| * furnished to do so, under the terms of the COPYING file. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| * SPDX-License-Identifier: curl |
| * |
| ***************************************************************************/ |
| #include "tool_setup.h" |
| |
| #ifdef HAVE_PWD_H |
| # undef __NO_NET_API /* required for building for AmigaOS */ |
| # include <pwd.h> |
| #endif |
| |
| #ifdef HAVE_SYS_STAT_H |
| #include <sys/stat.h> |
| #endif |
| #ifdef HAVE_FCNTL_H |
| #include <fcntl.h> |
| #endif |
| |
| #include <curl/mprintf.h> |
| |
| #include "tool_findfile.h" |
| |
| #include "memdebug.h" /* keep this as LAST include */ |
| |
| struct finder { |
| const char *env; |
| const char *append; |
| bool withoutdot; |
| }; |
| |
| /* The order of the variables below is important, as the index number is used |
| in the findfile() function */ |
| static const struct finder list[] = { |
| { "CURL_HOME", NULL, FALSE }, |
| { "XDG_CONFIG_HOME", NULL, FALSE }, /* index == 1, used in the code */ |
| { "HOME", NULL, FALSE }, |
| #ifdef WIN32 |
| { "USERPROFILE", NULL, FALSE }, |
| { "APPDATA", NULL, FALSE }, |
| { "USERPROFILE", "\\Application Data", FALSE}, |
| #endif |
| /* these are for .curlrc if XDG_CONFIG_HOME is not defined */ |
| { "CURL_HOME", "/.config", TRUE }, |
| { "HOME", "/.config", TRUE }, |
| |
| { NULL, NULL, FALSE } |
| }; |
| |
| static char *checkhome(const char *home, const char *fname, bool dotscore) |
| { |
| const char pref[2] = { '.', '_' }; |
| int i; |
| for(i = 0; i < (dotscore ? 2 : 1); i++) { |
| char *c; |
| if(dotscore) |
| c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]); |
| else |
| c = curl_maprintf("%s" DIR_CHAR "%s", home, fname); |
| if(c) { |
| int fd = open(c, O_RDONLY); |
| if(fd >= 0) { |
| char *path = strdup(c); |
| close(fd); |
| curl_free(c); |
| return path; |
| } |
| curl_free(c); |
| } |
| } |
| return NULL; |
| } |
| |
| /* |
| * findfile() - return the full path name of the file. |
| * |
| * If 'dotscore' is TRUE, then check for the file first with a leading dot |
| * and then with a leading underscore. |
| * |
| * 1. Iterate over the environment variables in order, and if set, check for |
| * the given file to be accessed there, then it is a match. |
| * 2. Non-windows: try getpwuid |
| */ |
| char *findfile(const char *fname, int dotscore) |
| { |
| int i; |
| bool xdg = FALSE; |
| DEBUGASSERT(fname && fname[0]); |
| DEBUGASSERT((dotscore != 1) || (fname[0] == '.')); |
| |
| if(!fname[0]) |
| return NULL; |
| |
| for(i = 0; list[i].env; i++) { |
| char *home = curl_getenv(list[i].env); |
| if(home) { |
| char *path; |
| const char *filename = fname; |
| if(i == 1 /* XDG_CONFIG_HOME */) |
| xdg = TRUE; |
| if(!home[0]) { |
| curl_free(home); |
| continue; |
| } |
| if(list[i].append) { |
| char *c = curl_maprintf("%s%s", home, list[i].append); |
| curl_free(home); |
| if(!c) |
| return NULL; |
| home = c; |
| } |
| if(list[i].withoutdot) { |
| if(!dotscore || xdg) { |
| /* this is not looking for .curlrc, or the XDG_CONFIG_HOME was |
| defined so we skip the extended check */ |
| curl_free(home); |
| continue; |
| } |
| filename++; /* move past the leading dot */ |
| dotscore = 0; /* disable it for this check */ |
| } |
| path = checkhome(home, filename, dotscore ? dotscore - 1 : 0); |
| curl_free(home); |
| if(path) |
| return path; |
| } |
| } |
| #if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) |
| { |
| struct passwd *pw = getpwuid(geteuid()); |
| if(pw) { |
| char *home = pw->pw_dir; |
| if(home && home[0]) |
| return checkhome(home, fname, FALSE); |
| } |
| } |
| #endif /* PWD-stuff */ |
| return NULL; |
| } |