2 * Copyright (C) 2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include <sys/utsname.h>
21 #include <utils/linked_list.h>
24 typedef struct private_os_info_t private_os_info_t
;
26 ENUM(os_fwd_status_names
, OS_FWD_DISABLED
, OS_FWD_UNKNOWN
,
33 * Private data of an os_info_t object.
36 struct private_os_info_t
{
39 * Public os_info_t interface.
55 METHOD(os_info_t
, get_name
, chunk_t
,
56 private_os_info_t
*this)
61 METHOD(os_info_t
, get_numeric_version
, void,
62 private_os_info_t
*this, u_int32_t
*major
, u_int32_t
*minor
)
68 *major
= atol(this->version
.ptr
);
70 pos
= memchr(this->version
.ptr
, '.', this->version
.len
);
73 *minor
= pos ?
atol(pos
+ 1) : 0;
77 METHOD(os_info_t
, get_version
, chunk_t
,
78 private_os_info_t
*this)
83 METHOD(os_info_t
, get_fwd_status
, os_fwd_status_t
,
84 private_os_info_t
*this)
86 const char ip_forward
[] = "/proc/sys/net/ipv4/ip_forward";
90 os_fwd_status_t fwd_status
= OS_FWD_UNKNOWN
;
92 file
= fopen(ip_forward
, "r");
95 if (fread(buf
, 1, 1, file
) == 1)
100 fwd_status
= OS_FWD_DISABLED
;
103 fwd_status
= OS_FWD_ENABLED
;
106 DBG1(DBG_IMC
, "\"%s\" returns invalid value ", ip_forward
);
112 DBG1(DBG_IMC
, "could not read from \"%s\"", ip_forward
);
118 DBG1(DBG_IMC
, "failed to open \"%s\"", ip_forward
);
124 METHOD(os_info_t
, get_uptime
, time_t,
125 private_os_info_t
*this)
127 const char proc_uptime
[] = "/proc/uptime";
131 file
= fopen(proc_uptime
, "r");
134 DBG1(DBG_IMC
, "failed to open \"%s\"", proc_uptime
);
137 if (fscanf(file
, "%u", &uptime
) != 1)
139 DBG1(DBG_IMC
, "failed to read file \"%s\"", proc_uptime
);
147 METHOD(os_info_t
, create_package_enumerator
, enumerator_t
*,
148 private_os_info_t
*this)
156 METHOD(os_info_t
, destroy
, void,
157 private_os_info_t
*this)
159 free(this->name
.ptr
);
160 free(this->version
.ptr
);
164 #define RELEASE_LSB 0
165 #define RELEASE_DEBIAN 1
168 * Determine Linux distribution version and hardware platform
170 static bool extract_platform_info(chunk_t
*name
, chunk_t
*version
)
173 u_char buf
[BUF_LEN
], *pos
= buf
;
174 int len
= BUF_LEN
- 1;
175 chunk_t os_name
= chunk_empty
;
176 chunk_t os_version
= chunk_empty
;
177 struct utsname uninfo
;
180 /* Linux/Unix distribution release info (from http://linuxmafia.com) */
181 const char* releases
[] = {
182 "/etc/lsb-release", "/etc/debian_version",
183 "/etc/SuSE-release", "/etc/novell-release",
184 "/etc/sles-release", "/etc/redhat-release",
185 "/etc/fedora-release", "/etc/gentoo-release",
186 "/etc/slackware-version", "/etc/annvix-release",
187 "/etc/arch-release", "/etc/arklinux-release",
188 "/etc/aurox-release", "/etc/blackcat-release",
189 "/etc/cobalt-release", "/etc/conectiva-release",
190 "/etc/debian_release", "/etc/immunix-release",
191 "/etc/lfs-release", "/etc/linuxppc-release",
192 "/etc/mandrake-release", "/etc/mandriva-release",
193 "/etc/mandrakelinux-release", "/etc/mklinux-release",
194 "/etc/pld-release", "/etc/redhat_version",
195 "/etc/slackware-release", "/etc/e-smith-release",
196 "/etc/release", "/etc/sun-release",
197 "/etc/tinysofa-release", "/etc/turbolinux-release",
198 "/etc/ultrapenguin-release", "/etc/UnitedLinux-release",
199 "/etc/va-release", "/etc/yellowdog-release"
202 const char lsb_distrib_id
[] = "DISTRIB_ID=";
203 const char lsb_distrib_release
[] = "DISTRIB_RELEASE=";
205 for (i
= 0; i
< countof(releases
); i
++)
207 file
= fopen(releases
[i
], "r");
213 /* read release file into buffer */
214 fseek(file
, 0, SEEK_END
);
215 len
= min(ftell(file
), len
);
218 if (fread(buf
, 1, len
, file
) != len
)
220 DBG1(DBG_IMC
, "failed to read file \"%s\"", releases
[i
]);
226 DBG1(DBG_IMC
, "processing \"%s\" file", releases
[i
]);
232 /* Determine Distribution ID */
233 pos
= strstr(buf
, lsb_distrib_id
);
236 DBG1(DBG_IMC
, "failed to find begin of DISTRIB_ID field");
239 pos
+= strlen(lsb_distrib_id
);
243 pos
= strchr(pos
, '\n');
246 DBG1(DBG_IMC
, "failed to find end of DISTRIB_ID field");
250 os_name
.len
= pos
- os_name
.ptr
;
252 /* Determine Distribution Release */
253 pos
= strstr(buf
, lsb_distrib_release
);
256 DBG1(DBG_IMC
, "failed to find begin of DISTRIB_RELEASE field");
259 pos
+= strlen(lsb_distrib_release
);
261 os_version
.ptr
= pos
;
263 pos
= strchr(pos
, '\n');
266 DBG1(DBG_IMC
, "failed to find end of DISTRIB_RELEASE field");
270 os_version
.len
= pos
- os_version
.ptr
;
276 char str_debian
[] = "Debian";
278 os_name
= chunk_create(str_debian
, strlen(str_debian
));
279 os_version
.ptr
= buf
;
281 pos
= strchr(buf
, '\n');
284 DBG1(DBG_PTS
, "failed to find end of release string");
288 os_version
.len
= pos
- os_version
.ptr
;
294 const char str_release
[] = " release ";
298 pos
= strstr(buf
, str_release
);
301 DBG1(DBG_IMC
, "failed to find release keyword");
305 os_name
.len
= pos
- os_name
.ptr
;
306 pos
+= strlen(str_release
);
307 os_version
.ptr
= pos
;
309 pos
= strchr(pos
, '\n');
312 DBG1(DBG_IMC
, "failed to find end of release string");
316 os_version
.len
= pos
- os_version
.ptr
;
326 DBG1(DBG_IMC
, "no distribution release file found");
330 if (uname(&uninfo
) < 0)
332 DBG1(DBG_IMC
, "could not retrieve machine architecture");
337 *name
= chunk_clone(os_name
);
339 /* copy OS version and machine architecture */
340 *version
= chunk_alloc(os_version
.len
+ 1 + strlen(uninfo
.machine
));
342 memcpy(pos
, os_version
.ptr
, os_version
.len
);
343 pos
+= os_version
.len
;
345 memcpy(pos
, uninfo
.machine
, strlen(uninfo
.machine
));
353 os_info_t
*os_info_create(void)
355 private_os_info_t
*this;
356 chunk_t name
, version
;
358 /* As an opton OS name and OS version can be configured manually */
359 name
.ptr
= lib
->settings
->get_str(lib
->settings
,
360 "libimcv.os_info.name", NULL
);
361 version
.ptr
= lib
->settings
->get_str(lib
->settings
,
362 "libimcv.os_info.version", NULL
);
363 if (name
.ptr
&& version
.ptr
)
365 name
.len
= strlen(name
.ptr
);
366 name
= chunk_clone(name
);
368 version
.len
= strlen(version
.ptr
);
369 version
= chunk_clone(version
);
373 if (!extract_platform_info(&name
, &version
))
378 DBG1(DBG_IMC
, "operating system name is '%.*s'",
380 DBG1(DBG_IMC
, "operating system version is '%.*s'",
381 version
.len
, version
.ptr
);
385 .get_name
= _get_name
,
386 .get_numeric_version
= _get_numeric_version
,
387 .get_version
= _get_version
,
388 .get_fwd_status
= _get_fwd_status
,
389 .get_uptime
= _get_uptime
,
390 .create_package_enumerator
= _create_package_enumerator
,
397 return &this->public;