В ходе подготовки к проведению меропрятия Sun Tech Days 2010 я столкнулся с необходимостью мониторинга большого количества оборудования разных вендоров. В результате небольшого обзора существующих открытых систем мониторинга я остановил свой выбор на Zabbix. Среди используемого оборудования были сервера Sun: x4150 и x4200. Сбор информации для системы мониторинга на уровне ОС обеспечивал агент Zabbix, сбор информации на уровне аппаратной платформы обеспечивал сервисный процессор ILOM, доступный по протоколу IPMI. Zabbix может контролировать работу IPMI-совместимых устройств, в том случае, если он собран с поддержкой этого протокола. Однако на момент запуска системы в коллекции портов FreeBSD для zabbix-server отсутствовала опция сборки, отвечающая за поддержку IPMI, поэтому я попробовал ее добавить.
Для сборки Zabbix с поддержкой IPMI в системе необходимо наличие пакета OpenIPMI, которого также не оказалось в коллекции портов. Поэтому я решил создать такой порт. Но прежде чем писать Makefile я попробовал собрать пакет OpenIPMI традиционным способом - configure/make/make install. В списке обязательных зависимостей OpenIPMI значились:
* popt
* curses, ncurses or termcap
в списке опциональных:
* netsnmp or ucdsnmp
* openssl
* glib
* swig
* perl
* python
* Tcl/Tk
* Tkinter/Tix
* gdbm
Для начала я решил обойтись достаточным для моей задачи минимумом:
$ tar xf OpenIPMI-2.0.16.tar.gz
$ cd OpenIPMI-2.0.16
$ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" \
./configure --with-openssl --prefix=/var/tmp/openipmi
Но начав сборку, почти сразу же получил ошибку:
$ gmake
...
gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/local/include -Wall -Wsign-compare -I../include
-DIPMI_CHECK_LOCKS -g -O2 -MT oem_intel.lo -MD -MP -MF .deps/oem_intel.Tpo -c oem_intel.c
-fPIC -DPIC -o .libs/oem_intel.o
oem_intel.c:34:20: error: alloca.h: No such file or directory
gmake[2]: *** [oem_intel.lo] Ошибка 1
решение быстро нашлось в списках рассылки:
FreeBSD has no system-wide 'alloca.h'. Instead it uses a routine in
'stdlib.h' for this. Here is a copy of the section in /usr/include/stdlib.h:
/*
* The alloca() function can't be implemented in C, and on some
* platforms it can't be implemented at all as a callable function.
* The GNU C compiler provides a built-in alloca() which we can use;
* in all other cases, provide a prototype, mainly to pacify various
* incarnations of lint. On platforms where alloca() is not in libc,
* programs which use it will fail to link when compiled with non-GNU
* compilers.
*/
Поправив все заголовочные файлы, в которых упоминался alloca.h, я продолжил сборку и в скором времени получил еще одну ошибку:
gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/local/include -Wall -Wsign-compare -I../include
-DIPMI_CHECK_LOCKS -g -O2 -MT fru_spd_decode.lo -MD -MP -MF .deps/fru_spd_decode.Tpo
-c fru_spd_decode.c -fPIC -DPIC -o .libs/fru_spd_decode.o
fru_spd_decode.c:42:20: error: values.h: No such file or directory
gmake[2]: *** [fru_spd_decode.lo] Ошибка 1
Эта проблема также легко решается заменой (согласно стадарта) values.h на limits.h. Но на этом ошибки не закончились:
gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/local/include -Wall -Wsign-compare -I../include -g
-O2 -MT selector.lo -MD -MP -MF .deps/selector.Tpo -c selector.c -fPIC -DPIC
-o .libs/selector.o
In file included from selector.c:52:
/usr/include/malloc.h:3:2: error: #error "<malloc.h> has been replaced by <stdlib.h>"
selector.c: In function 'sel_alloc_selector':
Такая ошибка наиболее часто встречается при сборке программ на FreeBSD. После удаления ненужных ссылок на malloc.h сборка прервалась снова:
gcc -Wall -Wsign-compare -I../include -g -O2 -o .libs/test_handlers test_handlers.o
-L/usr/local/lib ./.libs/libOpenIPMIposix.so ./.libs/libOpenIPMIpthread.so -lpthread
/home/tiamat/Downloads/OpenIPMI-2.0.16/utils/.libs/libOpenIPMIutils.so
../utils/.libs/libOpenIPMIutils.so /usr/local/lib/libgdbm.so -lcurses -Wl,--rpath
-Wl,/var/tmp/openipmi/lib -Wl,--rpath -Wl,/usr/local/lib
/home/tiamat/Downloads/OpenIPMI-2.0.16/utils/.libs/libOpenIPMIutils.so: undefined
reference to `backtrace'
gmake[2]: *** [test_handlers] Ошибка 1
Ошибка связана с отсутствием в libc соответствующей функции и присутствии в системе пакета libexecinfo:
$ pkg_info libexecinfo-1.1_3
Information for libexecinfo-1.1_3:
Comment:
A library for inspecting program's backtrace
Required by:
samba34-3.4.5_1
Description:
This is a quick-n-dirty BSD licensed clone of backtrace facility found
in the GNU libc, mainly intended for porting linuxish code to BSD
platforms, however it can be used at any platform which has a gcc
compiler.
WWW: http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
Поправив configure.in и пересоздав при помощи autotools файл configure я продолжил:
libtool: compile: gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/local/include -Wall
-Wsign-compare -I../include -I../libedit -DIPMI_CHECK_LOCKS -D_REENTRANT
-I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include -g -O2 -MT out_fru.lo
-MD -MP -MF .deps/out_fru.Tpo -c out_fru.c -fPIC -DPIC -o .libs/out_fru.o
out_fru.c: In function 'traverse_fru_node_tree':
out_fru.c:123: error: 'MAXINT' undeclared (first use in this function)
out_fru.c:123: error: (Each undeclared identifier is reported only once
out_fru.c:123: error: for each function it appears in.)
out_fru.c: In function 'ipmi_cmdlang_dump_fru_info':
out_fru.c:160: error: 'MAXINT' undeclared (first use in this function)
gmake[2]: *** [out_fru.lo] Ошибка 1
Вместо MAXINT надобно применять (опять-таки в соответствии со стандартом) INT_MAX:
if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/local/include -Wall -Wsign-compare
-I../include -I../libedit -DIPMI_CHECK_LOCKS -D_REENTRANT -I/usr/local/include/glib-2.0
-I/usr/local/lib/glib-2.0/include -g -O2 -MT ipmish.o -MD -MP -MF ".deps/ipmish.Tpo"
-c -o ipmish.o ipmish.c; \
then mv -f ".deps/ipmish.Tpo" ".deps/ipmish.Po"; else rm -f ".deps/ipmish.Tpo";
exit 1; fi
ipmish.c: In function 'setup_term':
ipmish.c:655: error: 'SIGPWR' undeclared (first use in this function)
Такого сигнала в ОС FreeBSD просто нет:
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGEMT 8) SIGFPE 9) SIGKILL 10) SIGBUS
11) SIGSEGV 12) SIGSYS 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGURG 17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD
21) SIGTTIN 22) SIGTTOU 23) SIGIO 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGINFO 30) SIGUSR1
31) SIGUSR2
Соответственно добавляем неообходимые #ifdef и продолжаем:
libtool: compile: gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/local/include -Wall
-Wsign-compare -I../include -DIPMI_CHECK_LOCKS -g -O2 -MT lanserv_ipmi.lo -MD -MP
-MF .deps/lanserv_ipmi.Tpo -c lanserv_ipmi.c -fPIC -DPIC -o .libs/lanserv_ipmi.o
In file included from ./OpenIPMI/lanserv.h:63,
from lanserv_ipmi.c:68:
/usr/include/resolv.h:161: error: array type has incomplete element type
/usr/include/resolv.h:175: error: field 'addr' has incomplete type
/usr/include/resolv.h:199: error: field 'sin' has incomplete type
In file included from lanserv_ipmi.c:68:
./OpenIPMI/lanserv.h:502: error: field 's_addr4' has incomplete type
./OpenIPMI/lanserv.h:504: error: field 's_addr6' has incomplete type
gmake[3]: *** [lanserv_ipmi.lo] Ошибка 1
В man resolver ясно сказано:
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
а в исходных файлах явно не хватает нужных файлов. Добавляем их и идем дальше:
if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/local/include -Wall -Wsign-compare -I../include
-DIPMI_CHECK_LOCKS -g -O2 -MT emu_cmd.o -MD -MP -MF ".deps/emu_cmd.Tpo" -c -o emu_cmd.o
emu_cmd.c; \
then mv -f ".deps/emu_cmd.Tpo" ".deps/emu_cmd.Po"; else rm -f ".deps/emu_cmd.Tpo";
exit 1; fi
In file included from emu_cmd.c:6:
emu.h:12: warning: 'struct timeval' declared inside parameter list
emu.h:12: warning: its scope is only this definition or declaration, which is probably not what you want
emu.h:18: warning: 'struct timeval' declared inside parameter list
emu_cmd.c: In function 'sleep_cmd':
emu_cmd.c:790: error: storage size of 'tv' isn't known
emu_cmd.c:790: warning: unused variable 'tv'
Опять же - для использования timeval необходим заголовочный файл sys/time.h. Добавляем его и на этом сборка успешно завершается!
Но собранная программа не всегда означает рабочую программу. При запуске ipmicmd выдает ошибку:
$ /var/tmp/openipmi/bin/ipmicmd lan -U root -P passwd 10.2.2.1
=> f 0 6 1
Error sending command: 16
Копания в исходном тексте программы показали, что возникает ошибка errno=22(Invalid argument) при попытке соединится с удаленным хостом в момент вызова sendto:
lib/ipmi_lan.c:
rv = sendto(lan->fd->fd, tmsg, pos, 0,
(struct sockaddr *) &(lan->cparm.ip_addr[addr_num]),
sizeof(sockaddr_ip_t));
if (rv == -1) {
При этом последний аргумент sendto равен 28. В соответствии со страницей руководства (man sendto) последний аргумент представляет собой длину адреса получателя:
ssize_t
sendto(int s, const void *msg, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen);
The address of the target is given by to with tolen specifying its size.
The length of the message is given by len. If the message is too long to
pass atomically through the underlying protocol, the error EMSGSIZE is
returned, and the message is not transmitted.
No indication of failure to deliver is implicit in a send(). Locally
detected errors are indicated by a return value of -1.
Для IPv4 эта длина составляет 16 байт и в нашем случае это справедливо:
(gdb) p lan->fd->fd
$1 = 3
(gdb) p *tmsg
$2 = 6 '\006'
(gdb) print pos
$3 = 23
(gdb) p lan->cparm.ip_addr[addr_num]
$4 = {s_ipsock = {s_addr = {sa_len = 16 '\020', sa_family = 2 '\002',
sa_data = "\002o\n\002\027\210\000\000\000\000\000\000\000"}, s_addr4 = {
sin_len = 16 '\020', sin_family = 2 '\002', sin_port = 28418,
sin_addr = {s_addr = 2283209226},
sin_zero = "\000\000\000\000\000\000\000"}, s_addr6 = {
sin6_len = 16 '\020', sin6_family = 2 '\002', sin6_port = 28418,
sin6_flowinfo = 2283209226, sin6_addr = {__u6_addr = {
__u6_addr8 = '\0' <repeats 15 times>, __u6_addr16 = {0, 0, 0, 0, 0,
0, 0, 0}, __u6_addr32 = {0, 0, 0, 0}}}, sin6_scope_id = 0}}}
(gdb) p *(struct sockaddr *) &(lan->cparm.ip_addr[addr_num])
$2 = {sa_len = 16 '\020', sa_family = 2 '\002',
sa_data = "\002o\n\002\027\210\000\000\000\000\000\000\000"}
В исходных текстах OpenIPMI адрес хранится в структуре sockaddr_ip_t:
/* Because sizeof(sockaddr_in6) > sizeof(sockaddr_in), this structure
* is used as a replacement of struct sockaddr. */
typedef struct sockaddr_ip_s {
union
{
struct sockaddr s_addr;
struct sockaddr_in s_addr4;
#ifdef PF_INET6
struct sockaddr_in6 s_addr6;
#endif
} s_ipsock;
} sockaddr_ip_t;
Вот способом хранения и объясняется ошибка - независимо от используемого адреса (IPv4 или IPv6) размер этой структуры всегда равен наибольшему составляющему объединение элементу. А данном случае это struct sockaddr_in6 s_addr6, размер которой и дает неправильный tolen=28 в sendto.
Наиболе примечателен тот факт, что несмотря на очевидную ошибку весь это код успешно работает на Linux! В качестве иллюстрации вышесказанного можно воспользоваться примером из статьи Википедии про Berkeley sockets. В этой статье есть пример клиент-сервера для UDP протокола. Если модифицировать клиента таким образом, чтобы он использовал в качестве последнего аргумента sendto что-нибудь отличное от sizeof (struct sockaddr_in) то мы получим программу, успешно работающую на Linux и не работающую (с ошибкой 22 Invalid argument) на FreeBSD.
Оформив все изменения в виде патча, обеспечивающего возможность сборки OpenIPMI на FreeBSD:
diff -ur OpenIPMI/cmdlang/ipmish.c OpenIPMI-patched/cmdlang/ipmish.c
--- OpenIPMI/cmdlang/ipmish.c 2006-04-06 18:13:46.000000000 +0400
+++ OpenIPMI-patched/cmdlang/ipmish.c 2010-04-19 16:47:19.708782708 +0400
@@ -652,7 +652,9 @@
signal(SIGPIPE, cleanup_sig);
signal(SIGUSR1, cleanup_sig);
signal(SIGUSR2, cleanup_sig);
+#ifdef SIGPWR
signal(SIGPWR, cleanup_sig);
+#endif
stifle_history(500);
rl_callback_handler_install("> ", rl_ipmish_cb_handler);
diff -ur OpenIPMI/cmdlang/out_fru.c OpenIPMI-patched/cmdlang/out_fru.c
--- OpenIPMI/cmdlang/out_fru.c 2006-10-25 23:04:08.000000000 +0400
+++ OpenIPMI-patched/cmdlang/out_fru.c 2010-04-16 00:20:11.176952295 +0400
@@ -33,7 +33,7 @@
#include <errno.h>
#include <string.h>
-#include <values.h>
+#include <limits.h>
#include <OpenIPMI/ipmi_bits.h>
#include <OpenIPMI/ipmi_fru.h>
#include <OpenIPMI/ipmi_cmdlang.h>
@@ -120,7 +120,7 @@
if (intval != -1)
ipmi_cmdlang_out_int(cmd_info, "Element Count", intval);
else
- intval = MAXINT;
+ intval = INT_MAX;
traverse_fru_node_tree(cmd_info, sub_node, intval);
ipmi_cmdlang_up(cmd_info);
break;
@@ -157,7 +157,7 @@
rv = ipmi_fru_get_root_node(fru, &type, &node);
if (!rv) {
ipmi_cmdlang_out(cmd_info, "Type", type);
- rv = traverse_fru_node_tree(cmd_info, node, MAXINT);
+ rv = traverse_fru_node_tree(cmd_info, node, INT_MAX);
if (rv)
cmdlang->errstr = "Error traversing FRU node tree";
} else {
diff -ur OpenIPMI/configure.in OpenIPMI-patched/configure.in
--- OpenIPMI/configure.in 2009-03-17 03:56:38.000000000 +0300
+++ OpenIPMI-patched/configure.in 2010-04-19 17:03:02.663825318 +0400
@@ -22,9 +22,6 @@
AC_SUBST(OPENIPMI_SMI)
-# Check for execinfo.h
-AC_CHECK_HEADERS(execinfo.h)
-
SNMPLIBS=
# Where do we find the UCD SNMP includes and libs
diff -ur OpenIPMI/lanserv/OpenIPMI/lanserv.h OpenIPMI-patched/lanserv/OpenIPMI/lanserv.h
--- OpenIPMI/lanserv/OpenIPMI/lanserv.h 2008-03-12 20:53:21.000000000 +0300
+++ OpenIPMI-patched/lanserv/OpenIPMI/lanserv.h 2010-04-16 00:50:52.790912170 +0400
@@ -60,7 +60,10 @@
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
#include <resolv.h>
+#include <netdb.h>
#include <OpenIPMI/ipmi_auth.h>
diff -ur OpenIPMI/lanserv/emu.h OpenIPMI-patched/lanserv/emu.h
--- OpenIPMI/lanserv/emu.h 2006-10-24 20:50:30.000000000 +0400
+++ OpenIPMI-patched/lanserv/emu.h 2010-04-16 00:52:25.971815329 +0400
@@ -2,6 +2,7 @@
#ifndef __EMU_IPMI_
#define __EMU_IPMI_
+#include <sys/time.h>
#include <OpenIPMI/ipmi_types.h>
typedef struct emu_data_s emu_data_t;
diff -ur OpenIPMI/lanserv/lanserv.c OpenIPMI-patched/lanserv/lanserv.c
--- OpenIPMI/lanserv/lanserv.c 2006-05-02 17:54:53.000000000 +0400
+++ OpenIPMI-patched/lanserv/lanserv.c 2010-04-16 00:22:33.562882071 +0400
@@ -68,7 +68,6 @@
#include <stdlib.h>
#include <stdarg.h>
#include <popt.h> /* Option parsing made easy */
-#include <malloc.h>
#include <sys/ioctl.h>
#if HAVE_SYSLOG
#include <syslog.h>
diff -ur OpenIPMI/lanserv/lanserv_emu.c OpenIPMI-patched/lanserv/lanserv_emu.c
--- OpenIPMI/lanserv/lanserv_emu.c 2006-10-24 20:50:30.000000000 +0400
+++ OpenIPMI-patched/lanserv/lanserv_emu.c 2010-04-16 00:22:40.728197495 +0400
@@ -69,7 +69,6 @@
#include <stdlib.h>
#include <stdarg.h>
#include <popt.h> /* Option parsing made easy */
-#include <malloc.h>
#include <sys/ioctl.h>
#include <termios.h>
diff -ur OpenIPMI/lib/fru_spd_decode.c OpenIPMI-patched/lib/fru_spd_decode.c
--- OpenIPMI/lib/fru_spd_decode.c 2008-04-04 02:29:10.000000000 +0400
+++ OpenIPMI-patched/lib/fru_spd_decode.c 2010-04-16 00:16:54.724804327 +0400
@@ -39,7 +39,7 @@
#include <string.h>
#include <stdint.h>
#include <errno.h>
-#include <values.h>
+#include <limits.h>
#include <OpenIPMI/ipmiif.h>
#include <OpenIPMI/ipmi_fru.h>
diff -ur OpenIPMI/lib/oem_intel.c OpenIPMI-patched/lib/oem_intel.c
--- OpenIPMI/lib/oem_intel.c 2007-07-12 08:06:25.000000000 +0400
+++ OpenIPMI-patched/lib/oem_intel.c 2010-04-16 00:16:31.304802343 +0400
@@ -31,7 +31,6 @@
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <alloca.h>
#include <string.h>
#include <stdlib.h>
diff -ur OpenIPMI/sample/dump_sensors.c OpenIPMI-patched/sample/dump_sensors.c
--- OpenIPMI/sample/dump_sensors.c 2008-12-09 21:33:12.000000000 +0300
+++ OpenIPMI-patched/sample/dump_sensors.c 2010-04-16 00:24:00.078553756 +0400
@@ -30,7 +30,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
diff -ur OpenIPMI/sample/ipmi_serial_bmc_emu.c OpenIPMI-patched/sample/ipmi_serial_bmc_emu.c
--- OpenIPMI/sample/ipmi_serial_bmc_emu.c 2008-11-07 18:20:29.000000000 +0300
+++ OpenIPMI-patched/sample/ipmi_serial_bmc_emu.c 2010-04-16 00:41:20.549690171 +0400
@@ -37,7 +37,6 @@
#include <netinet/tcp.h>
#include <netdb.h>
#include <errno.h>
-#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
diff -ur OpenIPMI/sample/sample.c OpenIPMI-patched/sample/sample.c
--- OpenIPMI/sample/sample.c 2008-04-21 17:41:17.000000000 +0400
+++ OpenIPMI-patched/sample/sample.c 2010-04-16 00:23:23.448742984 +0400
@@ -31,7 +31,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
diff -ur OpenIPMI/sample/sample2.c OpenIPMI-patched/sample/sample2.c
--- OpenIPMI/sample/sample2.c 2006-07-13 02:56:58.000000000 +0400
+++ OpenIPMI-patched/sample/sample2.c 2010-04-16 00:23:30.035289877 +0400
@@ -31,7 +31,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <malloc.h>
#include <unistd.h>
#include <signal.h>
diff -ur OpenIPMI/sample/sample3.c OpenIPMI-patched/sample/sample3.c
--- OpenIPMI/sample/sample3.c 2006-07-13 02:56:58.000000000 +0400
+++ OpenIPMI-patched/sample/sample3.c 2010-04-16 00:23:32.145295199 +0400
@@ -30,7 +30,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
diff -ur OpenIPMI/sample/solterm.c OpenIPMI-patched/sample/solterm.c
--- OpenIPMI/sample/solterm.c 2006-04-05 02:30:42.000000000 +0400
+++ OpenIPMI-patched/sample/solterm.c 2010-04-16 00:23:14.621666637 +0400
@@ -33,7 +33,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
diff -ur OpenIPMI/unix/selector.c OpenIPMI-patched/unix/selector.c
--- OpenIPMI/unix/selector.c 2008-09-08 00:48:27.000000000 +0400
+++ OpenIPMI-patched/unix/selector.c 2010-04-16 12:40:55.391123058 +0400
@@ -49,7 +49,6 @@
#include <syslog.h>
#include <signal.h>
#include <string.h>
-#include <malloc.h>
typedef struct fd_state_s
{
@@ -809,7 +808,7 @@
sel_alloc_selector(os_handler_t *os_hnd, selector_t **new_selector)
{
selector_t *sel;
- int i;
+ unsigned int i;
int rv;
sel = malloc(sizeof(*sel));
diff -ur OpenIPMI/unix/test_heap.c OpenIPMI-patched/unix/test_heap.c
--- OpenIPMI/unix/test_heap.c 2004-09-02 20:51:27.000000000 +0400
+++ OpenIPMI-patched/unix/test_heap.c 2010-04-16 00:17:33.238117052 +0400
@@ -36,7 +36,6 @@
#include <signal.h>
#include <string.h>
#include <time.h>
-#include <malloc.h>
#define HEAP_EXPORT_NAME(s) test_ ## s
typedef struct heap_val_s { int a; } heap_val_t;
И патча, исправляющего вызов sendto:
diff -ur OpenIPMI/lib/ipmi_lan.c OpenIPMI-patch/lib/ipmi_lan.c
--- OpenIPMI/lib/ipmi_lan.c 2009-06-17 16:55:22.000000000 +0400
+++ OpenIPMI-patch/lib/ipmi_lan.c 2010-04-27 17:46:18.075276480 +0400
@@ -1810,6 +1810,7 @@
ipmi_payload_t *payload = NULL;
unsigned char oem_iana[3] = {0, 0, 0};
unsigned int oem_payload_id = 0;
+ socklen_t to_len;
if ((addr->addr_type >= IPMI_RMCPP_ADDR_START)
&& (addr->addr_type <= IPMI_RMCPP_ADDR_END))
@@ -1915,9 +1916,15 @@
add_stat(lan->ipmi, STAT_XMIT_PACKETS, 1);
+#ifdef PF_INET6
+ if (((struct sockaddr)(lan->cparm.ip_addr[addr_num].s_ipsock.s_addr)).sa_family==AF_INET6)
+ to_len = sizeof(struct sockaddr_in6);
+ else
+#endif
+ to_len = sizeof(struct sockaddr_in);
rv = sendto(lan->fd->fd, tmsg, pos, 0,
(struct sockaddr *) &(lan->cparm.ip_addr[addr_num]),
- sizeof(sockaddr_ip_t));
+ to_len);
if (rv == -1)
rv = errno;
else
я написал автору OpenIPMI - Corey Minyard. Переписка заняла пару дней, по истечении которых Corey принял все патчи, позволяющие собрать OpenIPMI на FreeBSD:
http://openipmi.cvs.sourceforge.net/viewvc/openipmi/OpenIPMI/ChangeLog?view=log
2010-04-21 Alex Deiter <alex.deiter@gmail.com>
* cmdlang/ipmish.c, cmdlang/out_fru.c, configure.in,
lanserv/OpenIPMI/lanserv.h, lanserv/emu.h, lanserv/lanserv.c,
lanserv/lanserv_emu.c, lib/fru_spd_decode.c, lib/oem_intel.c,
sample/dump_sensors.c, sample/ipmi_serial_bmc_emu.c,
sample/sample.c, sample/sample2.c, sample/sample3.c
sample/solterm.c, unix/selector.c, unix/test_heap.c:
Get OpenIPMI to compile under FreeBSD.
Патч для sendto он посчитал необходимым кардинально переписать, добавив длину адреса получателя в структуру struct sockaddr_ip_s:
2010-04-27 Corey Minyard <cminyard@mvista.com>
* lib/sensor.c: Use unsigned int, not double, to hold the raw
sensor value.
* lib/ipmi_lan.c: Pass in the correct socket length to sendto,
not just the maximum possible size.
Далее я попробовал собрать пакет со всеми возможными зависимостями и получил еще несколько ошибок при сборке Python и Perl модулей:
libtool: link: gcc -Wall -o .libs/OpenIPMI.so OpenIPMI_wrap.o
OpenIPMI_perl.o ../../unix/.libs/libOpenIPMIposix.so -L/usr/local/lib
../../lib/.libs/libOpenIPMI.so ../../utils/.libs/libOpenIPMIutils.so
../../cmdlang/.libs/libOpenIPMIcmdlang.so
/home/tiamat/tmp/port/OpenIPMI/lib/.libs/libOpenIPMI.so -lm
/home/tiamat/tmp/port/OpenIPMI/utils/.libs/libOpenIPMIutils.so
-lcrypto -Wl,-rpath -Wl,/var/tmp/openipmi/lib
/usr/lib/crt1.o(.text+0x8a): In function `_start':
: undefined reference to `main'
OpenIPMI_wrap.o(.text+0xed0): In function `SWIG_Perl_ConvertPtr':
/home/tiamat/tmp/port/OpenIPMI/swig/perl/OpenIPMI_wrap.c:1119:
undefined reference to `Perl_Gthr_key_ptr'
OpenIPMI_wrap.o(.text+0xee3):/home/tiamat/tmp/port/OpenIPMI/swig/perl/OpenIPMI_wrap.c:1119:
undefined reference to `Perl_mg_get'
OpenIPMI_wrap.o(.text+0xeed):/home/tiamat/tmp/port/OpenIPMI/swig/perl/OpenIPMI_wrap.c:1122:
undefined reference to `Perl_Gthr_key_ptr'
OpenIPMI_wrap.o(.text+0xf00):/home/tiamat/tmp/port/OpenIPMI/swig/perl/OpenIPMI_wrap.c:1122:
undefined reference to `Perl_sv_isobject'
...
gcc -Wall -DHAVE_CONFIG_H -I/usr/local/include/python2.6 -I ../.. -I
../../include -I ../../include -I ../../swig/python -ggdb -fPIC
-DPYTHON_HAS_POSIX_THREADS=1 -c OpenIPMI_wrap.c
OpenIPMI_wrap.c: In function 'parse_ip_addr':
OpenIPMI_wrap.c:2979: error: 'PF_UNSPEC' undeclared (first use in this function)
OpenIPMI_wrap.c:2979: error: (Each undeclared identifier is reported only once
OpenIPMI_wrap.c:2979: error: for each function it appears in.)
OpenIPMI_wrap.c:2980: error: 'SOCK_DGRAM' undeclared (first use in
this function)
OpenIPMI_wrap.c:2988: error: 'PF_INET' undeclared (first use in this function)
OpenIPMI_wrap.c: In function 'vswig_call_cb_rv':
Также я обнаружил, что все разделяемые библиотеки OpenIPMI почему-то слинкованы с libncurses:
$ ldd /var/tmp/openipmi/lib/lib*.so|grep curs
libncurses.so.8 => /lib/libncurses.so.8 (0x80096f000)
libncurses.so.8 => /lib/libncurses.so.8 (0x8013a2000)
libncurses.so.8 => /lib/libncurses.so.8 (0x8014c1000)
libncurses.so.8 => /lib/libncurses.so.8 (0x800a6c000)
libncurses.so.8 => /lib/libncurses.so.8 (0x801000000)
libncurses.so.8 => /lib/libncurses.so.8 (0x80098b000)
libncurses.so.8 => /lib/libncurses.so.8 (0x800966000)
Написав еще несколько патчей:
diff -ur OpenIPMI.orig/swig/OpenIPMI.i OpenIPMI/swig/OpenIPMI.i
--- OpenIPMI.orig/swig/OpenIPMI.i 2008-04-13 07:00:11.000000000 +0400
+++ OpenIPMI/swig/OpenIPMI.i 2010-04-28 00:24:03.562178026 +0400
@@ -36,6 +36,8 @@
%{
#include <config.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#ifdef HAVE_GETADDRINFO
#include <netdb.h>
diff -ur OpenIPMI.orig/swig/python/Makefile.am OpenIPMI/swig/python/Makefile.am
--- OpenIPMI.orig/swig/python/Makefile.am 2010-03-24 19:52:23.000000000 +0300
+++ OpenIPMI/swig/python/Makefile.am 2010-04-28 00:34:47.684857305 +0400
@@ -5,52 +5,39 @@
-I $(top_builddir) \
-I $(top_builddir)/include \
-I $(top_srcdir)/include \
- -I $(top_srcdir)/swig/python
+ -I $(top_srcdir)/swig/python \
+ -DPYTHON_HAS_POSIX_THREADS=@PYTHON_HAS_POSIX_THREADS@
-CC = @CC@ -Wall
-CFLAGS = @CFLAGS@ -fPIC -DPYTHON_HAS_POSIX_THREADS=@PYTHON_HAS_POSIX_THREADS@
-DEFS = @DEFS@
+pythonlibdir=$(PYTHON_INSTALL_LIB_DIR)
+PYPATH=$(top_builddir)/swig/python:$(top_builddir)/swig/python/.libs:$(srcdir)/openipmigui
-COMPILE = $(CC) $(DEFS) $(AM_CFLAGS) $(CFLAGS)
+pythonlib_LTLIBRARIES = _OpenIPMI.la
-all-local: _OpenIPMI.so
-
-OpenIPMI_SRC = OpenIPMI_wrap.c
-OpenIPMI_OBJ = OpenIPMI_wrap.o
+_OpenIPMI_la_SOURCES = OpenIPMI_wrap.c
+_OpenIPMI_la_LDFLAGS = -module -avoid-version
+_OpenIPMI_la_LIBADD = $(OPENIPMI_SWIG_LIBS) $(PYTHON_POSIX_LIB)
EXTRA_DIST = OpenIPMI_lang.i OpenIPMI.h openipmigui.py sample.py
-_OpenIPMI.so: $(OpenIPMI_OBJ)
- $(LIBTOOL) --mode=link $(CC) -shared -o $@ $^ $(OPENIPMI_SWIG_LIBS)
- rm _OpenIPMI.so
- mv .libs/_OpenIPMI.so .
- rm -rf .libs
-
-OpenIPMI_wrap.o OpenIPMI.py: OpenIPMI_wrap.c OpenIPMI.h
- $(COMPILE) -c $<
-
-OpenIPMI.pyc: OpenIPMI.py _OpenIPMI.so
- -$(pythonprog) -c 'import OpenIPMI.py'
+OpenIPMI.pyc: OpenIPMI.py _OpenIPMI.la
+ -PYTHONPATH=$(PYPATH) $(pythonprog) -c 'import OpenIPMI.py'
-OpenIPMI.pyo: OpenIPMI.py _OpenIPMI.so
- -$(pythonprog) -O -c 'import OpenIPMI.py'
+OpenIPMI.pyo: OpenIPMI.py _OpenIPMI.la
+ -PYTHONPATH=$(PYPATH) $(pythonprog) -O -c 'import OpenIPMI.py'
-OpenIPMI_wrap.c: $(top_srcdir)/swig/OpenIPMI.i OpenIPMI_lang.i
+OpenIPMI_wrap.c OpenIPMI.py: $(top_srcdir)/swig/OpenIPMI.i OpenIPMI_lang.i
$(SWIG) $(DEFS) -python -o $@ -I$(top_srcdir)/swig/python $<
-CLEANFILES = $(OpenIPMI_OBJ) _OpenIPMI.so OpenIPMI_wrap.c \
- OpenIPMI.py OpenIPMI.pyo OpenIPMI.pyc
+CLEANFILES = OpenIPMI_wrap.c OpenIPMI.py OpenIPMI.pyo OpenIPMI.pyc
-install-exec-local: _OpenIPMI.so OpenIPMI.py OpenIPMI.pyc OpenIPMI.pyo
+install-exec-local: _OpenIPMI.la OpenIPMI.py OpenIPMI.pyc OpenIPMI.pyo
$(INSTALL) -d $(DESTDIR)$(PYTHON_INSTALL_DIR)
- $(INSTALL) -d $(DESTDIR)$(PYTHON_INSTALL_LIB_DIR)
- $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) _OpenIPMI.so "$(DESTDIR)$(PYTHON_INSTALL_LIB_DIR)/"
$(INSTALL_DATA) OpenIPMI.py "$(DESTDIR)$(PYTHON_INSTALL_DIR)"
$(INSTALL_DATA) OpenIPMI.pyc "$(DESTDIR)$(PYTHON_INSTALL_DIR)"
$(INSTALL_DATA) OpenIPMI.pyo "$(DESTDIR)$(PYTHON_INSTALL_DIR)"
if test "x$(PYTHON_GUI_DIR)" = "xopenipmigui"; then \
$(INSTALL) -d $(DESTDIR)$(bindir); \
- $(INSTALL_PROGRAM) openipmigui.py "$(DESTDIR)$(bindir)/openipmigui";\
+ $(INSTALL_SCRIPT) openipmigui.py "$(DESTDIR)$(bindir)/openipmigui";\
fi
uninstall-local:
@@ -60,7 +47,5 @@
rm -f "$(DESTDIR)$(PYTHON_INSTALL_DIR)/OpenIPMI.pyo"
rm -f "$(DESTDIR)$(bindir)/openipmigui"
-PYPATH=$(top_builddir)/swig/python:$(srcdir)/openipmigui
-
rungui:
LD_LIBRARY_PATH=$(top_builddir)/glib/.libs LD_PRELOAD=$(OPENIPMI_SWIG_SO):$(top_builddir)/swig/python/_OpenIPMI.so PYTHONPATH=$(PYPATH) $(pythonprog) $(top_srcdir)/swig/python/openipmigui.py
diff -ur OpenIPMI.orig/swig/python/openipmigui/Makefile.am OpenIPMI/swig/python/openipmigui/Makefile.am
--- OpenIPMI.orig/swig/python/openipmigui/Makefile.am 2007-10-02 18:48:05.000000000 +0400
+++ OpenIPMI/swig/python/openipmigui/Makefile.am 2010-04-28 00:35:58.905028305 +0400
@@ -35,12 +35,12 @@
done)
-rmdir "$(DESTDIR)$(PYTHON_INSTALL_DIR)/openipmigui"
-PYPATH=$(top_builddir)/swig/python:$(srcdir)
+PYPATH=$(top_builddir)/swig/python:$(top_builddir)/swig/python/.libs:$(srcdir)
.py.pyc:
- LD_PRELOAD=$(OPENIPMI_SWIG_SO):$(top_builddir)/swig/python/_OpenIPMI.so PYTHONPATH=$(PYPATH) $(pythonprog) -c 'import $*'
+ LD_PRELOAD=$(OPENIPMI_SWIG_SO):$(top_builddir)/swig/python/.libs/_OpenIPMI.so PYTHONPATH=$(PYPATH) $(pythonprog) -c 'import $*'
.py.pyo:
- LD_PRELOAD=$(OPENIPMI_SWIG_SO):$(top_builddir)/swig/python/_OpenIPMI.so PYTHONPATH=$(PYPATH) $(pythonprog) -O -c 'import $*'
+ LD_PRELOAD=$(OPENIPMI_SWIG_SO):$(top_builddir)/swig/python/.libs/_OpenIPMI.so PYTHONPATH=$(PYPATH) $(pythonprog) -O -c 'import $*'
CLEANFILES = $(PYC_FILES) $(PYO_FILES)
diff -ur OpenIPMI.orig/swig/perl/Makefile.am OpenIPMI/swig/perl/Makefile.am
--- OpenIPMI.orig/swig/perl/Makefile.am 2008-04-11 09:26:04.000000000 +0400
+++ OpenIPMI/swig/perl/Makefile.am 2010-04-28 00:01:14.696236964 +0400
@@ -16,19 +16,19 @@
all: OpenIPMI.so
OpenIPMI_SRC = OpenIPMI_wrap.c OpenIPMI_perl.c
-OpenIPMI_OBJ = OpenIPMI_wrap.o OpenIPMI_perl.o
+OpenIPMI_OBJ = OpenIPMI_wrap.lo OpenIPMI_perl.lo
OpenIPMI.so: $(OpenIPMI_OBJ)
- $(LIBTOOL) --mode=link $(CC) -shared -o $@ $^ $(OPENIPMI_SWIG_LIBS)
- rm OpenIPMI.so
+ $(LIBTOOL) --mode=link $(CC) -shared -module -avoid-version -o $(@:.so=.la) $^ $(OPENIPMI_SWIG_LIBS) $(PERL_POSIX_LIB) -rpath $(PERL_INSTALL_DIR)/auto/OpenIPMI
+ rm -f OpenIPMI.so
mv .libs/OpenIPMI.so .
rm -rf .libs
-OpenIPMI_wrap.o: OpenIPMI_wrap.c OpenIPMI.h
- $(COMPILE) -c $<
+OpenIPMI_wrap.lo: OpenIPMI_wrap.c OpenIPMI.h
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
-OpenIPMI_perl.o: OpenIPMI_perl.c OpenIPMI.h
- $(COMPILE) -c $<
+OpenIPMI_perl.lo: OpenIPMI_perl.c OpenIPMI.h
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
OpenIPMI_wrap.c OpenIPMI.pm: $(top_srcdir)/swig/OpenIPMI.i OpenIPMI_lang.i
$(SWIG) $(DEFS) -perl5 -o $@ -I$(top_srcdir)/swig/perl $<
@@ -38,7 +38,7 @@
install-exec-local: OpenIPMI.so OpenIPMI.pm
$(INSTALL) -d "$(DESTDIR)$(PERL_INSTALL_DIR)/auto/OpenIPMI"
$(INSTALL_PROGRAM) OpenIPMI.so "$(DESTDIR)$(PERL_INSTALL_DIR)/auto/OpenIPMI"
- $(INSTALL_PROGRAM) OpenIPMI.pm "$(DESTDIR)$(PERL_INSTALL_DIR)"
+ $(INSTALL_DATA) OpenIPMI.pm "$(DESTDIR)$(PERL_INSTALL_DIR)"
uninstall-local:
$(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(PERL_INSTALL_DIR)/auto/OpenIPMI/OpenIPMI.so"
diff -ur OpenIPMI.orig/cmdlang/Makefile.am OpenIPMI/cmdlang/Makefile.am
--- OpenIPMI.orig/cmdlang/Makefile.am 2007-10-02 18:48:05.000000000 +0400
+++ OpenIPMI/cmdlang/Makefile.am 2010-04-27 23:39:13.064860630 +0400
@@ -33,6 +33,7 @@
$(top_builddir)/lib/libOpenIPMI.la \
$(top_builddir)/unix/libOpenIPMIposix.la \
$(top_builddir)/libedit/libedit.a \
+ $(TERM_LIBS) \
$(SNMPLIBS) $(GLIB_LIB) $(GLIB_LIBS) \
$(TCL_LIB) $(TCL_LIBS) \
$(OPENSSLLIBS) $(GDBM_LIB)
diff -ur OpenIPMI.orig/configure.in OpenIPMI/configure.in
--- OpenIPMI.orig/configure.in 2010-04-21 18:10:54.000000000 +0400
+++ OpenIPMI/configure.in 2010-04-27 23:45:01.647949542 +0400
@@ -849,8 +849,8 @@
*-sun-*) AC_DEFINE([_SUNOS], [], [Solaris's term.h does horrid things.]);;
esac
-AC_CHECK_LIB(curses, tgetent,,
- [AC_CHECK_LIB(ncurses, tgetent,,
+AC_CHECK_LIB(curses, tgetent, TERM_LIBS=-lcurses,
+ [AC_CHECK_LIB(ncurses, tgetent, TERM_LIBS=-lncurses,
[AC_MSG_ERROR([libtermcap, libcurses or libncurses are required!])] )] )
# Checks for header files.
@@ -888,6 +888,7 @@
AC_CHECK_FUNCS([endpwent isascii memchr memset re_comp regcomp strcasecmp strchr strcspn strdup strerror strrchr strstr strtol issetugid])
EL_GETPW_R_POSIX
EL_GETPW_R_DRAFT
+AC_SUBST(TERM_LIBS)
# End of libedit inclusions
diff -ur OpenIPMI.orig/sample/Makefile.am OpenIPMI/sample/Makefile.am
--- OpenIPMI.orig/sample/Makefile.am 2008-09-08 00:48:27.000000000 +0400
+++ OpenIPMI/sample/Makefile.am 2010-04-27 23:42:08.861654636 +0400
@@ -52,7 +52,7 @@
rmcp_ping_SOURCES = rmcp_ping.c
ipmi_serial_bmc_emu_SOURCES = ipmi_serial_bmc_emu.c
-ipmi_serial_bmc_emu_LDADD = $(top_builddir)/libedit/libedit.a
+ipmi_serial_bmc_emu_LDADD = $(top_builddir)/libedit/libedit.a $(TERM_LIBS)
ipmi_serial_bmc_emu_CFLAGS = -I $(top_srcdir)/libedit
EXTRA_DIST = example_oem.c
я попросил автора выпустить по этому поводу новую версию OpenIPMI, которая включала бы в себя все сделанные изменения. Corey Minyard не заставил себя долго ждать и через пару дней для загрузки стал доступен релиз OpenIPMI 2.0.17, на основе которого я сделал порт OpenIPMI для FreeBSD.
Этот PR еще не добавлен в коллекцию портов, поэтому пока я не отправлял патч для zabbix-server, добавляющий IPMI опцию сборки:
$ diff -u net-mgmt/zabbix-server/Makefile.orig net-mgmt/zabbix-server/Makefile
--- net-mgmt/zabbix-server/Makefile.orig 2010-04-29 11:11:54.509380512 +0400
+++ net-mgmt/zabbix-server/Makefile 2010-04-29 11:47:25.881947696 +0400
@@ -60,6 +60,7 @@
SQLITE "Use SQLite backend" off \
IPV6 "Support for IPv6" on \
LDAP "Support for checking LDAP servers" on \
+ IPMI "Support for IPMI" off \
JABBER "Use jabber media type" on \
FPING "Use fping for pinging hosts" on \
SSH "Use libssh2 for SSH-based checks" off
@@ -87,6 +88,11 @@
CONFIGURE_ARGS+= --with-ldap
.endif
+.ifndef WITHOUT_IPMI
+LIB_DEPENDS+= OpenIPMI:${PORTSDIR}/sysutils/OpenIPMI
+CONFIGURE_ARGS+= --with-openipmi
+.endif
+
.ifndef WITHOUT_JABBER
LIB_DEPENDS+= iksemel:${PORTSDIR}/textproc/iksemel
CONFIGURE_ARGS+= --with-jabber
Тем не менее все эти изменения прошли тестирование и с успехом могут использоваться при мониторинге IPMI-совместимых систем. Об этом я как-нибудь напишу отдельную заметку.
P.S. 14.05.2010 в коллекцию портов FreeBSD добавлено приложение sysutils/openipmi.
P.P.S. 01.06.2010 открыт PR 147287
P.P.P.S. 30.06.2010 для zabbix-server в коллекции портов FreeBSD добавлена поддержка IPMI: PR 146581