net-snmp 5.7
|
00001 /* Portions of this file are subject to the following copyright(s). See 00002 * the Net-SNMP's COPYING file for more details and other copyrights 00003 * that may apply: 00004 */ 00005 /* 00006 * Portions of this file are copyrighted by: 00007 * Copyright (C) 2007 Apple, Inc. All rights reserved. 00008 * Use is subject to license terms specified in the COPYING file 00009 * distributed with the Net-SNMP package. 00010 */ 00011 #include <net-snmp/net-snmp-config.h> 00012 #include <net-snmp/net-snmp-features.h> 00013 #include <net-snmp/net-snmp-includes.h> 00014 00015 #include <stdio.h> 00016 #include <ctype.h> 00017 #if HAVE_STDLIB_H 00018 # include <stdlib.h> 00019 #endif 00020 #if HAVE_UNISTD_H 00021 # include <unistd.h> 00022 #endif 00023 #if HAVE_STRING_H 00024 # include <string.h> 00025 #else 00026 # include <strings.h> 00027 #endif 00028 00029 #include <sys/types.h> 00030 #if HAVE_LIMITS_H 00031 #include <limits.h> 00032 #endif 00033 #if HAVE_SYS_STAT_H 00034 #include <sys/stat.h> 00035 #endif 00036 #ifdef HAVE_DIRENT_H 00037 #include <dirent.h> 00038 #endif 00039 00040 #include <errno.h> 00041 00042 #if HAVE_DMALLOC_H 00043 # include <dmalloc.h> 00044 #endif 00045 00046 #include <net-snmp/types.h> 00047 #include <net-snmp/library/container.h> 00048 #include <net-snmp/library/file_utils.h> 00049 #include <net-snmp/library/dir_utils.h> 00050 00051 netsnmp_feature_child_of(container_directory, container_types) 00052 #ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_DIRECTORY 00053 netsnmp_feature_require(file_utils) 00054 netsnmp_feature_require(container_free_all) 00055 #endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_DIRECTORY */ 00056 00057 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_DIRECTORY 00058 static int 00059 _insert_nsfile( netsnmp_container *c, const char *name, struct stat *stats, 00060 u_int flags); 00061 00062 /* 00063 * read file names in a directory, with an optional filter 00064 */ 00065 netsnmp_container * 00066 netsnmp_directory_container_read_some(netsnmp_container *user_container, 00067 const char *dirname, 00068 netsnmp_directory_filter *filter, 00069 void *filter_ctx, u_int flags) 00070 { 00071 DIR *dir; 00072 netsnmp_container *container = user_container, *tmp_c; 00073 struct dirent *file; 00074 char path[SNMP_MAXPATH]; 00075 size_t dirname_len; 00076 int rc; 00077 struct stat statbuf; 00078 netsnmp_file ns_file_tmp; 00079 00080 if ((flags & NETSNMP_DIR_RELATIVE_PATH) && (flags & NETSNMP_DIR_RECURSE)) { 00081 DEBUGMSGTL(("directory:container", 00082 "no support for relative path with recursion\n")); 00083 return NULL; 00084 } 00085 00086 DEBUGMSGTL(("directory:container", "reading %s\n", dirname)); 00087 00088 /* 00089 * create the container, if needed 00090 */ 00091 if (NULL == container) { 00092 if (flags & NETSNMP_DIR_NSFILE) { 00093 container = netsnmp_container_find("nsfile_directory_container:" 00094 "binary_array"); 00095 if (container) { 00096 container->compare = (netsnmp_container_compare*) 00097 netsnmp_file_compare_name; 00098 container->free_item = (netsnmp_container_obj_func *) 00099 netsnmp_file_container_free; 00100 } 00101 } 00102 else 00103 container = netsnmp_container_find("directory_container:cstring"); 00104 if (NULL == container) 00105 return NULL; 00106 container->container_name = strdup(dirname); 00108 if (! (flags & NETSNMP_DIR_SORTED)) 00109 CONTAINER_SET_OPTIONS(container, CONTAINER_KEY_UNSORTED, rc); 00110 } 00111 00112 dir = opendir(dirname); 00113 if (NULL == dir) { 00114 DEBUGMSGTL(("directory:container", " not a dir\n")); 00115 if (container != user_container) 00116 netsnmp_directory_container_free(container); 00117 return NULL; 00118 } 00119 00121 if (flags & NETSNMP_DIR_RELATIVE_PATH) 00122 dirname_len = 0; 00123 else { 00124 dirname_len = strlen(dirname); 00125 strncpy(path, dirname, sizeof(path)); 00126 if ((dirname_len + 2) > sizeof(path)) { 00128 closedir(dir); 00129 if (container != user_container) 00130 netsnmp_directory_container_free(container); 00131 return NULL; 00132 } 00133 path[dirname_len] = '/'; 00134 path[++dirname_len] = 0; 00135 } 00136 00138 while ((file = readdir(dir))) { 00139 00140 if ((file->d_name == NULL) || (file->d_name[0] == 0)) 00141 continue; 00142 00144 if ((file->d_name[0] == '.') && 00145 ((file->d_name[1] == 0) || 00146 ((file->d_name[1] == '.') && ((file->d_name[2] == 0))))) 00147 continue; 00148 00149 strncpy(&path[dirname_len], file->d_name, sizeof(path) - dirname_len); 00150 if (NULL != filter) { 00151 if (flags & NETSNMP_DIR_NSFILE_STATS) { 00153 if (stat(path, &statbuf) != 0) { 00154 snmp_log(LOG_ERR, "could not stat %s\n", file->d_name); 00155 break; 00156 } 00157 ns_file_tmp.stats = &statbuf; 00158 ns_file_tmp.name = path; 00159 rc = (*filter)(&ns_file_tmp, filter_ctx); 00160 } 00161 else 00162 rc = (*filter)(path, filter_ctx); 00163 if (0 == rc) { 00164 DEBUGMSGTL(("directory:container:filtered", "%s\n", 00165 file->d_name)); 00166 continue; 00167 } 00168 } 00169 00170 DEBUGMSGTL(("directory:container:found", "%s\n", path)); 00171 if ((flags & NETSNMP_DIR_RECURSE) 00172 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DT_DIR) 00173 && (file->d_type == DT_DIR) 00174 #elif defined(S_ISDIR) 00175 && (stat(file->d_name, &statbuf) != 0) && (S_ISDIR(statbuf.st_mode)) 00176 #endif 00177 ) { 00179 tmp_c = netsnmp_directory_container_read(container, path, flags); 00180 } 00181 else if (flags & NETSNMP_DIR_NSFILE) { 00182 if (_insert_nsfile( container, file->d_name, 00183 filter ? &statbuf : NULL, flags ) < 0) 00184 break; 00185 } 00186 else { 00187 char *dup = strdup(path); 00188 if (NULL == dup) { 00189 snmp_log(LOG_ERR, 00190 "strdup failed while building directory container\n"); 00191 break; 00192 } 00193 rc = CONTAINER_INSERT(container, dup); 00194 if (-1 == rc ) { 00195 DEBUGMSGTL(("directory:container", " err adding %s\n", path)); 00196 free(dup); 00197 } 00198 } 00199 } /* while */ 00200 00201 closedir(dir); 00202 00203 rc = CONTAINER_SIZE(container); 00204 DEBUGMSGTL(("directory:container", " container now has %d items\n", rc)); 00205 if ((0 == rc) && !(flags & NETSNMP_DIR_EMPTY_OK)) { 00206 netsnmp_directory_container_free(container); 00207 return NULL; 00208 } 00209 00210 return container; 00211 } 00212 00213 void 00214 netsnmp_directory_container_free(netsnmp_container *container) 00215 { 00216 CONTAINER_FREE_ALL(container, NULL); 00217 CONTAINER_FREE(container); 00218 } 00219 00220 static int 00221 _insert_nsfile( netsnmp_container *c, const char *name, struct stat *stats, 00222 u_int flags) 00223 { 00224 int rc; 00225 netsnmp_file *ns_file = netsnmp_file_new(name, 0, 0, 0); 00226 if (NULL == ns_file) { 00227 snmp_log(LOG_ERR, "error creating ns_file\n"); 00228 return -1; 00229 } 00230 00231 if (flags & NETSNMP_DIR_NSFILE_STATS) { 00232 ns_file->stats = (struct stat*)calloc(1,sizeof(*(ns_file->stats))); 00233 if (NULL == ns_file->stats) { 00234 snmp_log(LOG_ERR, "error creating stats for ns_file\n"); 00235 netsnmp_file_release(ns_file); 00236 return -1; 00237 } 00238 00240 if (stats) 00241 memcpy(ns_file->stats, stats, sizeof(*stats)); 00242 else 00243 stat(ns_file->name, ns_file->stats); 00244 } 00245 00246 rc = CONTAINER_INSERT(c, ns_file); 00247 if (-1 == rc ) { 00248 DEBUGMSGTL(("directory:container", " err adding %s\n", name)); 00249 netsnmp_file_release(ns_file); 00250 } 00251 00252 return 0; 00253 } 00254 #else /* NETSNMP_FEATURE_REMOVE_CONTAINER_DIRECTORY */ 00255 netsnmp_feature_unused(container_directory); 00256 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_DIRECTORY */