]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/unix_utility.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "pdnsexception.hh"
35 #include <sys/types.h>
36 #include <sys/select.h>
38 #ifdef NEED_INET_NTOP_PROTO
40 const char *inet_ntop(int af
, const void *src
, char *dst
, size_t cnt
);
45 #include "namespaces.hh"
48 // Connects to socket with timeout
49 int Utility::timed_connect( Utility::sock_t sock
,
51 Utility::socklen_t sockaddr_size
,
56 struct timeval timeout
;
59 timeout
.tv_sec
= timeout_sec
;
60 timeout
.tv_usec
= timeout_usec
;
67 if ((ret
= connect (sock
, addr
, sockaddr_size
)) < 0) {
68 if (errno
!= EINPROGRESS
)
72 ret
= select(sock
+ 1, NULL
, &set
, NULL
, &timeout
);
80 void Utility::setBindAny(int af
, sock_t sock
)
84 (void) one
; // avoids 'unused var' warning on systems that have none of the defines checked below
86 if (setsockopt(sock
, IPPROTO_IP
, IP_FREEBIND
, &one
, sizeof(one
)) < 0)
87 theL()<<Logger::Warning
<<"Warning: IP_FREEBIND setsockopt failed: "<<strerror(errno
)<<endl
;
92 if (setsockopt(sock
, IPPROTO_IP
, IP_BINDANY
, &one
, sizeof(one
)) < 0)
93 theL()<<Logger::Warning
<<"Warning: IP_BINDANY setsockopt failed: "<<strerror(errno
)<<endl
;
97 if (setsockopt(sock
, IPPROTO_IPV6
, IPV6_BINDANY
, &one
, sizeof(one
)) < 0)
98 theL()<<Logger::Warning
<<"Warning: IPV6_BINDANY setsockopt failed: "<<strerror(errno
)<<endl
;
101 if (setsockopt(sock
, SOL_SOCKET
, SO_BINDANY
, &one
, sizeof(one
)) < 0)
102 theL()<<Logger::Warning
<<"Warning: SO_BINDANY setsockopt failed: "<<strerror(errno
)<<endl
;
106 const char *Utility::inet_ntop(int af
, const char *src
, char *dst
, size_t size
)
108 return ::inet_ntop(af
,src
,dst
,size
);
111 unsigned int Utility::sleep(unsigned int sec
)
116 void Utility::usleep(unsigned long usec
)
119 ts
.tv_sec
= usec
/ 1000000;
120 ts
.tv_nsec
= (usec
% 1000000) * 1000;
121 // POSIX.1 recommends using nanosleep instead of usleep
122 ::nanosleep(&ts
, NULL
);
126 // Drops the program's group privileges.
127 void Utility::dropGroupPrivs( int uid
, int gid
)
131 theL()<<Logger::Critical
<<"Unable to set effective group id to "<<gid
<<": "<<stringerror()<<endl
;
135 theL()<<Logger::Info
<<"Set effective group id to "<<gid
<<endl
;
137 struct passwd
*pw
=getpwuid(uid
);
139 theL()<<Logger::Warning
<<"Unable to determine user name for uid "<<uid
<<endl
;
140 if (setgroups(0, NULL
)<0) {
141 theL()<<Logger::Critical
<<"Unable to drop supplementary gids: "<<stringerror()<<endl
;
145 if (initgroups(pw
->pw_name
, gid
)<0) {
146 theL()<<Logger::Critical
<<"Unable to set supplementary groups: "<<stringerror()<<endl
;
154 // Drops the program's user privileges.
155 void Utility::dropUserPrivs( int uid
)
159 theL()<<Logger::Critical
<<"Unable to set effective user id to "<<uid
<<": "<<stringerror()<<endl
;
163 theL()<<Logger::Info
<<"Set effective user id to "<<uid
<<endl
;
168 // Returns the current process id.
169 Utility::pid_t
Utility::getpid( void )
175 // Returns the current time.
176 int Utility::gettimeofday( struct timeval
*tv
, void *tz
)
178 return ::gettimeofday(tv
,0);
183 // Retrieves a gid using a groupname.
184 int Utility::makeGidNumeric(const string
&group
)
187 if(!(newgid
=atoi(group
.c_str()))) {
189 struct group
*gr
=getgrnam(group
.c_str());
191 theL()<<Logger::Critical
<<"Unable to look up gid of group '"<<group
<<"': "<< (errno
? strerror(errno
) : "not found") <<endl
;
200 // Retrieves an uid using a username.
201 int Utility::makeUidNumeric(const string
&username
)
204 if(!(newuid
=atoi(username
.c_str()))) {
205 struct passwd
*pw
=getpwnam(username
.c_str());
207 theL()<<Logger::Critical
<<"Unable to look up uid of user '"<<username
<<"': "<< (errno
? strerror(errno
) : "not found") <<endl
;
216 // Returns a random number.
217 long int Utility::random( void )
222 // Sets the random seed.
223 void Utility::srandom( unsigned int seed
)
230 int Utility::writev(int socket
, const iovec
*vector
, size_t count
)
232 return ::writev(socket
,vector
,count
);
235 /* this is cut and pasted from dietlibc, gratefully copied! */
236 static int isleap(int year
) {
237 /* every fourth year is a leap year except for century years that are
238 * not divisible by 400. */
239 return (!(year
%4) && ((year
%100) || !(year
%400)));
242 time_t Utility::timegm(struct tm
*const t
)
244 const static short spm
[13] = /* days per month -- nonleap! */
252 (31+28+31+30+31+30+31),
253 (31+28+31+30+31+30+31+31),
254 (31+28+31+30+31+30+31+31+30),
255 (31+28+31+30+31+30+31+31+30+31),
256 (31+28+31+30+31+30+31+31+30+31+30),
257 (31+28+31+30+31+30+31+31+30+31+30+31),
262 time_t years
= t
->tm_year
- 70;
264 if (t
->tm_sec
>60) { t
->tm_min
+= t
->tm_sec
/60; t
->tm_sec
%=60; }
265 if (t
->tm_min
>60) { t
->tm_hour
+= t
->tm_min
/60; t
->tm_min
%=60; }
266 if (t
->tm_hour
>60) { t
->tm_mday
+= t
->tm_hour
/60; t
->tm_hour
%=60; }
267 if (t
->tm_mon
>11) { t
->tm_year
+= t
->tm_mon
/12; t
->tm_mon
%=12; }
269 while (t
->tm_mday
>spm
[1+t
->tm_mon
]) {
270 if (t
->tm_mon
==1 && isleap(t
->tm_year
+1900)) {
271 if (t
->tm_mon
==31+29) break;
274 t
->tm_mday
-=spm
[t
->tm_mon
];
276 if (t
->tm_mon
>11) { t
->tm_mon
=0; ++t
->tm_year
; }
281 /* Days since 1970 is 365 * number of years + number of leap years since 1970 */
282 day
= years
* 365 + (years
+ 1) / 4;
284 /* After 2100 we have to subtract 3 leap years for every 400 years
285 This is not intuitive. Most mktime implementations do not support
286 dates after 2059, anyway, so we might leave this out for its
288 if ((years
-= 131) >= 0) {
290 day
-= (years
>> 2) * 3 + 1;
291 if ((years
&= 3) == 3) years
--;
295 day
+= t
->tm_yday
= spm
[t
->tm_mon
] + t
->tm_mday
-1 + ( isleap (t
->tm_year
+1900) & (t
->tm_mon
> 1) );
297 /* day is now the number of days since 'Jan 1 1970' */
299 t
->tm_wday
= (day
+ 4) % i
; /* Sunday=0, Monday=1, ..., Saturday=6 */
304 return ((day
+ t
->tm_hour
) * i
+ t
->tm_min
) * i
+ t
->tm_sec
;