/**************************************************************************** * libs/libc/misc/lib_envpath.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include "libc.h" #if defined(CONFIG_LIBC_ENVPATH) /**************************************************************************** * Private Types ****************************************************************************/ struct envpath_s { FAR char *next; /* Pointer to the next (unterminated) value in the PATH variable */ char path[1]; }; #define SIZEOF_ENVPATH_S(n) (sizeof(struct envpath_s) + (n) - 1) /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: envpath_init * * Description: * Initialize for the traversal of each value in the PATH variable. The * usage is sequence is as follows: * * 1) Call envpath_init() to initialize for the traversal. envpath_init() * will return an opaque handle that can then be provided to * envpath_next() and envpath_release(). * 2) Call envpath_next() repeatedly to examine every file that lies * in the directories of the PATH variable * 3) Call envpath_release() to free resources set aside by envpath_init(). * * Input Parameters: * None * * Returned Value: * On success, envpath_init() return a non-NULL, opaque handle that may * subsequently be used in calls to envpath_next() and envpath_release(). * On error, a NULL handle value will be returned. The most likely cause * of an error would be that there is no value associated with the PATH * variable. * ****************************************************************************/ ENVPATH_HANDLE envpath_init(FAR const char *name) { FAR struct envpath_s *envpath; FAR char *path; /* Get the value of the PATH variable */ path = getenv(name); if (!path) { /* getenv() will return a NULL value if the PATH variable does not * exist in the environment. */ return (ENVPATH_HANDLE)NULL; } /* Allocate a container for the PATH variable contents */ envpath = (FAR struct envpath_s *) lib_malloc(SIZEOF_ENVPATH_S(strlen(path) + 1)); if (!envpath) { /* Ooops.. we are out of memory */ return (ENVPATH_HANDLE)NULL; } /* Populate the container */ strcpy(envpath->path, path); envpath->next = envpath->path; /* And return the containing cast to an opaque handle */ return (ENVPATH_HANDLE)envpath; } /**************************************************************************** * Name: envpath_next * * Description: * Traverse all possible values in the PATH variable in attempt to find * the full path to an envcutable file when only a relative path is * provided. * * Input Parameters: * handle - The handle value returned by envpath_init * relpath - The relative path to the file to be found. * * Returned Value: * On success, a non-NULL pointer to a null-terminated string is provided. * This is the full path to a file that exists in the file system. This * function will verify that the file exists (but will not verify that it * is marked envcutable). * * NOTE: The string pointer return in the success case points to allocated * memory. This memory must be freed by the called by calling lib_free(). * * NULL is returned if no path is found to any file with the provided * 'relpath' from any absolute path in the PATH variable. In this case, * there is no point in calling envpath_next() further; envpath_release() * must be called to release resources set aside by expath_init(). * ****************************************************************************/ FAR char *envpath_next(ENVPATH_HANDLE handle, FAR const char *relpath) { FAR struct envpath_s *envpath = (FAR struct envpath_s *)handle; struct stat buf; FAR char *endptr; FAR char *path; FAR char *fullpath; int pathlen; int ret; /* Verify that a value handle and relative path were provided */ DEBUGASSERT(envpath && relpath); DEBUGASSERT(relpath[0] != '\0' && relpath[0] != '/'); /* Loop until (1) we find a file with this relative path from one of the * absolute paths in the PATH variable, or (2) all of the absolute paths * in the PATH variable have been considered. */ for (; ; ) { /* Make sure that envpath->next points to the beginning of a string */ path = envpath->next; if (*path == '\0') { /* If it points to a NULL it means that either (1) the PATH * varialbe is empty, or (2) we have already examined all of the * paths in the path variable. */ return (FAR char *)NULL; } /* Okay... 'path' points to the beginning of the string. The string * may be terminated either with (1) ':' which separates the path from * the next path in the list, or (2) NUL which marks the end of the * list. */ endptr = strchr(path, ':'); if (endptr == NULL) { /* If strchr returns NUL it means that ':' does not appear in the * string. Therefore, this must be the final path in the PATH * variable content. */ endptr = &path[strlen(path)]; envpath->next = endptr; DEBUGASSERT(*endptr == '\0'); } else { DEBUGASSERT(*endptr == ':'); envpath->next = endptr + 1; *endptr = '\0'; } pathlen = strlen(path) + strlen(relpath) + 2; fullpath = (FAR char *)lib_malloc(pathlen); if (fullpath == NULL) { /* Failed to allocate memory */ return (FAR char *)NULL; } /* Construct the full path */ sprintf(fullpath, "%s/%s", path, relpath); /* Verify that a regular file exists at this path */ ret = stat(fullpath, &buf); if (ret == OK && S_ISREG(buf.st_mode)) { return fullpath; } /* Failed to stat the file. Just free the allocated memory and * continue to try the next path. */ lib_free(fullpath); } /* We will not get here */ } /**************************************************************************** * Name: envpath_release * * Description: * Release all resources set aside by envpath_init() when the handle value * was created. The handle value is invalid on return from this function. * Attempts to all envpath_next() or envpath_release() with such a 'stale' * handle will result in undefined (i.e., not good) behavior. * * Input Parameters: * handle - The handle value returned by envpath_init * * Returned Value: * None * ****************************************************************************/ void envpath_release(ENVPATH_HANDLE handle) { lib_free(handle); } #endif /* CONFIG_LIBC_ENVPATH */