1
2// Environment_UNIX.cpp
3//
4// Library: Foundation
5// Package: Core
6// Module: Environment
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Environment_UNIX.h"
16#include "Poco/Exception.h"
17#include "Poco/Buffer.h"
18#include <cstring>
19#include <unistd.h>
20#include <stdlib.h>
21#include <sys/utsname.h>
22#include <sys/param.h>
23#if defined(POCO_OS_FAMILY_BSD)
24#include <sys/sysctl.h>
25#elif POCO_OS == POCO_OS_HPUX
26#include <pthread.h>
27#endif
28
29
30namespace Poco {
31
32
33EnvironmentImpl::StringMap EnvironmentImpl::_map;
34FastMutex EnvironmentImpl::_mutex;
35
36
37std::string EnvironmentImpl::getImpl(const std::string& name)
38{
39 FastMutex::ScopedLock lock(_mutex);
40
41 const char* val = getenv(name.c_str());
42 if (val)
43 return std::string(val);
44 else
45 throw NotFoundException(name);
46}
47
48
49bool EnvironmentImpl::hasImpl(const std::string& name)
50{
51 FastMutex::ScopedLock lock(_mutex);
52
53 return getenv(name.c_str()) != 0;
54}
55
56
57void EnvironmentImpl::setImpl(const std::string& name, const std::string& value)
58{
59 FastMutex::ScopedLock lock(_mutex);
60
61 std::string var = name;
62 var.append("=");
63 var.append(value);
64 _map[name] = var;
65 if (putenv((char*) _map[name].c_str()))
66 {
67 std::string msg = "cannot set environment variable: ";
68 msg.append(name);
69 throw SystemException(msg);
70 }
71}
72
73
74std::string EnvironmentImpl::osNameImpl()
75{
76 struct utsname uts;
77 uname(&uts);
78 return uts.sysname;
79}
80
81
82std::string EnvironmentImpl::osDisplayNameImpl()
83{
84 return osNameImpl();
85}
86
87
88std::string EnvironmentImpl::osVersionImpl()
89{
90 struct utsname uts;
91 uname(&uts);
92 return uts.release;
93}
94
95
96std::string EnvironmentImpl::osArchitectureImpl()
97{
98 struct utsname uts;
99 uname(&uts);
100 return uts.machine;
101}
102
103
104std::string EnvironmentImpl::nodeNameImpl()
105{
106 struct utsname uts;
107 uname(&uts);
108 return uts.nodename;
109}
110
111
112unsigned EnvironmentImpl::processorCountImpl()
113{
114#if defined(_SC_NPROCESSORS_ONLN)
115 int count = sysconf(_SC_NPROCESSORS_ONLN);
116 if (count <= 0) count = 1;
117 return static_cast<int>(count);
118#elif defined(POCO_OS_FAMILY_BSD)
119 unsigned count;
120 std::size_t size = sizeof(count);
121 if (sysctlbyname("hw.ncpu", &count, &size, 0, 0))
122 return 1;
123 else
124 return count;
125#elif POCO_OS == POCO_OS_HPUX
126 return pthread_num_processors_np();
127#else
128 return 1;
129#endif
130}
131
132
133} // namespace Poco
134
135
136//
137// nodeIdImpl
138//
139#if defined(POCO_OS_FAMILY_BSD) || POCO_OS == POCO_OS_QNX
140//
141// BSD variants
142//
143#include <sys/types.h>
144#include <sys/socket.h>
145#include <ifaddrs.h>
146#include <net/if_dl.h>
147
148
149namespace Poco {
150
151
152void EnvironmentImpl::nodeIdImpl(NodeId& id)
153{
154 std::memset(&id, 0, sizeof(id));
155 struct ifaddrs* ifaphead;
156 int rc = getifaddrs(&ifaphead);
157 if (rc) return;
158
159 for (struct ifaddrs* ifap = ifaphead; ifap; ifap = ifap->ifa_next)
160 {
161 if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_LINK)
162 {
163 struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>(ifap->ifa_addr);
164 caddr_t ap = LLADDR(sdl);
165 int alen = sdl->sdl_alen;
166 if (ap && alen > 0)
167 {
168 std::memcpy(&id, ap, sizeof(id));
169 break;
170 }
171 }
172 }
173 freeifaddrs(ifaphead);
174}
175
176
177} // namespace Poco
178
179
180#elif defined(__CYGWIN__) || POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID
181//
182// Linux, Cygwin
183//
184#include <sys/ioctl.h>
185#include <sys/socket.h>
186#include <netinet/in.h>
187#include <net/if.h>
188#ifndef __CYGWIN__
189#include <net/if_arp.h>
190#else // workaround for Cygwin, which does not have if_arp.h
191#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */
192#endif
193#include <arpa/inet.h>
194#include <unistd.h>
195#include <sys/types.h>
196#include <sys/stat.h>
197#include <fcntl.h>
198#include <cstdio>
199
200
201namespace Poco {
202
203
204void EnvironmentImpl::nodeIdImpl(NodeId& id)
205{
206 std::memset(&id, 0, sizeof(id));
207
208 // ideally, the following code should be rewritten
209 // to use netlink
210
211 // first try to obtain the MAC address of eth0 using /sys/class/net
212 int fd = open("/sys/class/net/eth0/address", O_RDONLY);
213 if (fd >= 0)
214 {
215 char buffer[18];
216 int n = read(fd, buffer, 17);
217 close(fd);
218 if (n == 17)
219 {
220 buffer[n] = 0;
221 if (std::sscanf(buffer, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &id[0], &id[1], &id[2], &id[3], &id[4], &id[5]) == 6)
222 return;
223 }
224 }
225
226 // if that did not work, search active interfaces
227 int sock = socket(PF_INET, SOCK_DGRAM, 0);
228 if (sock == -1) return;
229
230 // the following code is loosely based
231 // on W. Richard Stevens, UNIX Network Programming, pp 434ff.
232 int lastlen = 0;
233 int len = 100*sizeof(struct ifreq);
234 struct ifconf ifc;
235 char* buf = 0;
236 for (;;)
237 {
238 buf = new char[len];
239 ifc.ifc_len = len;
240 ifc.ifc_buf = buf;
241 if (::ioctl(sock, SIOCGIFCONF, &ifc) < 0)
242 {
243 if (errno != EINVAL || lastlen != 0)
244 {
245 close(sock);
246 delete [] buf;
247 return;
248 }
249 }
250 else
251 {
252 if (ifc.ifc_len == lastlen)
253 break;
254 lastlen = ifc.ifc_len;
255 }
256 len += 10*sizeof(struct ifreq);
257 delete [] buf;
258 }
259 for (const char* ptr = buf; ptr < buf + ifc.ifc_len;)
260 {
261 const struct ifreq* ifr = reinterpret_cast<const struct ifreq*>(ptr);
262 int rc = ioctl(sock, SIOCGIFHWADDR, ifr);
263 if (rc != -1)
264 {
265 const struct sockaddr* sa = reinterpret_cast<const struct sockaddr*>(&ifr->ifr_hwaddr);
266 if (sa->sa_family == ARPHRD_ETHER)
267 {
268 std::memcpy(&id, sa->sa_data, sizeof(id));
269 break;
270 }
271 }
272 ptr += sizeof(struct ifreq);
273 }
274 close(sock);
275 delete [] buf;
276}
277
278
279} // namespace Poco
280
281
282#elif defined(POCO_OS_FAMILY_UNIX)
283//
284// General Unix
285//
286#include <sys/ioctl.h>
287#if defined(sun) || defined(__sun)
288#include <sys/sockio.h>
289#endif
290#include <sys/socket.h>
291#include <sys/types.h>
292#include <netinet/in.h>
293#include <net/if.h>
294#include <arpa/inet.h>
295#include <netdb.h>
296#include <net/if.h>
297#include <net/if_arp.h>
298#include <unistd.h>
299
300
301namespace Poco {
302
303
304void EnvironmentImpl::nodeIdImpl(NodeId& id)
305{
306 std::memset(&id, 0, sizeof(id));
307 char name[MAXHOSTNAMELEN];
308 if (gethostname(name, sizeof(name)))
309 return;
310
311 struct hostent* pHost = gethostbyname(name);
312 if (!pHost) return;
313
314 int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
315 if (s == -1) return;
316
317 struct arpreq ar;
318 std::memset(&ar, 0, sizeof(ar));
319 struct sockaddr_in* pAddr = reinterpret_cast<struct sockaddr_in*>(&ar.arp_pa);
320 pAddr->sin_family = AF_INET;
321 std::memcpy(&pAddr->sin_addr, *pHost->h_addr_list, sizeof(struct in_addr));
322 int rc = ioctl(s, SIOCGARP, &ar);
323 close(s);
324 if (rc < 0) return;
325 std::memcpy(&id, ar.arp_ha.sa_data, sizeof(id));
326}
327
328
329} // namespace Poco
330
331
332#endif
333