xref: /titanic_41/usr/src/cmd/lms/tools/ATVersion.cpp (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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