Added sys_dlopen/sys_dlsym/sys_dlclose.
[ira/wip.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 chown isn't used much but OS/2 doesn't have it
269 ********************************************************************/
270
271 int sys_chown(const char *fname,uid_t uid,gid_t gid)
272 {
273 #ifndef HAVE_CHOWN
274         static int done;
275         if (!done) {
276                 DEBUG(1,("WARNING: no chown!\n"));
277                 done=1;
278         }
279 #else
280         return(chown(fname,uid,gid));
281 #endif
282 }
283
284 /*******************************************************************
285 os/2 also doesn't have chroot
286 ********************************************************************/
287 int sys_chroot(const char *dname)
288 {
289 #ifndef HAVE_CHROOT
290         static int done;
291         if (!done) {
292                 DEBUG(1,("WARNING: no chroot!\n"));
293                 done=1;
294         }
295         errno = ENOSYS;
296         return -1;
297 #else
298         return(chroot(dname));
299 #endif
300 }
301
302 /**************************************************************************
303 A wrapper for gethostbyname() that tries avoids looking up hostnames 
304 in the root domain, which can cause dial-on-demand links to come up for no
305 apparent reason.
306 ****************************************************************************/
307 struct hostent *sys_gethostbyname(const char *name)
308 {
309 #ifdef REDUCE_ROOT_DNS_LOOKUPS
310   char query[256], hostname[256];
311   char *domain;
312
313   /* Does this name have any dots in it? If so, make no change */
314
315   if (strchr(name, '.'))
316     return(gethostbyname(name));
317
318   /* Get my hostname, which should have domain name 
319      attached. If not, just do the gethostname on the
320      original string. 
321   */
322
323   gethostname(hostname, sizeof(hostname) - 1);
324   hostname[sizeof(hostname) - 1] = 0;
325   if ((domain = strchr(hostname, '.')) == NULL)
326     return(gethostbyname(name));
327
328   /* Attach domain name to query and do modified query.
329      If names too large, just do gethostname on the
330      original string.
331   */
332
333   if((strlen(name) + strlen(domain)) >= sizeof(query))
334     return(gethostbyname(name));
335
336   slprintf(query, sizeof(query)-1, "%s%s", name, domain);
337   return(gethostbyname(query));
338 #else /* REDUCE_ROOT_DNS_LOOKUPS */
339   return(gethostbyname(name));
340 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
341 }
342
343
344 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
345 /**************************************************************************
346  Try and abstract process capabilities (for systems that have them).
347 ****************************************************************************/
348 static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
349 {
350   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
351   {
352     cap_t cap = cap_get_proc();
353
354     if (cap == NULL) {
355       DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
356             strerror(errno)));
357       return False;
358     }
359
360     if(enable)
361       cap->cap_effective |= CAP_NETWORK_MGT;
362     else
363       cap->cap_effective &= ~CAP_NETWORK_MGT;
364
365     if (cap_set_proc(cap) == -1) {
366       DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
367             strerror(errno)));
368       cap_free(cap);
369       return False;
370     }
371
372     cap_free(cap);
373
374     DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
375   }
376   return True;
377 }
378
379 /**************************************************************************
380  Try and abstract inherited process capabilities (for systems that have them).
381 ****************************************************************************/
382
383 static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
384 {
385   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
386   {
387     cap_t cap = cap_get_proc();
388
389     if (cap == NULL) {
390       DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
391             strerror(errno)));
392       return False;
393     }
394
395     if(enable)
396       cap->cap_inheritable |= CAP_NETWORK_MGT;
397     else
398       cap->cap_inheritable &= ~CAP_NETWORK_MGT;
399
400     if (cap_set_proc(cap) == -1) {
401       DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
402             strerror(errno)));
403       cap_free(cap);
404       return False;
405     }
406
407     cap_free(cap);
408
409     DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
410   }
411   return True;
412 }
413 #endif
414
415 /****************************************************************************
416 gain the oplock capability from the kernel if possible
417 ****************************************************************************/
418 void oplock_set_capability(BOOL this_process, BOOL inherit)
419 {
420 #if HAVE_KERNEL_OPLOCKS_IRIX
421         set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
422         set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
423 #endif
424 }
425
426 /**************************************************************************
427  Wrapper for random().
428 ****************************************************************************/
429
430 long sys_random(void)
431 {
432 #if defined(HAVE_RANDOM)
433   return (long)random();
434 #elif defined(HAVE_RAND)
435   return (long)rand();
436 #else
437   DEBUG(0,("Error - no random function available !\n"));
438   exit(1);
439 #endif
440 }
441
442 /**************************************************************************
443  Wrapper for srandom().
444 ****************************************************************************/
445
446 void sys_srandom(unsigned int seed)
447 {
448 #if defined(HAVE_SRANDOM)
449   srandom(seed);
450 #elif defined(HAVE_SRAND)
451   srand(seed);
452 #else
453   DEBUG(0,("Error - no srandom function available !\n"));
454   exit(1);
455 #endif
456 }
457
458 /**************************************************************************
459  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
460 ****************************************************************************/
461
462 int groups_max(void)
463 {
464 #if defined(SYSCONF_SC_NGROUPS_MAX)
465   int ret = sysconf(_SC_NGROUPS_MAX);
466   return (ret == -1) ? NGROUPS_MAX : ret;
467 #else
468   return NGROUPS_MAX;
469 #endif
470 }
471
472 /**************************************************************************
473  Wrapper for getgroups. Deals with broken (int) case.
474 ****************************************************************************/
475
476 int sys_getgroups(int setlen, gid_t *gidset)
477 {
478 #if !defined(HAVE_BROKEN_GETGROUPS)
479   return getgroups(setlen, gidset);
480 #else
481
482   GID_T gid;
483   GID_T *group_list;
484   int i, ngroups;
485
486   if(setlen == 0) {
487     return getgroups(setlen, &gid);
488   }
489
490   /*
491    * Broken case. We need to allocate a
492    * GID_T array of size setlen.
493    */
494
495   if(setlen < 0) {
496     errno = EINVAL; 
497     return -1;
498   } 
499
500   if (setlen == 0)
501     setlen = groups_max();
502
503   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
504     DEBUG(0,("sys_getgroups: Malloc fail.\n"));
505     return -1;
506   }
507
508   if((ngroups = getgroups(setlen, group_list)) < 0) {
509     int saved_errno = errno;
510     free((char *)group_list);
511     errno = saved_errno;
512     return -1;
513   }
514
515   for(i = 0; i < ngroups; i++)
516     gidset[i] = (gid_t)group_list[i];
517
518   free((char *)group_list);
519   return ngroups;
520 #endif /* HAVE_BROKEN_GETGROUPS */
521 }
522
523 #ifdef HAVE_SETGROUPS
524
525 /**************************************************************************
526  Wrapper for setgroups. Deals with broken (int) case. Automatically used
527  if we have broken getgroups.
528 ****************************************************************************/
529
530 int sys_setgroups(int setlen, gid_t *gidset)
531 {
532 #if !defined(HAVE_BROKEN_GETGROUPS)
533   return setgroups(setlen, gidset);
534 #else
535
536   GID_T *group_list;
537   int i ; 
538
539   if (setlen == 0)
540     return 0 ;
541
542   if (setlen < 0 || setlen > groups_max()) {
543     errno = EINVAL; 
544     return -1;   
545   }
546
547   /*
548    * Broken case. We need to allocate a
549    * GID_T array of size setlen.
550    */
551
552   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
553     DEBUG(0,("sys_setgroups: Malloc fail.\n"));
554     return -1;    
555   }
556  
557   for(i = 0; i < setlen; i++) 
558     group_list[i] = (GID_T) gidset[i]; 
559
560   if(setgroups(setlen, group_list) != 0) {
561     int saved_errno = errno;
562     free((char *)group_list);
563     errno = saved_errno;
564     return -1;
565   }
566  
567   free((char *)group_list);
568   return 0 ;
569 #endif /* HAVE_BROKEN_GETGROUPS */
570 }
571
572 #endif /* HAVE_SETGROUPS */
573
574 /*
575  * We only wrap pw_name and pw_passwd for now as these
576  * are the only potentially modified fields.
577  */
578
579 /**************************************************************************
580  Helper function for getpwnam/getpwuid wrappers.
581 ****************************************************************************/
582
583 struct saved_pw {
584         fstring         pw_name;
585         fstring         pw_passwd;
586         struct passwd pass;
587 };
588
589 static struct saved_pw pw_mod; /* This is the structure returned - can be modified. */
590 static struct saved_pw pw_cache; /* This is the structure saved - used to check cache. */
591
592 static int num_lookups; /* Counter so we don't always use cache. */
593 #ifndef PW_RET_CACHE_MAX_LOOKUPS
594 #define PW_RET_CACHE_MAX_LOOKUPS 100
595 #endif
596
597 static struct passwd *setup_pwret(struct passwd *pass)
598 {
599         if (pass == NULL) {
600                 /* Clear the caches. */
601                 memset(&pw_cache, '\0', sizeof(struct saved_pw));
602                 memset(&pw_mod, '\0', sizeof(struct saved_pw));
603                 num_lookups = 0;
604                 return NULL;
605         }
606
607         /* this gets the uid, gid and null pointers */
608
609         memcpy((char *)&pw_mod.pass, pass, sizeof(struct passwd));
610         fstrcpy(pw_mod.pw_name, pass->pw_name);
611         pw_mod.pass.pw_name = pw_mod.pw_name;
612         fstrcpy(pw_mod.pw_passwd, pass->pw_passwd);
613         pw_mod.pass.pw_passwd = pw_mod.pw_passwd;
614
615
616         if (pass != &pw_cache.pass) {
617
618                 /* If it's a cache miss we must also refill the cache. */
619
620                 memcpy((char *)&pw_cache.pass, pass, sizeof(struct passwd));
621                 fstrcpy(pw_cache.pw_name, pass->pw_name);
622                 pw_cache.pass.pw_name = pw_cache.pw_name;
623                 fstrcpy(pw_cache.pw_passwd, pass->pw_passwd);
624                 pw_cache.pass.pw_passwd = pw_cache.pw_passwd;
625
626                 num_lookups = 1;
627
628         } else {
629
630                 /* Cache hit. */
631
632                 num_lookups++;
633                 num_lookups = (num_lookups % PW_RET_CACHE_MAX_LOOKUPS);
634         }
635
636         return &pw_mod.pass;
637 }
638
639 /**************************************************************************
640  Wrappers for setpwent(), getpwent() and endpwent()
641 ****************************************************************************/
642
643 void sys_setpwent(void)
644 {
645         setup_pwret(NULL); /* Clear cache. */
646         setpwent();
647 }
648
649 struct passwd *sys_getpwent(void)
650 {
651         return setup_pwret(getpwent());
652 }
653
654 void sys_endpwent(void)
655 {
656         setup_pwret(NULL); /* Clear cache. */
657         endpwent();
658 }
659
660 /**************************************************************************
661  Wrapper for getpwnam(). Always returns a static that can be modified.
662 ****************************************************************************/
663
664 struct passwd *sys_getpwnam(const char *name)
665 {
666         if (!name || !name[0])
667                 return NULL;
668
669         /* check for a cache hit first */
670         if (num_lookups && pw_cache.pass.pw_name && !strcmp(name, pw_cache.pass.pw_name)) {
671                 DEBUG(2,("getpwnam(%s) avoided - using cached results\n",name));
672                 return setup_pwret(&pw_cache.pass);
673         }
674
675         return setup_pwret(getpwnam(name));
676 }
677
678 /**************************************************************************
679  Wrapper for getpwuid(). Always returns a static that can be modified.
680 ****************************************************************************/
681
682 struct passwd *sys_getpwuid(uid_t uid)
683 {
684         if (num_lookups && pw_cache.pass.pw_name && (uid == pw_cache.pass.pw_uid)) {
685                 DEBUG(2,("getpwuid(%d) avoided - using cached results\n",uid));
686                 return setup_pwret(&pw_cache.pass);
687         }
688         
689         DEBUG(2,("getpwuid(%d) called\n",uid));
690
691         return setup_pwret(getpwuid(uid));
692 }
693
694 /**************************************************************************
695  The following are the UNICODE versions of *all* system interface functions
696  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
697  which currently are left as ascii as they are not used other than in name
698  resolution.
699 ****************************************************************************/
700
701 /**************************************************************************
702  Wide stat. Just narrow and call sys_xxx.
703 ****************************************************************************/
704
705 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
706 {
707         pstring fname;
708         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
709 }
710
711 /**************************************************************************
712  Wide lstat. Just narrow and call sys_xxx.
713 ****************************************************************************/
714
715 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
716 {
717         pstring fname;
718         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
719 }
720
721 /**************************************************************************
722  Wide creat. Just narrow and call sys_xxx.
723 ****************************************************************************/
724
725 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
726 {
727         pstring fname;
728         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
729 }
730
731 /**************************************************************************
732  Wide open. Just narrow and call sys_xxx.
733 ****************************************************************************/
734
735 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
736 {
737         pstring fname;
738         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
739 }
740
741 /**************************************************************************
742  Wide fopen. Just narrow and call sys_xxx.
743 ****************************************************************************/
744
745 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
746 {
747         pstring fname;
748         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
749 }
750
751 /**************************************************************************
752  Wide opendir. Just narrow and call sys_xxx.
753 ****************************************************************************/
754
755 DIR *wsys_opendir(const smb_ucs2_t *wfname)
756 {
757         pstring fname;
758         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
759 }
760
761 /**************************************************************************
762  Wide readdir. Return a structure pointer containing a wide filename.
763 ****************************************************************************/
764
765 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
766 {
767         static SMB_STRUCT_WDIRENT retval;
768         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
769
770         if(!dirval)
771                 return NULL;
772
773         /*
774          * The only POSIX defined member of this struct is d_name.
775          */
776
777         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
778
779         return &retval;
780 }
781
782 /**************************************************************************
783  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
784 ****************************************************************************/
785
786 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
787 {
788         pstring fname;
789         char *p = sys_getwd(fname);
790
791         if(!p)
792                 return NULL;
793
794         return unix_to_unicode(s, p, sizeof(wpstring));
795 }
796
797 /**************************************************************************
798  Wide chown. Just narrow and call sys_xxx.
799 ****************************************************************************/
800
801 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
802 {
803         pstring fname;
804         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
805 }
806
807 /**************************************************************************
808  Wide chroot. Just narrow and call sys_xxx.
809 ****************************************************************************/
810
811 int wsys_chroot(const smb_ucs2_t *wfname)
812 {
813         pstring fname;
814         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
815 }
816
817 /**************************************************************************
818  Wide getpwnam. Return a structure pointer containing wide names.
819 ****************************************************************************/
820
821 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
822 {
823         static SMB_STRUCT_WPASSWD retval;
824         fstring name;
825         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
826
827         if(!pwret)
828                 return NULL;
829
830         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
831         retval.pw_passwd = pwret->pw_passwd;
832         retval.pw_uid = pwret->pw_uid;
833         retval.pw_gid = pwret->pw_gid;
834         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
835         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
836         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
837
838         return &retval;
839 }
840
841 /**************************************************************************
842  Wide getpwuid. Return a structure pointer containing wide names.
843 ****************************************************************************/
844
845 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
846 {
847         static SMB_STRUCT_WPASSWD retval;
848         struct passwd *pwret = sys_getpwuid(uid);
849
850         if(!pwret)
851                 return NULL;
852
853         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
854         retval.pw_passwd = pwret->pw_passwd;
855         retval.pw_uid = pwret->pw_uid;
856         retval.pw_gid = pwret->pw_gid;
857         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
858         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
859         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
860
861         return &retval;
862 }
863
864 /**************************************************************************
865  Extract a command into an arg list. Uses a static pstring for storage.
866  Caller frees returned arg list (which contains pointers into the static pstring).
867 ****************************************************************************/
868
869 static char **extract_args(const char *command)
870 {
871         static pstring trunc_cmd;
872         char *ptr;
873         int argcl;
874         char **argl = NULL;
875         int i;
876
877         pstrcpy(trunc_cmd, command);
878
879         if(!(ptr = strtok(trunc_cmd, " \t"))) {
880                 errno = EINVAL;
881                 return NULL;
882         }
883
884         /*
885          * Count the args.
886          */
887
888         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
889                 argcl++;
890
891         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
892                 return NULL;
893
894         /*
895          * Now do the extraction.
896          */
897
898         pstrcpy(trunc_cmd, command);
899
900         ptr = strtok(trunc_cmd, " \t");
901         i = 0;
902         argl[i++] = ptr;
903
904         while((ptr = strtok(NULL, " \t")) != NULL)
905                 argl[i++] = ptr;
906
907         argl[i++] = NULL;
908         return argl;
909 }
910
911 /**************************************************************************
912  Wrapper for fork. Ensures that mypid is reset. Used so we can write
913  a sys_getpid() that only does a system call *once*.
914 ****************************************************************************/
915
916 static pid_t mypid = (pid_t)-1;
917
918 pid_t sys_fork(void)
919 {
920         pid_t forkret = fork();
921
922         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
923                 mypid = (pid_t) -1;
924
925         return forkret;
926 }
927
928 /**************************************************************************
929  Wrapper for getpid. Ensures we only do a system call *once*.
930 ****************************************************************************/
931
932 pid_t sys_getpid(void)
933 {
934         if (mypid == (pid_t)-1)
935                 mypid = getpid();
936
937         return mypid;
938 }
939
940 /**************************************************************************
941  Wrapper for popen. Safer as it doesn't search a path.
942  Modified from the glibc sources.
943  modified by tridge to return a file descriptor. We must kick our FILE* habit
944 ****************************************************************************/
945
946 typedef struct _popen_list
947 {
948         int fd;
949         pid_t child_pid;
950         struct _popen_list *next;
951 } popen_list;
952
953 static popen_list *popen_chain;
954
955 int sys_popen(const char *command)
956 {
957         int parent_end, child_end;
958         int pipe_fds[2];
959         popen_list *entry = NULL;
960         char **argl = NULL;
961
962         if (pipe(pipe_fds) < 0)
963                 return -1;
964
965         parent_end = pipe_fds[0];
966         child_end = pipe_fds[1];
967
968         if (!*command) {
969                 errno = EINVAL;
970                 goto err_exit;
971         }
972
973         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
974                 goto err_exit;
975
976         ZERO_STRUCTP(entry);
977
978         /*
979          * Extract the command and args into a NULL terminated array.
980          */
981
982         if(!(argl = extract_args(command)))
983                 goto err_exit;
984
985         entry->child_pid = sys_fork();
986
987         if (entry->child_pid == -1) {
988                 goto err_exit;
989         }
990
991         if (entry->child_pid == 0) {
992
993                 /*
994                  * Child !
995                  */
996
997                 int child_std_end = STDOUT_FILENO;
998                 popen_list *p;
999
1000                 close(parent_end);
1001                 if (child_end != child_std_end) {
1002                         dup2 (child_end, child_std_end);
1003                         close (child_end);
1004                 }
1005
1006                 /*
1007                  * POSIX.2:  "popen() shall ensure that any streams from previous
1008                  * popen() calls that remain open in the parent process are closed
1009                  * in the new child process."
1010                  */
1011
1012                 for (p = popen_chain; p; p = p->next)
1013                         close(p->fd);
1014
1015                 execv(argl[0], argl);
1016                 _exit (127);
1017         }
1018
1019         /*
1020          * Parent.
1021          */
1022
1023         close (child_end);
1024         free((char *)argl);
1025
1026         /* Link into popen_chain. */
1027         entry->next = popen_chain;
1028         popen_chain = entry;
1029         entry->fd = parent_end;
1030
1031         return entry->fd;
1032
1033 err_exit:
1034
1035         if(entry)
1036                 free((char *)entry);
1037         if(argl)
1038                 free((char *)argl);
1039         close(pipe_fds[0]);
1040         close(pipe_fds[1]);
1041         return -1;
1042 }
1043
1044 /**************************************************************************
1045  Wrapper for pclose. Modified from the glibc sources.
1046 ****************************************************************************/
1047 int sys_pclose(int fd)
1048 {
1049         int wstatus;
1050         popen_list **ptr = &popen_chain;
1051         popen_list *entry = NULL;
1052         pid_t wait_pid;
1053         int status = -1;
1054
1055         /* Unlink from popen_chain. */
1056         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1057                 if ((*ptr)->fd == fd) {
1058                         entry = *ptr;
1059                         *ptr = (*ptr)->next;
1060                         status = 0;
1061                         break;
1062                 }
1063         }
1064
1065         if (status < 0 || close(entry->fd) < 0)
1066                 return -1;
1067
1068         /*
1069          * As Samba is catching and eating child process
1070          * exits we don't really care about the child exit
1071          * code, a -1 with errno = ECHILD will do fine for us.
1072          */
1073
1074         do {
1075                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1076         } while (wait_pid == -1 && errno == EINTR);
1077
1078         free((char *)entry);
1079
1080         if (wait_pid == -1)
1081                 return -1;
1082         return wstatus;
1083 }
1084
1085 /**************************************************************************
1086  Wrappers for dlopen, dlsym, dlclose.
1087 ****************************************************************************/
1088
1089 void *sys_dlopen(const char *name, int flags)
1090 {
1091 #ifdef HAVE_LIBDL
1092         return dlopen(name, flags);
1093 #else
1094         return NULL;
1095 #endif
1096 }
1097
1098 void *sys_dlsym(void *handle, char *symbol)
1099 {
1100 #ifdef HAVE_LIBDL
1101     return dlsym(handle, symbol);
1102 #else
1103     return NULL;
1104 #endif
1105 }
1106
1107 int sys_dlclose (void *handle)
1108 {
1109 #ifdef HAVE_LIBDL
1110         return dlclose(handle);
1111 #else
1112         return 0;
1113 #endif
1114 }