libexplain
1.4.D001
|
00001 /* 00002 * libexplain - a library of system-call-specific strerror replacements 00003 * Copyright (C) 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 it 00007 * 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 your 00009 * option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, but WITHOUT 00012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00014 * 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/fcntl.h> 00021 #include <libexplain/ac/limits.h> /* for PATH_MAX except Solaris */ 00022 #include <libexplain/ac/stdio.h> 00023 #include <libexplain/ac/string.h> 00024 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris */ 00025 #include <libexplain/ac/unistd.h> 00026 00027 #include <libexplain/fileinfo.h> 00028 #include <libexplain/lsof.h> 00029 00030 00031 static int 00032 proc_pid_exe(pid_t pid, char *data, size_t data_size) 00033 { 00034 #ifdef PROC_PID_CMDLINE 00035 { 00036 int fd; 00037 char path[100]; 00038 00039 snprintf(path, sizeof(path), "/proc/%ld/cmdline", (long)pid); 00040 fd = open(path, O_RDONLY); 00041 if (fd >= 0) 00042 { 00043 ssize_t n; 00044 00045 n = read(fd, data, data_size); 00046 close(fd); 00047 if (n > 0) 00048 { 00049 char *cp; 00050 00051 /* 00052 * The data consists of each command line argument, and each is 00053 * terminated by a NUL character, not a space. Since we only 00054 * care about the first one (argv[0], the command name) we just 00055 * proceed as if there was only the one C string present. 00056 */ 00057 cp = memchr(data, '\0', n); 00058 if (cp) 00059 { 00060 return 1; 00061 } 00062 } 00063 } 00064 } 00065 #endif 00066 #if defined(PROC_PID_PATH_A_OUT) 00067 if (data_size >= 2) 00068 { 00069 int n; 00070 char path[100]; 00071 00072 snprintf(path, sizeof(path), "/proc/%ld/path/a.out", (long)pid); 00073 n = readlink(path, data, data_size - 1); 00074 if (n > 0 && data[0] == '/') 00075 { 00076 data[n] = '\0'; 00077 return 1; 00078 } 00079 } 00080 #elif defined(PROC_PID_EXE) 00081 if (data_size >= 2) 00082 { 00083 int n; 00084 char path[100]; 00085 00086 snprintf(path, sizeof(path), "/proc/%ld/exe", (long)pid); 00087 n = readlink(path, data, data_size - 1); 00088 if (n > 0 && data[0] == '/') 00089 { 00090 data[n] = '\0'; 00091 return 1; 00092 } 00093 } 00094 #else 00095 (void)pid; 00096 (void)data; 00097 (void)data_size; 00098 #endif 00099 00100 /* 00101 * Sorry, can't help you. 00102 */ 00103 return 0; 00104 } 00105 00106 00107 typedef struct adapter adapter; 00108 struct adapter 00109 { 00110 explain_lsof_t inherited; 00111 char *data; 00112 size_t data_size; 00113 int count; 00114 }; 00115 00116 00117 static void 00118 n_callback(explain_lsof_t *context, const char *name) 00119 { 00120 if (context->fildes == LIBEXPLAIN_LSOF_FD_txt) 00121 { 00122 /* 00123 * Sometimes lsof(1) is less than helpful, and says "exe (readlink: 00124 * Permission denied)" which is effectively no answer at all. 00125 */ 00126 if (0 == strstr(name, "exe (readlink:")) 00127 { 00128 adapter *a; 00129 00130 a = (adapter *)context; 00131 if (a->count == 0) 00132 { 00133 explain_strendcpy(a->data, name, a->data + a->data_size); 00134 a->count++; 00135 } 00136 } 00137 } 00138 } 00139 00140 00141 int 00142 explain_fileinfo_pid_exe(pid_t pid, char *data, size_t data_size) 00143 { 00144 /* 00145 * First, try to do it the easy way, through /proc 00146 */ 00147 if (proc_pid_exe(pid, data, data_size)) 00148 { 00149 return 1; 00150 } 00151 00152 /* 00153 * It is possible that /proc didn't work. Maybe ./configure 00154 * was fooled, or it could be that /proc worked in the build 00155 * environment, but it isn't available or doesn't work in the 00156 * runtime environment (e.g. chroot jails). 00157 * 00158 * Try lsof(1) instead. 00159 */ 00160 { 00161 adapter obj; 00162 char options[40]; 00163 00164 obj.inherited.n_callback = n_callback; 00165 obj.data = data; 00166 obj.data_size = data_size; 00167 obj.count = 0; 00168 snprintf(options, sizeof(options), "-p %ld", (long)pid); 00169 explain_lsof(options, &obj.inherited); 00170 if (obj.count > 0) 00171 return 1; 00172 } 00173 00174 /* 00175 * Sorry, can't help you. 00176 */ 00177 return 0; 00178 } 00179 00180 00181 /* vim: set ts=8 sw=4 et : */