r3443: the next stage in the include files re-organisation.
[samba.git] / source4 / lib / system.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 1998-2002
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "system/network.h"
24
25 /*
26    The idea is that this file will eventually have wrappers around all
27    important system calls in samba. The aims are:
28
29    - to enable easier porting by putting OS dependent stuff in here
30
31    - to allow for hooks into other "pseudo-filesystems"
32
33    - to allow easier integration of things like the japanese extensions
34
35    - to support the philosophy of Samba to expose the features of
36      the OS within the SMB model. In general whatever file/printer/variable
37      expansions/etc make sense to the OS should be acceptable to Samba.
38 */
39
40
41
42 /*******************************************************************
43  A wrapper for usleep in case we don't have one.
44 ********************************************************************/
45
46 int sys_usleep(long usecs)
47 {
48 #ifndef HAVE_USLEEP
49         struct timeval tval;
50 #endif
51
52         /*
53          * We need this braindamage as the glibc usleep
54          * is not SPEC1170 complient... grumble... JRA.
55          */
56
57         if(usecs < 0 || usecs > 1000000) {
58                 errno = EINVAL;
59                 return -1;
60         }
61
62 #if HAVE_USLEEP
63         usleep(usecs);
64         return 0;
65 #else /* HAVE_USLEEP */
66         /*
67          * Fake it with select...
68          */
69         tval.tv_sec = 0;
70         tval.tv_usec = usecs/1000;
71         select(0,NULL,NULL,NULL,&tval);
72         return 0;
73 #endif /* HAVE_USLEEP */
74 }
75
76 /*******************************************************************
77 A read wrapper that will deal with EINTR.
78 ********************************************************************/
79
80 ssize_t sys_read(int fd, void *buf, size_t count)
81 {
82         ssize_t ret;
83
84         do {
85                 ret = read(fd, buf, count);
86         } while (ret == -1 && errno == EINTR);
87         return ret;
88 }
89
90 /*******************************************************************
91 A write wrapper that will deal with EINTR.
92 ********************************************************************/
93
94 ssize_t sys_write(int fd, const void *buf, size_t count)
95 {
96         ssize_t ret;
97
98         do {
99                 ret = write(fd, buf, count);
100         } while (ret == -1 && errno == EINTR);
101         return ret;
102 }
103
104 /*******************************************************************
105 A send wrapper that will deal with EINTR.
106 ********************************************************************/
107
108 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
109 {
110         ssize_t ret;
111
112         do {
113                 ret = send(s, msg, len, flags);
114         } while (ret == -1 && errno == EINTR);
115         return ret;
116 }
117
118 /*******************************************************************
119 A sendto wrapper that will deal with EINTR.
120 ********************************************************************/
121
122 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
123 {
124         ssize_t ret;
125
126         do {
127                 ret = sendto(s, msg, len, flags, to, tolen);
128         } while (ret == -1 && errno == EINTR);
129         return ret;
130 }
131
132
133 /*******************************************************************
134  System wrapper for getwd
135 ********************************************************************/
136
137 char *sys_getwd(char *s)
138 {
139         char *wd;
140 #ifdef HAVE_GETCWD
141         wd = (char *)getcwd(s, sizeof (pstring));
142 #else
143         wd = (char *)getwd(s);
144 #endif
145         return wd;
146 }
147
148 /*******************************************************************
149 system wrapper for link
150 ********************************************************************/
151
152 int sys_link(const char *oldpath, const char *newpath)
153 {
154 #ifndef HAVE_LINK
155         errno = ENOSYS;
156         return -1;
157 #else
158         return link(oldpath, newpath);
159 #endif
160 }
161
162 /*******************************************************************
163 os/2 also doesn't have chroot
164 ********************************************************************/
165 int sys_chroot(const char *dname)
166 {
167 #ifndef HAVE_CHROOT
168         static int done;
169         if (!done) {
170                 DEBUG(1,("WARNING: no chroot!\n"));
171                 done=1;
172         }
173         errno = ENOSYS;
174         return -1;
175 #else
176         return(chroot(dname));
177 #endif
178 }
179
180 /**************************************************************************
181 A wrapper for gethostbyname() that tries avoids looking up hostnames 
182 in the root domain, which can cause dial-on-demand links to come up for no
183 apparent reason.
184 ****************************************************************************/
185
186 struct hostent *sys_gethostbyname(const char *name)
187 {
188 #ifdef REDUCE_ROOT_DNS_LOOKUPS
189         char query[256], hostname[256];
190         char *domain;
191
192         /* Does this name have any dots in it? If so, make no change */
193
194         if (strchr_m(name, '.'))
195                 return(gethostbyname(name));
196
197         /* Get my hostname, which should have domain name 
198                 attached. If not, just do the gethostname on the
199                 original string. 
200         */
201
202         gethostname(hostname, sizeof(hostname) - 1);
203         hostname[sizeof(hostname) - 1] = 0;
204         if ((domain = strchr_m(hostname, '.')) == NULL)
205                 return(gethostbyname(name));
206
207         /* Attach domain name to query and do modified query.
208                 If names too large, just do gethostname on the
209                 original string.
210         */
211
212         if((strlen(name) + strlen(domain)) >= sizeof(query))
213                 return(gethostbyname(name));
214
215         slprintf(query, sizeof(query)-1, "%s%s", name, domain);
216         return(gethostbyname(query));
217 #else /* REDUCE_ROOT_DNS_LOOKUPS */
218         return(gethostbyname(name));
219 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
220 }
221
222
223 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
224 /**************************************************************************
225  Try and abstract process capabilities (for systems that have them).
226 ****************************************************************************/
227 static BOOL set_process_capability( uint32_t cap_flag, BOOL enable )
228 {
229         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
230                 cap_t cap = cap_get_proc();
231
232                 if (cap == NULL) {
233                         DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
234                                 strerror(errno)));
235                         return False;
236                 }
237
238                 if(enable)
239                         cap->cap_effective |= CAP_NETWORK_MGT;
240                 else
241                         cap->cap_effective &= ~CAP_NETWORK_MGT;
242
243                 if (cap_set_proc(cap) == -1) {
244                         DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
245                                 strerror(errno)));
246                         cap_free(cap);
247                         return False;
248                 }
249
250                 cap_free(cap);
251
252                 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
253         }
254         return True;
255 }
256
257 /**************************************************************************
258  Try and abstract inherited process capabilities (for systems that have them).
259 ****************************************************************************/
260
261 static BOOL set_inherited_process_capability( uint32_t cap_flag, BOOL enable )
262 {
263         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
264                 cap_t cap = cap_get_proc();
265
266                 if (cap == NULL) {
267                         DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
268                                 strerror(errno)));
269                         return False;
270                 }
271
272                 if(enable)
273                         cap->cap_inheritable |= CAP_NETWORK_MGT;
274                 else
275                         cap->cap_inheritable &= ~CAP_NETWORK_MGT;
276
277                 if (cap_set_proc(cap) == -1) {
278                         DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
279                                 strerror(errno)));
280                         cap_free(cap);
281                         return False;
282                 }
283
284                 cap_free(cap);
285
286                 DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
287         }
288         return True;
289 }
290 #endif
291
292 /****************************************************************************
293  Gain the oplock capability from the kernel if possible.
294 ****************************************************************************/
295
296 void oplock_set_capability(BOOL this_process, BOOL inherit)
297 {
298 #if HAVE_KERNEL_OPLOCKS_IRIX
299         set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
300         set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
301 #endif
302 }
303
304 /**************************************************************************
305  Wrapper for random().
306 ****************************************************************************/
307
308 long sys_random(void)
309 {
310 #if defined(HAVE_RANDOM)
311         return (long)random();
312 #elif defined(HAVE_RAND)
313         return (long)rand();
314 #else
315         DEBUG(0,("Error - no random function available !\n"));
316         exit(1);
317 #endif
318 }
319
320 /**************************************************************************
321  Wrapper for srandom().
322 ****************************************************************************/
323
324 void sys_srandom(uint_t seed)
325 {
326 #if defined(HAVE_SRANDOM)
327         srandom(seed);
328 #elif defined(HAVE_SRAND)
329         srand(seed);
330 #else
331         DEBUG(0,("Error - no srandom function available !\n"));
332         exit(1);
333 #endif
334 }
335
336 /**************************************************************************
337  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
338 ****************************************************************************/
339
340 int groups_max(void)
341 {
342 #if defined(SYSCONF_SC_NGROUPS_MAX)
343         int ret = sysconf(_SC_NGROUPS_MAX);
344         return (ret == -1) ? NGROUPS_MAX : ret;
345 #else
346         return NGROUPS_MAX;
347 #endif
348 }
349
350 /**************************************************************************
351  Wrapper for getgroups. Deals with broken (int) case.
352 ****************************************************************************/
353
354 int sys_getgroups(int setlen, gid_t *gidset)
355 {
356 #if !defined(HAVE_BROKEN_GETGROUPS)
357         return getgroups(setlen, gidset);
358 #else
359
360         GID_T gid;
361         GID_T *group_list;
362         int i, ngroups;
363
364         if(setlen == 0) {
365                 return getgroups(setlen, &gid);
366         }
367
368         /*
369          * Broken case. We need to allocate a
370          * GID_T array of size setlen.
371          */
372
373         if(setlen < 0) {
374                 errno = EINVAL; 
375                 return -1;
376         } 
377
378         if (setlen == 0)
379                 setlen = groups_max();
380
381         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
382                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
383                 return -1;
384         }
385
386         if((ngroups = getgroups(setlen, group_list)) < 0) {
387                 int saved_errno = errno;
388                 SAFE_FREE(group_list);
389                 errno = saved_errno;
390                 return -1;
391         }
392
393         for(i = 0; i < ngroups; i++)
394                 gidset[i] = (gid_t)group_list[i];
395
396         SAFE_FREE(group_list);
397         return ngroups;
398 #endif /* HAVE_BROKEN_GETGROUPS */
399 }
400
401 #ifdef HAVE_SETGROUPS
402
403 /**************************************************************************
404  Wrapper for setgroups. Deals with broken (int) case. Automatically used
405  if we have broken getgroups.
406 ****************************************************************************/
407
408 int sys_setgroups(int setlen, gid_t *gidset)
409 {
410 #if !defined(HAVE_BROKEN_GETGROUPS)
411         return setgroups(setlen, gidset);
412 #else
413
414         GID_T *group_list;
415         int i ; 
416
417         if (setlen == 0)
418                 return 0 ;
419
420         if (setlen < 0 || setlen > groups_max()) {
421                 errno = EINVAL; 
422                 return -1;   
423         }
424
425         /*
426          * Broken case. We need to allocate a
427          * GID_T array of size setlen.
428          */
429
430         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
431                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
432                 return -1;    
433         }
434  
435         for(i = 0; i < setlen; i++) 
436                 group_list[i] = (GID_T) gidset[i]; 
437
438         if(setgroups(setlen, group_list) != 0) {
439                 int saved_errno = errno;
440                 SAFE_FREE(group_list);
441                 errno = saved_errno;
442                 return -1;
443         }
444  
445         SAFE_FREE(group_list);
446         return 0 ;
447 #endif /* HAVE_BROKEN_GETGROUPS */
448 }
449
450 #endif /* HAVE_SETGROUPS */
451
452 struct passwd *sys_getpwent(void)
453 {
454         return getpwent();
455 }
456
457 void sys_endpwent(void)
458 {
459         endpwent();
460 }
461
462 /**************************************************************************
463  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
464 ****************************************************************************/
465
466 struct passwd *sys_getpwnam(const char *name)
467 {
468         return getpwnam(name);
469 }
470
471 struct passwd *sys_getpwuid(uid_t uid)
472 {
473         return getpwuid(uid);
474 }
475
476 struct group *sys_getgrnam(const char *name)
477 {
478         return getgrnam(name);
479 }
480
481 struct group *sys_getgrgid(gid_t gid)
482 {
483         return getgrgid(gid);
484 }
485
486
487 /**************************************************************************
488  Wrappers for dlopen, dlsym, dlclose.
489 ****************************************************************************/
490
491 void *sys_dlopen(const char *name, int flags)
492 {
493 #if defined(HAVE_DLOPEN)
494         return dlopen(name, flags);
495 #else
496         return NULL;
497 #endif
498 }
499
500 void *sys_dlsym(void *handle, const char *symbol)
501 {
502 #if defined(HAVE_DLSYM)
503     return dlsym(handle, symbol);
504 #else
505     return NULL;
506 #endif
507 }
508
509 int sys_dlclose (void *handle)
510 {
511 #if defined(HAVE_DLCLOSE)
512         return dlclose(handle);
513 #else
514         return 0;
515 #endif
516 }
517
518 const char *sys_dlerror(void)
519 {
520 #if defined(HAVE_DLERROR)
521         return dlerror();
522 #else
523         return NULL;
524 #endif
525 }
526
527 int sys_dup2(int oldfd, int newfd) 
528 {
529 #if defined(HAVE_DUP2)
530         return dup2(oldfd, newfd);
531 #else
532         errno = ENOSYS;
533         return -1;
534 #endif
535 }
536
537
538 const char *sys_inet_ntoa(struct ipv4_addr in)
539 {
540         struct in_addr in2;
541         in2.s_addr = in.s_addr;
542         return inet_ntoa(in2);
543 }
544
545 uint32_t sys_inet_addr(const char *s)
546 {
547         return inet_addr(s);
548 }
549
550 struct ipv4_addr sys_inet_makeaddr(int net, int host)
551 {
552         struct in_addr in;
553         struct ipv4_addr in2;
554         in = inet_makeaddr(net, host);
555         in2.s_addr = in.s_addr;
556         return in2;
557 }