1 /******************************************************************************* 2 * Copyright (C) 2004-2008 Intel Corp. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * - Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * - Neither the name of Intel Corp. nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 *******************************************************************************/ 30 31 #ifdef HAVE_CONFIG_H 32 #include "config.h" 33 #endif 34 #include "iatshareddata.h" 35 #include "ATVersion.h" 36 #include <cstring> 37 #include <cstdlib> 38 #include <cstdio> 39 #include <climits> 40 #include <cerrno> 41 #include <fstream> 42 #include <dirent.h> 43 44 #define AT_VERSION_ARGUMENT "--version" 45 #define AT_VERSION_MAXSIZE 40 46 #define AT_APPNAME_MAXSIZE 15 47 #define ATstr(s) ATname(s) 48 #define ATname(s) #s 49 #define AT_VERSION_OUT_FORMAT "Version: %." ATstr(AT_VERSION_MAXSIZE) "s\n" 50 #define AT_VERSION_SCAN_FORMAT "Version: %" ATstr(AT_VERSION_MAXSIZE) "s" 51 #define AT_PIDFILE_NAME_FORMAT IATSTATERUNDIR "/%." ATstr(AT_APPNAME_MAXSIZE) "s.pid" 52 #define AT_DEF_PIDFILE_NAME_FORMAT "/var/run/%." ATstr(AT_APPNAME_MAXSIZE) "s.pid" 53 #define AT_PROCSTAT_NAME_FORMAT "Name:\t%" ATstr(AT_APPNAME_MAXSIZE) "s\n" 54 55 const std::string ATVersion::appSearchPath = 56 "PATH='/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin' && "; 57 58 bool ATVersion::ShowVersionIfArg(int argc, const char **argv, const char *versionStr) 59 { 60 if (1 < argc) { 61 for (int i = 1; i < argc; i++) { 62 if (0 == strncmp(argv[i], AT_VERSION_ARGUMENT, strlen(AT_VERSION_ARGUMENT))) { 63 fprintf(stdout, AT_VERSION_OUT_FORMAT, versionStr); 64 return true; 65 } 66 } 67 } 68 return false; 69 } 70 71 bool ATVersion::GetAppVersion(const char *appName, std::string &version) 72 { 73 std::list<unsigned long> pids; 74 75 version = ""; 76 if (IsAppRunning(appName, pids)) { 77 for (std::list<unsigned long>::iterator iter = pids.begin(); iter != pids.end(); iter++) { 78 std::string path = GetAppPathByPid(*iter); 79 if (!path.empty()) { 80 version = GetProcessVersion(path); 81 return true; 82 } 83 } 84 } 85 version = GetProcessVersion(ATVersion::appSearchPath + appName); 86 if (version.empty()) { 87 version = GetProcessVersion(appName); 88 } 89 return false; 90 } 91 92 std::string ATVersion::GetProcessVersion(std::string cmd) 93 { 94 if (cmd.empty()) { 95 return ""; 96 } 97 98 FILE *fp = popen((cmd + " " AT_VERSION_ARGUMENT " 2>/dev/null").c_str(), "r"); 99 if (fp) { 100 char buf[AT_VERSION_MAXSIZE + 1]; 101 int res = fscanf(fp, AT_VERSION_SCAN_FORMAT, buf); 102 buf[AT_VERSION_MAXSIZE] = '\0'; 103 pclose(fp); 104 if (1 == res) { 105 return buf; 106 } 107 } 108 return ""; 109 } 110 111 bool ATVersion::IsAppRunning(const char *appName, std::list<unsigned long> &pids) 112 { 113 struct dirent **namelist; 114 FILE *stat; 115 char name_str[AT_APPNAME_MAXSIZE + 1]; 116 int num_entries; 117 char status_path[256]; 118 unsigned long pid; 119 unsigned long selfpid = 0; 120 bool res = false; 121 int ret; 122 123 pids.clear(); 124 125 memset(status_path, '\0', sizeof(status_path)); 126 snprintf(status_path, sizeof(status_path), AT_PIDFILE_NAME_FORMAT, appName); 127 std::ifstream pidf(status_path); 128 if (pidf.is_open()) { 129 pidf >> pid; 130 pidf.close(); 131 if (!(GetAppPathByPid(pid).empty())) { 132 pids.push_back(pid); 133 return true; 134 } 135 } 136 137 memset(status_path, '\0', sizeof(status_path)); 138 snprintf(status_path, sizeof(status_path), AT_DEF_PIDFILE_NAME_FORMAT, appName); 139 pidf.open(status_path); 140 if (pidf.is_open()) { 141 pidf >> pid; 142 pidf.close(); 143 if (!(GetAppPathByPid(pid).empty())) { 144 pids.push_back(pid); 145 return true; 146 } 147 } 148 149 num_entries = scandir("/proc", &namelist, 0, alphasort); 150 if (num_entries < 0) { 151 return false; 152 } 153 154 memset(status_path, '\0', sizeof(status_path)); 155 if (-1 != readlink("/proc/self", status_path, sizeof(status_path))) { 156 selfpid = std::atol(status_path); 157 } 158 159 while (num_entries--) { 160 char *pidstr = namelist[num_entries]->d_name; 161 if ((pidstr) && (pidstr[0] > '0') && (pidstr[0] <= '9')) { 162 pid = std::atol(pidstr); 163 if (pid != selfpid) { 164 /* for process name we check the 'status' entry */ 165 memset(status_path, '\0', sizeof(status_path)); 166 snprintf(status_path, sizeof(status_path), "/proc/%lu/status", pid); 167 if (NULL != (stat = fopen(status_path, "r"))) { 168 memset(name_str, '\0', sizeof(name_str)); 169 ret = fscanf(stat, AT_PROCSTAT_NAME_FORMAT, name_str); 170 fclose(stat); 171 if ((1 == ret) && (strncmp(name_str, appName, 15) == 0)) { 172 pids.push_back(pid); 173 res = true; 174 } 175 } 176 } 177 } 178 free(namelist[num_entries]); 179 } 180 free(namelist); 181 182 return res; 183 } 184 185 186 std::string ATVersion::GetAppPathByPid(unsigned long pid) 187 { 188 char path[256]; 189 char exe_buf[PATH_MAX]; 190 191 memset(path, '\0', sizeof(path)); 192 snprintf(path, sizeof(path), "/proc/%lu/exe", pid); 193 memset(exe_buf, '\0', PATH_MAX); 194 if (-1 == readlink(path, exe_buf, PATH_MAX)) { 195 return ""; 196 } 197 198 if (NULL != strstr(exe_buf, " (deleted)")) { 199 return ""; 200 } 201 202 return exe_buf; 203 } 204 205