1 /*
2 * Copyright (C) 2011-2021 - EATON
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 /*! \file nutscan-init.c
20 \brief init functions for nut scanner library
21 \author Frederic Bohe <fredericbohe@eaton.com>
22 */
23
24 #include "common.h"
25 #include "nutscan-init.h"
26 #include <ltdl.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include "nut-scan.h"
31
32 int nutscan_avail_avahi = 0;
33 int nutscan_avail_ipmi = 0;
34 int nutscan_avail_nut = 0;
35 int nutscan_avail_snmp = 0;
36 int nutscan_avail_usb = 0;
37 int nutscan_avail_xml_http = 0;
38
39 int nutscan_load_usb_library(const char *libname_path);
40 int nutscan_load_snmp_library(const char *libname_path);
41 int nutscan_load_neon_library(const char *libname_path);
42 int nutscan_load_avahi_library(const char *libname_path);
43 int nutscan_load_ipmi_library(const char *libname_path);
44 int nutscan_load_upsclient_library(const char *libname_path);
45
46 #ifdef HAVE_PTHREAD
47 # ifdef HAVE_SEMAPHORE
48 /* Shared by library consumers, exposed by nutscan_semaphore() below */
49 static sem_t semaphore;
50
nutscan_semaphore(void)51 sem_t * nutscan_semaphore(void)
52 {
53 return &semaphore;
54 }
55 # endif /* HAVE_SEMAPHORE */
56
57 # ifdef HAVE_PTHREAD_TRYJOIN
58 pthread_mutex_t threadcount_mutex;
59 # endif
60
61 # if (defined HAVE_PTHREAD_TRYJOIN) || (defined HAVE_SEMAPHORE)
62 /* We have 3 networked scan types: nut, snmp, xml,
63 * and users typically give their /24 subnet as "-m" arg.
64 * With some systems having a 1024 default (u)limit to
65 * file descriptors, this should fit if those are involved.
66 * On some systems tested, a large amount of not-joined
67 * pthreads did cause various crashes; also RAM is limited.
68 * Note that each scan may be time consuming to query an
69 * IP address and wait for (no) reply, so while these threads
70 * are usually not resource-intensive (nor computationally),
71 * they spend much wallclock time each so parallelism helps.
72 */
73 size_t max_threads = DEFAULT_THREAD;
74 size_t curr_threads = 0;
75
76 size_t max_threads_netxml = 1021; /* experimental finding, see PR#1158 */
77 size_t max_threads_oldnut = 1021;
78 size_t max_threads_netsnmp = 0; // 10240;
79 /* per reports in PR#1158, some versions of net-snmp could be limited
80 * to 1024 threads in the past; this was not found in practice.
81 * Still, some practical limit can be useful (configurable?)
82 * Here 0 means to not apply any special limit (beside max_threads).
83 */
84
85 # endif /* HAVE_PTHREAD_TRYJOIN || HAVE_SEMAPHORE */
86
87 #endif /* HAVE_PTHREAD */
88
nutscan_init(void)89 void nutscan_init(void)
90 {
91 #ifdef HAVE_PTHREAD
92 /* TOTHINK: Should semaphores to limit thread count
93 * and the more naive but portable methods be an
94 * if-else proposition? At least when initializing?
95 */
96 # ifdef HAVE_SEMAPHORE
97 /* NOTE: This semaphore may get re-initialized in nut-scanner program
98 * after parsing command-line arguments. It calls nutscan_init() before
99 * parsing CLI, to know about available libs and to set defaults below.
100 */
101 if (SIZE_MAX > UINT_MAX && max_threads > UINT_MAX) {
102 upsdebugx(1,
103 "WARNING: %s: Limiting max_threads to range acceptable for sem_init()",
104 __func__);
105 max_threads = UINT_MAX - 1;
106 }
107 sem_init(&semaphore, 0, (unsigned int)max_threads);
108 # endif
109
110 # ifdef HAVE_PTHREAD_TRYJOIN
111 pthread_mutex_init(&threadcount_mutex, NULL);
112 # endif
113 #endif /* HAVE_PTHREAD */
114
115 char *libname = NULL;
116 #ifdef WITH_USB
117 libname = get_libname("libusb-0.1.so");
118 if (!libname) {
119 /* We can also use libusb-compat from newer libusb-1.0 releases */
120 libname = get_libname("libusb.so");
121 }
122 if (libname) {
123 nutscan_avail_usb = nutscan_load_usb_library(libname);
124 free(libname);
125 }
126 #endif
127 #ifdef WITH_SNMP
128 libname = get_libname("libnetsnmp.so");
129 if (libname) {
130 nutscan_avail_snmp = nutscan_load_snmp_library(libname);
131 free(libname);
132 }
133 #endif
134 #ifdef WITH_NEON
135 libname = get_libname("libneon.so");
136 if (!libname) {
137 libname = get_libname("libneon-gnutls.so");
138 }
139 if (libname) {
140 nutscan_avail_xml_http = nutscan_load_neon_library(libname);
141 free(libname);
142 }
143 #endif
144 #ifdef WITH_AVAHI
145 libname = get_libname("libavahi-client.so");
146 if (libname) {
147 nutscan_avail_avahi = nutscan_load_avahi_library(libname);
148 free(libname);
149 }
150 #endif
151 #ifdef WITH_FREEIPMI
152 libname = get_libname("libfreeipmi.so");
153 if (libname) {
154 nutscan_avail_ipmi = nutscan_load_ipmi_library(libname);
155 free(libname);
156 }
157 #endif
158 libname = get_libname("libupsclient.so");
159 if (libname) {
160 nutscan_avail_nut = nutscan_load_upsclient_library(libname);
161 free(libname);
162 }
163 }
164
nutscan_free(void)165 void nutscan_free(void)
166 {
167 if (nutscan_avail_usb) {
168 lt_dlexit();
169 }
170 if (nutscan_avail_snmp) {
171 lt_dlexit();
172 }
173 if (nutscan_avail_xml_http) {
174 lt_dlexit();
175 }
176 if (nutscan_avail_avahi) {
177 lt_dlexit();
178 }
179 if (nutscan_avail_ipmi) {
180 lt_dlexit();
181 }
182 if (nutscan_avail_nut) {
183 lt_dlexit();
184 }
185
186 #ifdef HAVE_PTHREAD
187 /* TOTHINK: See comments near mutex/semaphore init code above */
188 # ifdef HAVE_SEMAPHORE
189 sem_destroy(nutscan_semaphore());
190 # endif
191
192 # ifdef HAVE_PTHREAD_TRYJOIN
193 pthread_mutex_destroy(&threadcount_mutex);
194 # endif
195 #endif
196
197 }
198