8c9627eb26bb641a75cb2af0222cb02727791ce1
[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
24 /*
25    The idea is that this file will eventually have wrappers around all
26    important system calls in samba. The aims are:
27
28    - to enable easier porting by putting OS dependent stuff in here
29
30    - to allow for hooks into other "pseudo-filesystems"
31
32    - to allow easier integration of things like the japanese extensions
33
34    - to support the philosophy of Samba to expose the features of
35      the OS within the SMB model. In general whatever file/printer/variable
36      expansions/etc make sense to the OS should be acceptable to Samba.
37 */
38
39
40
41 /*******************************************************************
42  A wrapper for usleep in case we don't have one.
43 ********************************************************************/
44
45 int sys_usleep(long usecs)
46 {
47 #ifndef HAVE_USLEEP
48         struct timeval tval;
49 #endif
50
51         /*
52          * We need this braindamage as the glibc usleep
53          * is not SPEC1170 complient... grumble... JRA.
54          */
55
56         if(usecs < 0 || usecs > 1000000) {
57                 errno = EINVAL;
58                 return -1;
59         }
60
61 #if HAVE_USLEEP
62         usleep(usecs);
63         return 0;
64 #else /* HAVE_USLEEP */
65         /*
66          * Fake it with select...
67          */
68         tval.tv_sec = 0;
69         tval.tv_usec = usecs/1000;
70         select(0,NULL,NULL,NULL,&tval);
71         return 0;
72 #endif /* HAVE_USLEEP */
73 }
74
75 /*******************************************************************
76 A read wrapper that will deal with EINTR.
77 ********************************************************************/
78
79 ssize_t sys_read(int fd, void *buf, size_t count)
80 {
81         ssize_t ret;
82
83         do {
84                 ret = read(fd, buf, count);
85         } while (ret == -1 && errno == EINTR);
86         return ret;
87 }
88
89 /*******************************************************************
90 A write wrapper that will deal with EINTR.
91 ********************************************************************/
92
93 ssize_t sys_write(int fd, const void *buf, size_t count)
94 {
95         ssize_t ret;
96
97         do {
98                 ret = write(fd, buf, count);
99         } while (ret == -1 && errno == EINTR);
100         return ret;
101 }
102
103 /*******************************************************************
104 A send wrapper that will deal with EINTR.
105 ********************************************************************/
106
107 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
108 {
109         ssize_t ret;
110
111         do {
112                 ret = send(s, msg, len, flags);
113         } while (ret == -1 && errno == EINTR);
114         return ret;
115 }
116
117 /*******************************************************************
118 A sendto wrapper that will deal with EINTR.
119 ********************************************************************/
120
121 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
122 {
123         ssize_t ret;
124
125         do {
126                 ret = sendto(s, msg, len, flags, to, tolen);
127         } while (ret == -1 && errno == EINTR);
128         return ret;
129 }
130
131 /*******************************************************************
132 A recvfrom wrapper that will deal with EINTR.
133 ********************************************************************/
134
135 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
136 {
137         ssize_t ret;
138
139         do {
140                 ret = recvfrom(s, buf, len, flags, from, fromlen);
141         } while (ret == -1 && errno == EINTR);
142         return ret;
143 }
144
145 /*******************************************************************
146 A fcntl wrapper that will deal with EINTR.
147 ********************************************************************/
148
149 int sys_fcntl_ptr(int fd, int cmd, void *arg)
150 {
151         int ret;
152
153         do {
154                 ret = fcntl(fd, cmd, arg);
155         } while (ret == -1 && errno == EINTR);
156         return ret;
157 }
158
159 /*******************************************************************
160 A fcntl wrapper that will deal with EINTR.
161 ********************************************************************/
162
163 int sys_fcntl_long(int fd, int cmd, long arg)
164 {
165         int ret;
166
167         do {
168                 ret = fcntl(fd, cmd, arg);
169         } while (ret == -1 && errno == EINTR);
170         return ret;
171 }
172
173 /*******************************************************************
174 A stat() wrapper that will deal with 64 bit filesizes.
175 ********************************************************************/
176
177 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
178 {
179         int ret;
180 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
181         ret = stat64(fname, sbuf);
182 #else
183         ret = stat(fname, sbuf);
184 #endif
185         /* we always want directories to appear zero size */
186         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
187         return ret;
188 }
189
190 /*******************************************************************
191  An fstat() wrapper that will deal with 64 bit filesizes.
192 ********************************************************************/
193
194 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
195 {
196         int ret;
197 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
198         ret = fstat64(fd, sbuf);
199 #else
200         ret = fstat(fd, sbuf);
201 #endif
202         /* we always want directories to appear zero size */
203         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
204         return ret;
205 }
206
207 /*******************************************************************
208  An lstat() wrapper that will deal with 64 bit filesizes.
209 ********************************************************************/
210
211 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
212 {
213         int ret;
214 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
215         ret = lstat64(fname, sbuf);
216 #else
217         ret = lstat(fname, sbuf);
218 #endif
219         /* we always want directories to appear zero size */
220         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
221         return ret;
222 }
223
224 /*******************************************************************
225  An ftruncate() wrapper that will deal with 64 bit filesizes.
226 ********************************************************************/
227
228 int sys_ftruncate(int fd, SMB_OFF_T offset)
229 {
230 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
231         return ftruncate64(fd, offset);
232 #else
233         return ftruncate(fd, offset);
234 #endif
235 }
236
237 /*******************************************************************
238  An lseek() wrapper that will deal with 64 bit filesizes.
239 ********************************************************************/
240
241 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
242 {
243 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
244         return lseek64(fd, offset, whence);
245 #else
246         return lseek(fd, offset, whence);
247 #endif
248 }
249
250 /*******************************************************************
251  A creat() wrapper that will deal with 64 bit filesizes.
252 ********************************************************************/
253
254 int sys_creat(const char *path, mode_t mode)
255 {
256 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
257         return creat64(path, mode);
258 #else
259         /*
260          * If creat64 isn't defined then ensure we call a potential open64.
261          * JRA.
262          */
263         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
264 #endif
265 }
266
267 /*******************************************************************
268  An open() wrapper that will deal with 64 bit filesizes.
269 ********************************************************************/
270
271 int sys_open(const char *path, int oflag, mode_t mode)
272 {
273 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
274         return open64(path, oflag, mode);
275 #else
276         return open(path, oflag, mode);
277 #endif
278 }
279
280 /*******************************************************************
281  An fopen() wrapper that will deal with 64 bit filesizes.
282 ********************************************************************/
283
284 FILE *sys_fopen(const char *path, const char *type)
285 {
286 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
287         return fopen64(path, type);
288 #else
289         return fopen(path, type);
290 #endif
291 }
292
293 /*******************************************************************
294  A readdir wrapper that will deal with 64 bit filesizes.
295 ********************************************************************/
296
297 struct smb_dirent *sys_readdir(DIR *dirp)
298 {
299 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
300         return readdir64(dirp);
301 #else
302         return readdir(dirp);
303 #endif
304 }
305
306 /*******************************************************************
307 The wait() calls vary between systems
308 ********************************************************************/
309
310 int sys_waitpid(pid_t pid,int *status,int options)
311 {
312 #ifdef HAVE_WAITPID
313         return waitpid(pid,status,options);
314 #else /* HAVE_WAITPID */
315         return wait4(pid, status, options, NULL);
316 #endif /* HAVE_WAITPID */
317 }
318
319 /*******************************************************************
320  System wrapper for getwd
321 ********************************************************************/
322
323 char *sys_getwd(char *s)
324 {
325         char *wd;
326 #ifdef HAVE_GETCWD
327         wd = (char *)getcwd(s, sizeof (pstring));
328 #else
329         wd = (char *)getwd(s);
330 #endif
331         return wd;
332 }
333
334 /*******************************************************************
335 system wrapper for link
336 ********************************************************************/
337
338 int sys_link(const char *oldpath, const char *newpath)
339 {
340 #ifndef HAVE_LINK
341         errno = ENOSYS;
342         return -1;
343 #else
344         return link(oldpath, newpath);
345 #endif
346 }
347
348 /*******************************************************************
349 os/2 also doesn't have chroot
350 ********************************************************************/
351 int sys_chroot(const char *dname)
352 {
353 #ifndef HAVE_CHROOT
354         static int done;
355         if (!done) {
356                 DEBUG(1,("WARNING: no chroot!\n"));
357                 done=1;
358         }
359         errno = ENOSYS;
360         return -1;
361 #else
362         return(chroot(dname));
363 #endif
364 }
365
366 /**************************************************************************
367 A wrapper for gethostbyname() that tries avoids looking up hostnames 
368 in the root domain, which can cause dial-on-demand links to come up for no
369 apparent reason.
370 ****************************************************************************/
371
372 struct hostent *sys_gethostbyname(const char *name)
373 {
374 #ifdef REDUCE_ROOT_DNS_LOOKUPS
375         char query[256], hostname[256];
376         char *domain;
377
378         /* Does this name have any dots in it? If so, make no change */
379
380         if (strchr_m(name, '.'))
381                 return(gethostbyname(name));
382
383         /* Get my hostname, which should have domain name 
384                 attached. If not, just do the gethostname on the
385                 original string. 
386         */
387
388         gethostname(hostname, sizeof(hostname) - 1);
389         hostname[sizeof(hostname) - 1] = 0;
390         if ((domain = strchr_m(hostname, '.')) == NULL)
391                 return(gethostbyname(name));
392
393         /* Attach domain name to query and do modified query.
394                 If names too large, just do gethostname on the
395                 original string.
396         */
397
398         if((strlen(name) + strlen(domain)) >= sizeof(query))
399                 return(gethostbyname(name));
400
401         slprintf(query, sizeof(query)-1, "%s%s", name, domain);
402         return(gethostbyname(query));
403 #else /* REDUCE_ROOT_DNS_LOOKUPS */
404         return(gethostbyname(name));
405 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
406 }
407
408
409 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
410 /**************************************************************************
411  Try and abstract process capabilities (for systems that have them).
412 ****************************************************************************/
413 static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
414 {
415         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
416                 cap_t cap = cap_get_proc();
417
418                 if (cap == NULL) {
419                         DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
420                                 strerror(errno)));
421                         return False;
422                 }
423
424                 if(enable)
425                         cap->cap_effective |= CAP_NETWORK_MGT;
426                 else
427                         cap->cap_effective &= ~CAP_NETWORK_MGT;
428
429                 if (cap_set_proc(cap) == -1) {
430                         DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
431                                 strerror(errno)));
432                         cap_free(cap);
433                         return False;
434                 }
435
436                 cap_free(cap);
437
438                 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
439         }
440         return True;
441 }
442
443 /**************************************************************************
444  Try and abstract inherited process capabilities (for systems that have them).
445 ****************************************************************************/
446
447 static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
448 {
449         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
450                 cap_t cap = cap_get_proc();
451
452                 if (cap == NULL) {
453                         DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
454                                 strerror(errno)));
455                         return False;
456                 }
457
458                 if(enable)
459                         cap->cap_inheritable |= CAP_NETWORK_MGT;
460                 else
461                         cap->cap_inheritable &= ~CAP_NETWORK_MGT;
462
463                 if (cap_set_proc(cap) == -1) {
464                         DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
465                                 strerror(errno)));
466                         cap_free(cap);
467                         return False;
468                 }
469
470                 cap_free(cap);
471
472                 DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
473         }
474         return True;
475 }
476 #endif
477
478 /****************************************************************************
479  Gain the oplock capability from the kernel if possible.
480 ****************************************************************************/
481
482 void oplock_set_capability(BOOL this_process, BOOL inherit)
483 {
484 #if HAVE_KERNEL_OPLOCKS_IRIX
485         set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
486         set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
487 #endif
488 }
489
490 /**************************************************************************
491  Wrapper for random().
492 ****************************************************************************/
493
494 long sys_random(void)
495 {
496 #if defined(HAVE_RANDOM)
497         return (long)random();
498 #elif defined(HAVE_RAND)
499         return (long)rand();
500 #else
501         DEBUG(0,("Error - no random function available !\n"));
502         exit(1);
503 #endif
504 }
505
506 /**************************************************************************
507  Wrapper for srandom().
508 ****************************************************************************/
509
510 void sys_srandom(unsigned int seed)
511 {
512 #if defined(HAVE_SRANDOM)
513         srandom(seed);
514 #elif defined(HAVE_SRAND)
515         srand(seed);
516 #else
517         DEBUG(0,("Error - no srandom function available !\n"));
518         exit(1);
519 #endif
520 }
521
522 /**************************************************************************
523  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
524 ****************************************************************************/
525
526 int groups_max(void)
527 {
528 #if defined(SYSCONF_SC_NGROUPS_MAX)
529         int ret = sysconf(_SC_NGROUPS_MAX);
530         return (ret == -1) ? NGROUPS_MAX : ret;
531 #else
532         return NGROUPS_MAX;
533 #endif
534 }
535
536 /**************************************************************************
537  Wrapper for getgroups. Deals with broken (int) case.
538 ****************************************************************************/
539
540 int sys_getgroups(int setlen, gid_t *gidset)
541 {
542 #if !defined(HAVE_BROKEN_GETGROUPS)
543         return getgroups(setlen, gidset);
544 #else
545
546         GID_T gid;
547         GID_T *group_list;
548         int i, ngroups;
549
550         if(setlen == 0) {
551                 return getgroups(setlen, &gid);
552         }
553
554         /*
555          * Broken case. We need to allocate a
556          * GID_T array of size setlen.
557          */
558
559         if(setlen < 0) {
560                 errno = EINVAL; 
561                 return -1;
562         } 
563
564         if (setlen == 0)
565                 setlen = groups_max();
566
567         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
568                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
569                 return -1;
570         }
571
572         if((ngroups = getgroups(setlen, group_list)) < 0) {
573                 int saved_errno = errno;
574                 SAFE_FREE(group_list);
575                 errno = saved_errno;
576                 return -1;
577         }
578
579         for(i = 0; i < ngroups; i++)
580                 gidset[i] = (gid_t)group_list[i];
581
582         SAFE_FREE(group_list);
583         return ngroups;
584 #endif /* HAVE_BROKEN_GETGROUPS */
585 }
586
587 #ifdef HAVE_SETGROUPS
588
589 /**************************************************************************
590  Wrapper for setgroups. Deals with broken (int) case. Automatically used
591  if we have broken getgroups.
592 ****************************************************************************/
593
594 int sys_setgroups(int setlen, gid_t *gidset)
595 {
596 #if !defined(HAVE_BROKEN_GETGROUPS)
597         return setgroups(setlen, gidset);
598 #else
599
600         GID_T *group_list;
601         int i ; 
602
603         if (setlen == 0)
604                 return 0 ;
605
606         if (setlen < 0 || setlen > groups_max()) {
607                 errno = EINVAL; 
608                 return -1;   
609         }
610
611         /*
612          * Broken case. We need to allocate a
613          * GID_T array of size setlen.
614          */
615
616         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
617                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
618                 return -1;    
619         }
620  
621         for(i = 0; i < setlen; i++) 
622                 group_list[i] = (GID_T) gidset[i]; 
623
624         if(setgroups(setlen, group_list) != 0) {
625                 int saved_errno = errno;
626                 SAFE_FREE(group_list);
627                 errno = saved_errno;
628                 return -1;
629         }
630  
631         SAFE_FREE(group_list);
632         return 0 ;
633 #endif /* HAVE_BROKEN_GETGROUPS */
634 }
635
636 #endif /* HAVE_SETGROUPS */
637
638 struct passwd *sys_getpwent(void)
639 {
640         return getpwent();
641 }
642
643 void sys_endpwent(void)
644 {
645         endpwent();
646 }
647
648 /**************************************************************************
649  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
650 ****************************************************************************/
651
652 struct passwd *sys_getpwnam(const char *name)
653 {
654         return getpwnam(name);
655 }
656
657 struct passwd *sys_getpwuid(uid_t uid)
658 {
659         return getpwuid(uid);
660 }
661
662 struct group *sys_getgrnam(const char *name)
663 {
664         return getgrnam(name);
665 }
666
667 struct group *sys_getgrgid(gid_t gid)
668 {
669         return getgrgid(gid);
670 }
671
672
673 /**************************************************************************
674  Extract a command into an arg list. Uses a static pstring for storage.
675  Caller frees returned arg list (which contains pointers into the static pstring).
676 ****************************************************************************/
677
678 static char **extract_args(const char *command)
679 {
680         static pstring trunc_cmd;
681         char *ptr;
682         int argcl;
683         char **argl = NULL;
684         int i;
685
686         pstrcpy(trunc_cmd, command);
687
688         if(!(ptr = strtok(trunc_cmd, " \t"))) {
689                 errno = EINVAL;
690                 return NULL;
691         }
692
693         /*
694          * Count the args.
695          */
696
697         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
698                 argcl++;
699
700         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
701                 return NULL;
702
703         /*
704          * Now do the extraction.
705          */
706
707         pstrcpy(trunc_cmd, command);
708
709         ptr = strtok(trunc_cmd, " \t");
710         i = 0;
711         argl[i++] = ptr;
712
713         while((ptr = strtok(NULL, " \t")) != NULL)
714                 argl[i++] = ptr;
715
716         argl[i++] = NULL;
717         return argl;
718 }
719
720 /**************************************************************************
721  Wrapper for popen. Safer as it doesn't search a path.
722  Modified from the glibc sources.
723  modified by tridge to return a file descriptor. We must kick our FILE* habit
724 ****************************************************************************/
725
726 typedef struct _popen_list
727 {
728         int fd;
729         pid_t child_pid;
730         struct _popen_list *next;
731 } popen_list;
732
733 static popen_list *popen_chain;
734
735 int sys_popen(const char *command)
736 {
737         int parent_end, child_end;
738         int pipe_fds[2];
739         popen_list *entry = NULL;
740         char **argl = NULL;
741
742         if (pipe(pipe_fds) < 0)
743                 return -1;
744
745         parent_end = pipe_fds[0];
746         child_end = pipe_fds[1];
747
748         if (!*command) {
749                 errno = EINVAL;
750                 goto err_exit;
751         }
752
753         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
754                 goto err_exit;
755
756         ZERO_STRUCTP(entry);
757
758         /*
759          * Extract the command and args into a NULL terminated array.
760          */
761
762         if(!(argl = extract_args(command)))
763                 goto err_exit;
764
765         entry->child_pid = fork();
766
767         if (entry->child_pid == -1) {
768                 goto err_exit;
769         }
770
771         if (entry->child_pid == 0) {
772
773                 /*
774                  * Child !
775                  */
776
777                 int child_std_end = STDOUT_FILENO;
778                 popen_list *p;
779
780                 close(parent_end);
781                 if (child_end != child_std_end) {
782                         dup2 (child_end, child_std_end);
783                         close (child_end);
784                 }
785
786                 /*
787                  * POSIX.2:  "popen() shall ensure that any streams from previous
788                  * popen() calls that remain open in the parent process are closed
789                  * in the new child process."
790                  */
791
792                 for (p = popen_chain; p; p = p->next)
793                         close(p->fd);
794
795                 execv(argl[0], argl);
796                 _exit (127);
797         }
798
799         /*
800          * Parent.
801          */
802
803         close (child_end);
804         SAFE_FREE(argl);
805
806         /* Link into popen_chain. */
807         entry->next = popen_chain;
808         popen_chain = entry;
809         entry->fd = parent_end;
810
811         return entry->fd;
812
813 err_exit:
814
815         SAFE_FREE(entry);
816         SAFE_FREE(argl);
817         close(pipe_fds[0]);
818         close(pipe_fds[1]);
819         return -1;
820 }
821
822 /**************************************************************************
823  Wrapper for pclose. Modified from the glibc sources.
824 ****************************************************************************/
825
826 int sys_pclose(int fd)
827 {
828         int wstatus;
829         popen_list **ptr = &popen_chain;
830         popen_list *entry = NULL;
831         pid_t wait_pid;
832         int status = -1;
833
834         /* Unlink from popen_chain. */
835         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
836                 if ((*ptr)->fd == fd) {
837                         entry = *ptr;
838                         *ptr = (*ptr)->next;
839                         status = 0;
840                         break;
841                 }
842         }
843
844         if (status < 0 || close(entry->fd) < 0)
845                 return -1;
846
847         /*
848          * As Samba is catching and eating child process
849          * exits we don't really care about the child exit
850          * code, a -1 with errno = ECHILD will do fine for us.
851          */
852
853         do {
854                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
855         } while (wait_pid == -1 && errno == EINTR);
856
857         SAFE_FREE(entry);
858
859         if (wait_pid == -1)
860                 return -1;
861         return wstatus;
862 }
863
864 /**************************************************************************
865  Wrappers for dlopen, dlsym, dlclose.
866 ****************************************************************************/
867
868 void *sys_dlopen(const char *name, int flags)
869 {
870 #if defined(HAVE_DLOPEN)
871         return dlopen(name, flags);
872 #else
873         return NULL;
874 #endif
875 }
876
877 void *sys_dlsym(void *handle, const char *symbol)
878 {
879 #if defined(HAVE_DLSYM)
880     return dlsym(handle, symbol);
881 #else
882     return NULL;
883 #endif
884 }
885
886 int sys_dlclose (void *handle)
887 {
888 #if defined(HAVE_DLCLOSE)
889         return dlclose(handle);
890 #else
891         return 0;
892 #endif
893 }
894
895 const char *sys_dlerror(void)
896 {
897 #if defined(HAVE_DLERROR)
898         return dlerror();
899 #else
900         return NULL;
901 #endif
902 }
903
904 int sys_dup2(int oldfd, int newfd) 
905 {
906 #if defined(HAVE_DUP2)
907         return dup2(oldfd, newfd);
908 #else
909         errno = ENOSYS;
910         return -1;
911 #endif
912 }
913