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
ShowVersionIfArg(int argc,const char ** argv,const char * versionStr)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
GetAppVersion(const char * appName,std::string & version)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
GetProcessVersion(std::string cmd)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
IsAppRunning(const char * appName,std::list<unsigned long> & pids)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
GetAppPathByPid(unsigned long pid)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