1 /* distcache, Distributed Session Caching technology
2  * Copyright (C) 2000-2003  Geoff Thorpe, and Cryptographic Appliances, Inc.
3  * Copyright (C) 2004       The Distcache.org project
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; using version 2.1 of the License. The copyright holders
8  * may elect to allow the application of later versions of the License to this
9  * software, please contact the author (geoff@distcache.org) if you wish us to
10  * review any later version released by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #define SYS_LOCAL
23 
24 #include <libsys/pre.h>
25 #define IN_SYS_C
26 #include <libsys/post.h>
27 
28 #ifdef WIN32
29 
30 /************************************************************************/
31 /* WIN32 gets no process or signal code, but gets a network initialiser */
32 /************************************************************************/
33 
sockets_init(void)34 int sockets_init(void)
35 {
36 	WORD wVersionRequested;
37 	WSADATA wsaData;
38 
39 	wVersionRequested = MAKEWORD(2, 2);
40 	if(WSAStartup(wVersionRequested, &wsaData) != 0)
41 		return 0;
42 	return 1;
43 }
44 
45 #else
46 
47 /**************************************/
48 /* Process model related utility code */
49 /**************************************/
50 
51 /* Redeclared as a macro */
52 #if 0
53 pid_t SYS_getpid(void)
54 {
55 	return getpid();
56 }
57 #endif
58 
59 /*
60  * SYS_daemon() is a utility function to make the current process a "daemon"
61  * such that it detaches from the current termisys and holds the attributes
62  * normally associated with daemon processes.
63  *
64  * The "nochdir" parameter, if zero, changes the current working directory to
65  * "/", thereby preventing the daemon process keeping a hold on directories
66  * (Where this might be useful is, for example, NFS file systems preventing
67  * those machines from unmounting the exported file system.)
68  *
69  * Returns non-zero for success, zero otherwise.
70  */
SYS_daemon(int nochdir)71 int SYS_daemon(int nochdir)
72 {
73 #ifdef HAVE_DAEMON
74        if(daemon(nochdir, 0) == -1)
75 	       return 0;
76        return 1;
77 #else
78        /* The system has no daemon() function, so we have to duplicate
79 	* the functionality.  */
80 	pid_t pid;
81 
82 	if ( (pid = fork()) < 0)
83 		return 0;
84 	else if (pid != 0)
85 		exit(0);
86 
87 	/* At this point we're the child process, and our parent has been
88 	 * killed off */
89 
90 	setsid();
91 
92 	if (!nochdir)
93 		chdir("/");
94 
95 	umask(0);
96 
97 	close(STDIN_FILENO);
98 	close(STDOUT_FILENO);
99 	close(STDERR_FILENO);
100 
101 	return 1;
102 #endif
103 }
104 
SYS_setuid(const char * username)105 int SYS_setuid(const char *username)
106 {
107 #if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID)
108 	struct passwd *p = getpwnam(username);
109 	if(!p || (setuid(p->pw_uid) != 0))
110 		return 0;
111 	return 1;
112 #else
113 	return 0;
114 #endif
115 }
116 
117 /*******************************/
118 /* SIGNAL related utility code */
119 /*******************************/
120 
121 /* If SYS_sigusr_interrupt() provides a pointer, we store it here. */
122 static int *gb_ptr = NULL;
123 
empty_handler(int foo)124 static void empty_handler(int foo)
125 {
126 	if(gb_ptr) *gb_ptr = 1;
127 }
128 
int_sig_set(int signum,void (* handler)(int))129 static int int_sig_set(int signum, void (*handler)(int))
130 {
131 	struct sigaction sig;
132 
133 	sig.sa_handler = handler;
134 	sigemptyset(&sig.sa_mask);
135 	sig.sa_flags = 0;
136 	if(sigaction(signum, &sig, NULL) != 0)
137 		return 0;
138 	return 1;
139 }
140 
SYS_sigpipe_ignore(void)141 int SYS_sigpipe_ignore(void)
142 {
143 	if(!int_sig_set(SIGPIPE, SIG_IGN)) {
144 #if SYS_DEBUG_LEVEL > 0
145 		SYS_fprintf(SYS_stderr, "Error, couldn't ignore SIGPIPE\n\n");
146 #endif
147 		return 0;
148 	}
149 	return 1;
150 }
151 
SYS_sigusr_interrupt(int * ptr)152 int SYS_sigusr_interrupt(int *ptr)
153 {
154 	gb_ptr = ptr;
155 	if(!int_sig_set(SIGUSR1, empty_handler) ||
156 			!int_sig_set(SIGUSR2, empty_handler)) {
157 #if SYS_DEBUG_LEVEL > 0
158 		SYS_fprintf(SYS_stderr, "Error, couldn't ignore SIGUSR1 or SIGUSR2\n\n");
159 #endif
160 		return 0;
161 	}
162 	return 1;
163 }
164 
165 #endif /* !defined(WIN32) */
166 
167 /*******************************/
168 /* Time manipulation functions */
169 /*******************************/
170 
171 /* Redeclared as macros */
172 #if 0
173 int SYS_timecmp(const struct timeval *a, const struct timeval *b)
174 {
175 	if(a->tv_sec < b->tv_sec)
176 		return -1;
177 	else if(a->tv_sec > b->tv_sec)
178 		return 1;
179 	if(a->tv_usec < b->tv_usec)
180 		return -1;
181 	else if(a->tv_usec > b->tv_usec)
182 		return 1;
183 	return 0;
184 }
185 
186 void SYS_gettime(struct timeval *tv)
187 {
188 #ifdef WIN32
189 	/* GetSystemTimeAsFileTime seems to be the only capable win32 API call
190 	 * that (a) has a high-enough resolution (100 nanoseconds in theory),
191 	 * (b) no sudden 1-hour skews thanks to local time handling, and (c) no
192 	 * wraparound (GetTickCount() would be better but it wraps after 49
193 	 * days). */
194 	FILETIME decimillisecs;
195 	unsigned __int64 crud;
196 	GetSystemTimeAsFileTime(&decimillisecs);
197 	/* FILETIME has 2 32-bit DWORD components, representing the number of
198 	 * 100-nanosecond intervals since Jan 1, 1601. Convert them to
199 	 * microseconds first. Then subsitute enough years to ensure 32-bits of
200 	 * resolution is enough for the seconds components. (We substract
201 	 * slightly less than 400 years, so we're counting from around mid
202 	 * 2000). */
203 	crud = ((unsigned __int64)decimillisecs.dwHighDateTime << 32) +
204 		(unsigned __int64)decimillisecs.dwLowDateTime;
205 	crud /= 10;
206 	/* 12,614,400,000 seconds is slightly less than 400 years */
207 	crud -= (unsigned __int64)12614400000 * (unsigned __int64)1000000;
208 	tv->tv_sec = (long)(crud / 1000000);
209 	tv->tv_usec = (long)(crud % 1000000);
210 #else
211 	if(gettimeofday(tv, NULL) != 0)
212 		/* This should never happen unless tv pointed outside the
213 		 * accessible address space, so abort() as an alternative
214 		 * to segfaulting :-) */
215 		abort();
216 #endif
217 }
218 
219 void SYS_timecpy(struct timeval *dest, const struct timeval *src)
220 {
221 	SYS_memcpy(struct timeval, dest, src);
222 }
223 
224 void SYS_timeadd(struct timeval *res, const struct timeval *I,
225 		unsigned long msecs)
226 {
227 	unsigned long carry = I->tv_usec + (msecs * 1000);
228 	res->tv_usec = carry % 1000000;
229 	carry /= 1000000;
230 	res->tv_sec = I->tv_sec + carry;
231 }
232 
233 #endif
234 
SYS_expirycheck(const struct timeval * timeitem,unsigned long msec_expiry,const struct timeval * timenow)235 int SYS_expirycheck(const struct timeval *timeitem, unsigned long msec_expiry,
236 		const struct timeval *timenow)
237 {
238 	struct timeval threshold;
239 	unsigned long usec_expiry = msec_expiry * 1000;
240 	SYS_memcpy(struct timeval, &threshold, timeitem);
241 	threshold.tv_sec = threshold.tv_sec + (usec_expiry / 1000000L);
242 	threshold.tv_usec += (usec_expiry % 1000000);
243 	if(threshold.tv_usec > 1000000) {
244 		threshold.tv_usec -= 1000000;
245 		threshold.tv_sec++;
246 	}
247 	if(timercmp(timenow, &threshold, <))
248 		/* Not expired yet */
249 		return 0;
250 	/* Expired */
251 	return 1;
252 }
253 
SYS_timesub(struct timeval * res,const struct timeval * I,unsigned long msecs)254 void SYS_timesub(struct timeval *res, const struct timeval *I,
255 		unsigned long msecs)
256 {
257 	unsigned long sub_low = (msecs % 1000) * 1000;
258 	unsigned long sub_high = msecs / 1000;
259 	if((unsigned long)I->tv_usec < sub_low) {
260 		sub_high++;
261 		res->tv_usec = (I->tv_usec + 1000000) - sub_low;
262 	} else
263 		res->tv_usec = I->tv_usec - sub_low;
264 	res->tv_sec = I->tv_sec - sub_high;
265 }
266 
SYS_msecs_between(const struct timeval * a,const struct timeval * b)267 unsigned long SYS_msecs_between(const struct timeval *a, const struct timeval *b)
268 {
269 	unsigned long toret;
270 	const struct timeval *tmp;
271 
272 	if(SYS_timecmp(a, b) > 0) {
273 		tmp = a;
274 		a = b;
275 		b = tmp;
276 	}
277 	/* Now we now that a <= b */
278 	toret = (unsigned long)1000000 * (b->tv_sec - a->tv_sec);
279 	if(b->tv_usec > a->tv_usec)
280 		toret += b->tv_usec - a->tv_usec;
281 	else
282 		toret -= a->tv_usec - b->tv_usec;
283 	return (toret / 1000);
284 }
285 
286