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