libexplain  1.4.D001
libexplain/buffer/path_to_pid.c
Go to the documentation of this file.
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 : */