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