Skip to content

Commit 29dd621

Browse files
committed
Feature: Added more advanced version display in admin interface
1 parent 1963031 commit 29dd621

File tree

3 files changed

+314
-0
lines changed

3 files changed

+314
-0
lines changed

admin/includes/header.xsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
</xsl:if>
2020
</xsl:for-each>
2121
<li class="right"><a href="/status.xsl">Public area</a></li>
22+
<li class="right adminlink"><a href="/admin/version.xsl">Version</a></li>
2223
</ul>
2324
</nav>
2425
</header>

admin/version.xsl

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
2+
<xsl:include href="includes/page.xsl"/>
3+
<xsl:variable name="title">Version</xsl:variable>
4+
5+
<xsl:template name="valuetable">
6+
<table class="table-block">
7+
<thead>
8+
<tr>
9+
<th>Key</th>
10+
<th>Value</th>
11+
</tr>
12+
</thead>
13+
<tbody>
14+
<xsl:for-each select="value">
15+
<xsl:if test="not(*)">
16+
<tr>
17+
<td><xsl:value-of select="@member" /></td>
18+
<td><xsl:value-of select="@value" /></td>
19+
</tr>
20+
</xsl:if>
21+
</xsl:for-each>
22+
</tbody>
23+
</table>
24+
</xsl:template>
25+
26+
<xsl:template name="flagslist">
27+
<ul>
28+
<xsl:for-each select="value[@type='flag']">
29+
<xsl:if test="@value = 'true'">
30+
<li><xsl:value-of select="@member" /></li>
31+
</xsl:if>
32+
</xsl:for-each>
33+
</ul>
34+
</xsl:template>
35+
36+
<xsl:template name="content">
37+
<h2><xsl:value-of select="$title" /></h2>
38+
<xsl:for-each select="/report/incident">
39+
<section class="box">
40+
<h3 class="box_title">Details</h3>
41+
<h4>Overview</h4>
42+
<xsl:for-each select="resource[@type='result']">
43+
<xsl:call-template name="valuetable" />
44+
45+
<xsl:for-each select="value[@member='uname']">
46+
<h4>uname</h4>
47+
<xsl:call-template name="valuetable" />
48+
</xsl:for-each>
49+
50+
<xsl:for-each select="value[@member='config']">
51+
<h4>Configuration</h4>
52+
<xsl:call-template name="valuetable" />
53+
</xsl:for-each>
54+
55+
<xsl:for-each select="value[@member='dependencies']">
56+
<h4>Dependencies</h4>
57+
<table class="table-block">
58+
<thead>
59+
<tr>
60+
<th>Dependency</th>
61+
<th>Compile time version</th>
62+
<th>Runtime time version</th>
63+
</tr>
64+
</thead>
65+
<tbody>
66+
<xsl:for-each select="value[@type='structure']">
67+
<tr>
68+
<td><xsl:value-of select="@member" /></td>
69+
<td><xsl:value-of select="value[@member='compiletime']/@value" /></td>
70+
<td><xsl:value-of select="value[@member='runtime']/@value" /></td>
71+
</tr>
72+
</xsl:for-each>
73+
</tbody>
74+
</table>
75+
</xsl:for-each>
76+
77+
<xsl:for-each select="value[@member='flags']">
78+
<h4>Flags</h4>
79+
80+
<xsl:for-each select="value[@member='compiletime']">
81+
<h5>Compile time</h5>
82+
<xsl:call-template name="flagslist" />
83+
</xsl:for-each>
84+
85+
<xsl:for-each select="value[@member='runtime']">
86+
<h5>Runtime time</h5>
87+
<xsl:call-template name="flagslist" />
88+
</xsl:for-each>
89+
</xsl:for-each>
90+
</xsl:for-each>
91+
</section>
92+
93+
<section class="box">
94+
<h3 class="box_title">Summary for reporting</h3>
95+
<xsl:for-each select="resource[@type='result']">
96+
<pre>
97+
<xsl:for-each select="value[@type!='structure']"><xsl:value-of select="@member" />: <xsl:value-of select="@value" /><xsl:text>
98+
</xsl:text></xsl:for-each>
99+
<xsl:for-each select="value[@member='uname' and @state='set']/value">uname: <xsl:value-of select="@member" />: <xsl:value-of select="@value" /><xsl:text>
100+
</xsl:text></xsl:for-each>
101+
<xsl:for-each select="value[@member='config' and @state='set']/value">config: <xsl:value-of select="@member" />: <xsl:value-of select="@value" /><xsl:text>
102+
</xsl:text></xsl:for-each>
103+
<xsl:for-each select="value[@member='dependencies' and @state='set']/value">dependency: <xsl:value-of select="@member" />: <xsl:for-each select="value"><xsl:if test="@state = 'set'">[<xsl:value-of select="@member" />] <xsl:value-of select="@value" /><xsl:text> </xsl:text></xsl:if></xsl:for-each><xsl:text>
104+
</xsl:text></xsl:for-each>
105+
<xsl:for-each select="value[@member='flags' and @state='set']/value">flags: <xsl:value-of select="@member" />: <xsl:for-each select="value[@type='flag']"><xsl:if test="@value = 'true'"><xsl:value-of select="@member" /><xsl:text> </xsl:text></xsl:if></xsl:for-each><xsl:text>
106+
</xsl:text></xsl:for-each>
107+
</pre>
108+
</xsl:for-each>
109+
</section>
110+
</xsl:for-each>
111+
</xsl:template>
112+
</xsl:stylesheet>

src/admin.c

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,39 @@
2323
#include <libxml/xmlmemory.h>
2424
#include <libxml/parser.h>
2525
#include <libxml/tree.h>
26+
#include <libxml/xmlversion.h>
27+
28+
#ifdef HAVE_UNISTD_H
29+
# include <unistd.h>
30+
#endif
2631

2732
#if HAVE_GETRLIMIT && HAVE_SYS_RESOURCE_H
2833
#include <sys/resource.h>
2934
#endif
3035

36+
#ifdef HAVE_OPENSSL
37+
#include <openssl/opensslv.h>
38+
#endif
39+
40+
#include <vorbis/codec.h>
41+
42+
#ifdef HAVE_THEORA
43+
#include <theora/theora.h>
44+
#endif
45+
46+
#ifdef HAVE_SPEEX
47+
#include <speex/speex.h>
48+
#endif
49+
50+
#ifdef HAVE_CURL
51+
#include <curl/curlver.h>
52+
#include <curl/curl.h>
53+
#endif
54+
55+
#ifdef HAVE_UNAME
56+
#include <sys/utsname.h>
57+
#endif
58+
3159
#include "common/net/sock.h"
3260

3361
#include "admin.h"
@@ -125,6 +153,8 @@
125153
#define DASHBOARD_RAW_REQUEST "dashboard"
126154
#define DASHBOARD_HTML_REQUEST "dashboard.xsl"
127155
#define DASHBOARD_JSON_REQUEST "dashboard.json"
156+
#define VERSION_RAW_REQUEST "version"
157+
#define VERSION_HTML_REQUEST "version.xsl"
128158
#define DEFAULT_RAW_REQUEST ""
129159
#define DEFAULT_HTML_REQUEST ""
130160
#define BUILDM3U_RAW_REQUEST "buildm3u"
@@ -160,6 +190,7 @@ static void command_buildm3u (client_t *client, source_t *source, adm
160190
static void command_show_log (client_t *client, source_t *source, admin_format_t response);
161191
static void command_mark_log (client_t *client, source_t *source, admin_format_t response);
162192
static void command_dashboard (client_t *client, source_t *source, admin_format_t response);
193+
static void command_version (client_t *client, source_t *source, admin_format_t response);
163194

164195
static const admin_command_handler_t handlers[] = {
165196
{ "*", ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, ADMINSAFE_UNSAFE, NULL, NULL}, /* for ACL framework */
@@ -216,6 +247,8 @@ static const admin_command_handler_t handlers[] = {
216247
{ DASHBOARD_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, ADMINSAFE_SAFE, command_dashboard, NULL},
217248
{ DASHBOARD_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, ADMINSAFE_SAFE, command_dashboard, NULL},
218249
{ DASHBOARD_JSON_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_JSON, ADMINSAFE_SAFE, command_dashboard, NULL},
250+
{ VERSION_RAW_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_RAW, ADMINSAFE_SAFE, command_version, NULL},
251+
{ VERSION_HTML_REQUEST, ADMINTYPE_GENERAL, ADMIN_FORMAT_HTML, ADMINSAFE_SAFE, command_version, NULL},
219252
{ DEFAULT_HTML_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, ADMINSAFE_SAFE, command_default_selector, NULL},
220253
{ DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, ADMIN_FORMAT_HTML, ADMINSAFE_SAFE, command_default_selector, NULL}
221254
};
@@ -1726,6 +1759,174 @@ static void command_dashboard (client_t *client, source_t *source, adm
17261759
refobject_unref(report);
17271760
}
17281761

1762+
#ifdef HAVE_SPEEX
1763+
static inline const char *get_speex_version(void)
1764+
{
1765+
const char *version;
1766+
if (speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, &version) != 0)
1767+
return NULL;
1768+
return version;
1769+
}
1770+
#endif
1771+
1772+
static void command_version (client_t *client, source_t *source, admin_format_t response)
1773+
{
1774+
reportxml_t *report = client_get_reportxml("8cdfc150-094d-42f7-9c61-f9fb9a6e07e7", NULL, NULL);
1775+
reportxml_node_t *incident = reportxml_get_node_by_type(report, REPORTXML_NODE_TYPE_INCIDENT, 0);
1776+
reportxml_node_t *resource = reportxml_node_new(REPORTXML_NODE_TYPE_RESOURCE, NULL, NULL, NULL);
1777+
reportxml_node_t *config = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
1778+
reportxml_node_t *dependencies = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
1779+
reportxml_node_t *flags = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
1780+
reportxml_node_t *cflags = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
1781+
reportxml_node_t *rflags = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
1782+
ice_config_t *icecast_config;
1783+
#ifdef HAVE_CURL
1784+
const curl_version_info_data * curl_runtime_version = curl_version_info(CURLVERSION_NOW);
1785+
#endif
1786+
struct {
1787+
const char *name;
1788+
const char *compiletime;
1789+
const char *runtime;
1790+
} dependency_versions[] = {
1791+
{"libxml2", LIBXML_DOTTED_VERSION, NULL},
1792+
#if defined(HAVE_OPENSSL) && defined(OPENSSL_VERSION_TEXT)
1793+
{"OpenSSL", OPENSSL_VERSION_TEXT, NULL},
1794+
#endif
1795+
{"libvorbis", NULL, vorbis_version_string()},
1796+
#ifdef HAVE_THEORA
1797+
{"libtheora", NULL, theora_version_string()},
1798+
#endif
1799+
#ifdef HAVE_SPEEX
1800+
{"libspeex", NULL, get_speex_version()},
1801+
#endif
1802+
#ifdef HAVE_CURL
1803+
{"libcurl", LIBCURL_VERSION, curl_runtime_version->version},
1804+
#endif
1805+
{NULL, NULL, NULL}
1806+
};
1807+
const char *compiletime_flags[] = {
1808+
#ifdef HAVE_POLL
1809+
"poll",
1810+
#endif
1811+
#ifdef HAVE_SYS_SELECT_H
1812+
"select",
1813+
#endif
1814+
#ifdef HAVE_UNAME
1815+
"uname",
1816+
#endif
1817+
#ifdef HAVE_GETHOSTNAME
1818+
"gethostname",
1819+
#endif
1820+
#ifdef WIN32
1821+
"win32",
1822+
#endif
1823+
#ifdef DEVEL_LOGGING
1824+
"developer-logging",
1825+
#endif
1826+
NULL,
1827+
};
1828+
size_t i;
1829+
1830+
reportxml_node_set_attribute(resource, "type", "result");
1831+
reportxml_node_add_child(incident, resource);
1832+
1833+
reportxml_helper_add_value_string(resource, "version", ICECAST_VERSION_STRING);
1834+
reportxml_helper_add_value_int(resource, "address-bits", sizeof(void*)*8);
1835+
1836+
#ifdef HAVE_GETHOSTNAME
1837+
if (true) {
1838+
char hostname[80];
1839+
if (gethostname(hostname, sizeof(hostname)) == 0) {
1840+
reportxml_helper_add_value_string(resource, "gethostname", hostname);
1841+
} else {
1842+
reportxml_helper_add_value_string(resource, "gethostname", NULL);
1843+
}
1844+
}
1845+
#endif
1846+
1847+
#ifdef HAVE_UNAME
1848+
if (true) {
1849+
reportxml_node_t *res = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
1850+
struct utsname utsname;
1851+
1852+
reportxml_node_set_attribute(res, "type", "structure");
1853+
reportxml_node_set_attribute(res, "member", "uname");
1854+
reportxml_node_add_child(resource, res);
1855+
1856+
if(uname(&utsname) == 0) {
1857+
reportxml_helper_add_value_string(res, "sysname", utsname.sysname);
1858+
reportxml_helper_add_value_string(res, "release", utsname.release);
1859+
reportxml_helper_add_value_string(res, "nodename", utsname.nodename);
1860+
reportxml_helper_add_value_string(res, "version", utsname.version);
1861+
reportxml_helper_add_value_string(res, "machine", utsname.machine);
1862+
} else {
1863+
reportxml_node_set_attribute(res, "state", "unset");
1864+
}
1865+
1866+
refobject_unref(res);
1867+
}
1868+
#endif
1869+
1870+
reportxml_node_set_attribute(config, "type", "structure");
1871+
reportxml_node_set_attribute(config, "member", "config");
1872+
reportxml_node_add_child(resource, config);
1873+
1874+
icecast_config = config_get_config();
1875+
reportxml_helper_add_value_string(config, "hostname", icecast_config->hostname);
1876+
reportxml_helper_add_value_string(config, "location", icecast_config->location);
1877+
reportxml_helper_add_value_string(config, "admin", icecast_config->admin);
1878+
reportxml_helper_add_value_string(config, "server-id", icecast_config->server_id);
1879+
1880+
reportxml_helper_add_value_flag(rflags, "requested-chroot", icecast_config->chroot);
1881+
reportxml_helper_add_value_flag(rflags, "requested-chuid", icecast_config->chuid);
1882+
config_release_config();
1883+
1884+
reportxml_node_set_attribute(dependencies, "type", "structure");
1885+
reportxml_node_set_attribute(dependencies, "member", "dependencies");
1886+
reportxml_node_add_child(resource, dependencies);
1887+
1888+
for (i = 0; dependency_versions[i].name; i++) {
1889+
reportxml_node_t *dependency = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
1890+
reportxml_node_set_attribute(dependency, "type", "structure");
1891+
reportxml_node_set_attribute(dependency, "member", dependency_versions[i].name);
1892+
reportxml_helper_add_value_string(dependency, "compiletime", dependency_versions[i].compiletime);
1893+
reportxml_helper_add_value_string(dependency, "runtime", dependency_versions[i].runtime);
1894+
reportxml_node_add_child(dependencies, dependency);
1895+
refobject_unref(dependency);
1896+
}
1897+
1898+
reportxml_node_set_attribute(flags, "type", "structure");
1899+
reportxml_node_set_attribute(flags, "member", "flags");
1900+
reportxml_node_add_child(resource, flags);
1901+
1902+
reportxml_node_set_attribute(cflags, "type", "unordered-list");
1903+
reportxml_node_set_attribute(cflags, "member", "compiletime");
1904+
reportxml_node_add_child(flags, cflags);
1905+
for (i = 0; compiletime_flags[i]; i++) {
1906+
reportxml_helper_add_value_flag(cflags, compiletime_flags[i], true);
1907+
}
1908+
1909+
reportxml_node_set_attribute(rflags, "type", "unordered-list");
1910+
reportxml_node_set_attribute(rflags, "member", "runtime");
1911+
reportxml_node_add_child(flags, rflags);
1912+
reportxml_helper_add_value_flag(rflags, "ipv4-mapped", sock_is_ipv4_mapped_supported());
1913+
1914+
global_lock();
1915+
reportxml_helper_add_value_flag(rflags, "bound-unix", listensocket_container_is_family_included(global.listensockets, SOCK_FAMILY_UNIX));
1916+
reportxml_helper_add_value_flag(rflags, "bound-inet4", listensocket_container_is_family_included(global.listensockets, SOCK_FAMILY_INET4));
1917+
reportxml_helper_add_value_flag(rflags, "bound-inet6", listensocket_container_is_family_included(global.listensockets, SOCK_FAMILY_INET6));
1918+
global_unlock();
1919+
1920+
refobject_unref(config);
1921+
refobject_unref(dependencies);
1922+
refobject_unref(cflags);
1923+
refobject_unref(rflags);
1924+
refobject_unref(flags);
1925+
refobject_unref(resource);
1926+
refobject_unref(incident);
1927+
client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, VERSION_HTML_REQUEST, response, 200, NULL);
1928+
refobject_unref(report);
1929+
}
17291930

17301931
static void ui_command(client_t * client, source_t * source, admin_format_t format, resourcematch_extract_t *parameters)
17311932
{

0 commit comments

Comments
 (0)