libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-2011, 2013 Peter Miller 00004 * Written by Peter Miller <pmiller@opensource.org.au> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 3 of the License, or (at 00009 * your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <libexplain/ac/dirent.h> 00021 #include <libexplain/ac/limits.h> /* for PATH_MAX on Solaris */ 00022 #include <libexplain/ac/stdio.h> 00023 #include <libexplain/ac/stdlib.h> 00024 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris */ 00025 #include <libexplain/ac/sys/stat.h> 00026 #include <libexplain/ac/unistd.h> 00027 00028 #include <libexplain/buffer/path_to_pid.h> 00029 #include <libexplain/is_same_inode.h> 00030 #include <libexplain/lsof.h> 00031 #include <libexplain/string_buffer.h> 00032 00033 00034 #if (defined(PROC_PID_PATH_CWD) || defined(PROC_PID_CWD)) && \ 00035 (defined(PROC_PID_PATH_ROOT) || defined(PROC_PID_ROOT)) && \ 00036 (defined(PROC_PID_PATH_A_OUT) || defined(PROC_PID_EXE)) && \ 00037 (defined(PROC_PID_PATH_N) || defined(PROC_PID_FD_N)) 00038 #define TRY_PROC_FIRST 1 00039 #endif 00040 00041 00042 #ifdef TRY_PROC_FIRST 00043 00044 static int 00045 snoop_symlink(const char *path, const struct stat *st1) 00046 { 00047 char link_content[PATH_MAX + 1]; 00048 long link_len; 00049 00050 link_len = readlink(path, link_content, sizeof(link_content) - 1); 00051 if (link_len > 0) 00052 { 00053 struct stat st4; 00054 00055 link_content[link_len] = '\0'; 00056 if 00057 ( 00058 lstat(link_content, &st4) == 0 00059 && 00060 explain_is_same_inode(st1, &st4) 00061 ) 00062 return 1; 00063 } 00064 return 0; 00065 } 00066 00067 00068 static int 00069 snoop_process(pid_t pid, const struct stat *st) 00070 { 00071 char path2[100]; 00072 DIR *dp2; 00073 00074 #if defined(PROC_PID_PATH_CWD) 00075 snprintf(path2, sizeof(path2), "/proc/%ld/path/cwd", (long)pid); 00076 if (snoop_symlink(path2, st)) 00077 return 1; 00078 #elif defined(PROC_PID_CWD) 00079 snprintf(path2, sizeof(path2), "/proc/%ld/cwd", (long)pid); 00080 if (snoop_symlink(path2, st)) 00081 return 1; 00082 #endif 00083 00084 #if defined(PROC_PID_PATH_A_OUT) 00085 snprintf(path2, sizeof(path2), "/proc/%d/path/a.out", pid); 00086 if (snoop_symlink(path2, st)) 00087 return 1; 00088 #elif defined(PROC_PID_EXE) 00089 snprintf(path2, sizeof(path2), "/proc/%d/exe", pid); 00090 if (snoop_symlink(path2, st)) 00091 return 1; 00092 #endif 00093 00094 #if defined(PROC_PID_PATH_ROOT) 00095 snprintf(path2, sizeof(path2), "/proc/%d/path/root", pid); 00096 if (snoop_symlink(path2, st)) 00097 return 1; 00098 #elif defined(PROC_PID_ROOT) 00099 snprintf(path2, sizeof(path2), "/proc/%d/root", pid); 00100 if (snoop_symlink(path2, st)) 00101 return 1; 00102 #endif 00103 00104 #if defined(PROC_PID_PATH_N) 00105 snprintf(path2, sizeof(path2), "/proc/%ld/path", (long)pid); 00106 #elif defined(PROC_PID_FD_N) 00107 snprintf(path2, sizeof(path2), "/proc/%ld/fd", (long)pid); 00108 #else 00109 #error oops 00110 #endif 00111 dp2 = opendir(path2); 00112 if (!dp2) 00113 return 0; 00114 for (;;) 00115 { 00116 struct dirent *dep2; 00117 char *ep2; 00118 int fd; 00119 char path3[100]; 00120 00121 dep2 = readdir(dp2); 00122 if (!dep2) 00123 break; 00124 ep2 = 0; 00125 fd = strtol(dep2->d_name, &ep2, 10); 00126 if (ep2 == dep2->d_name || *ep2) 00127 continue; 00128 snprintf(path3, sizeof(path3), "%s/%d", path2, fd); 00129 if (snoop_symlink(path3, st)) 00130 { 00131 closedir(dp2); 00132 return 1; 00133 } 00134 } 00135 closedir(dp2); 00136 return 0; 00137 } 00138 00139 00140 #else /* !TRY_PROC_FIRST */ 00141 00142 00143 typedef struct adapter adapter; 00144 struct adapter 00145 { 00146 explain_lsof_t inherited; 00147 explain_string_buffer_t *sb; 00148 const struct stat *st; 00149 int count; 00150 const char *caption; 00151 }; 00152 00153 00154 static void 00155 n_callback(explain_lsof_t *context, const char *name) 00156 { 00157 adapter *a; 00158 struct stat st; 00159 00160 a = (adapter *)context; 00161 if (lstat(name, &st) >= 0 && explain_is_same_inode(a->st, &st)) 00162 { 00163 if (a->count == 0) 00164 { 00165 if (a->caption) 00166 { 00167 explain_string_buffer_putc(a->sb, ' '); 00168 explain_string_buffer_puts(a->sb, a->caption); 00169 explain_string_buffer_puts(a->sb, " is in use"); 00170 } 00171 explain_string_buffer_puts(a->sb, " (pid"); 00172 } 00173 else 00174 explain_string_buffer_putc(a->sb, ','); 00175 explain_string_buffer_printf(a->sb, " %d", context->pid); 00176 a->count++; 00177 } 00178 } 00179 00180 #endif 00181 00182 00183 static int 00184 stat_to_pid(explain_string_buffer_t *sb, const struct stat *st) 00185 { 00186 #ifdef TRY_PROC_FIRST 00187 int count; 00188 DIR *dp; 00189 00190 count = 0; 00191 dp = opendir("/proc"); 00192 if (!dp) 00193 return -1; 00194 for (;;) 00195 { 00196 struct dirent *dep; 00197 char *ep; 00198 int pid; 00199 00200 dep = readdir(dp); 00201 if (!dep) 00202 break; 00203 ep = 0; 00204 pid = strtol(dep->d_name, &ep, 10); 00205 if (ep == dep->d_name || *ep) 00206 continue; 00207 if (snoop_process(pid, st)) 00208 { 00209 if (count == 0) 00210 explain_string_buffer_puts(sb, " (pid"); 00211 else 00212 explain_string_buffer_putc(sb, ','); 00213 explain_string_buffer_printf(sb, " %d", pid); 00214 ++count; 00215 } 00216 } 00217 closedir(dp); 00218 if (count > 0) 00219 explain_string_buffer_putc(sb, ')'); 00220 return count; 00221 #else 00222 adapter obj; 00223 00224 obj.st = st; 00225 obj.inherited.n_callback = n_callback; 00226 obj.sb = sb; 00227 obj.count = 0; 00228 obj.caption = 0; 00229 explain_lsof("", &obj.inherited); 00230 if (obj.count > 0) 00231 explain_string_buffer_putc(sb, ')'); 00232 return obj.count; 00233 #endif 00234 } 00235 00236 00237 int 00238 explain_buffer_path_to_pid(explain_string_buffer_t *sb, const char *path) 00239 { 00240 struct stat st; 00241 00242 if (lstat(path, &st) < 0) 00243 return -1; 00244 return stat_to_pid(sb, &st); 00245 } 00246 00247 00248 int 00249 explain_buffer_fildes_to_pid(explain_string_buffer_t *sb, int fildes) 00250 { 00251 struct stat st; 00252 00253 if (fstat(fildes, &st) < 0) 00254 return -1; 00255 return stat_to_pid(sb, &st); 00256 } 00257 00258 00259 int 00260 explain_buffer_path_users(explain_string_buffer_t *sb, const char *path, 00261 const char *caption) 00262 { 00263 #ifdef TRY_PROC_FIRST 00264 int count; 00265 struct stat st; 00266 DIR *dp; 00267 00268 if (lstat(path, &st) < 0) 00269 return -1; 00270 count = 0; 00271 dp = opendir("/proc"); 00272 if (!dp) 00273 return -1; 00274 for (;;) 00275 { 00276 struct dirent *dep; 00277 char *ep; 00278 int pid; 00279 00280 dep = readdir(dp); 00281 if (!dep) 00282 break; 00283 ep = 0; 00284 pid = strtol(dep->d_name, &ep, 10); 00285 if (ep == dep->d_name || *ep) 00286 continue; 00287 if (snoop_process(pid, &st)) 00288 { 00289 if (count == 0) 00290 { 00291 explain_string_buffer_putc(sb, ' '); 00292 explain_string_buffer_puts(sb, caption); 00293 explain_string_buffer_puts(sb, " is in use"); 00294 explain_string_buffer_puts(sb, " (pid"); 00295 } 00296 else 00297 explain_string_buffer_putc(sb, ','); 00298 explain_string_buffer_printf(sb, " %d", pid); 00299 ++count; 00300 } 00301 } 00302 closedir(dp); 00303 if (count > 0) 00304 explain_string_buffer_putc(sb, ')'); 00305 return count; 00306 #else 00307 adapter obj; 00308 struct stat st; 00309 00310 if (lstat(path, &st) < 0) 00311 return -1; 00312 obj.st = &st; 00313 obj.inherited.n_callback = n_callback; 00314 obj.sb = sb; 00315 obj.count = 0; 00316 obj.caption = caption; 00317 explain_lsof("", &obj.inherited); 00318 if (obj.count > 0) 00319 explain_string_buffer_putc(sb, ')'); 00320 return obj.count; 00321 #endif 00322 } 00323 00324 00325 /* vim: set ts=8 sw=4 et : */