Ensured all the system calls in msdfs.c go through the vfs layer.
[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 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(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(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     free((char *)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   free((char *)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     free((char *)group_list);
591     errno = saved_errno;
592     return -1;
593   }
594  
595   free((char *)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  The following are the UNICODE versions of *all* system interface functions
731  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
732  which currently are left as ascii as they are not used other than in name
733  resolution.
734 ****************************************************************************/
735
736 /**************************************************************************
737  Wide stat. Just narrow and call sys_xxx.
738 ****************************************************************************/
739
740 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
741 {
742         pstring fname;
743         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
744 }
745
746 /**************************************************************************
747  Wide lstat. Just narrow and call sys_xxx.
748 ****************************************************************************/
749
750 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
751 {
752         pstring fname;
753         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
754 }
755
756 /**************************************************************************
757  Wide creat. Just narrow and call sys_xxx.
758 ****************************************************************************/
759
760 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
761 {
762         pstring fname;
763         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
764 }
765
766 /**************************************************************************
767  Wide open. Just narrow and call sys_xxx.
768 ****************************************************************************/
769
770 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
771 {
772         pstring fname;
773         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
774 }
775
776 /**************************************************************************
777  Wide fopen. Just narrow and call sys_xxx.
778 ****************************************************************************/
779
780 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
781 {
782         pstring fname;
783         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
784 }
785
786 /**************************************************************************
787  Wide opendir. Just narrow and call sys_xxx.
788 ****************************************************************************/
789
790 DIR *wsys_opendir(const smb_ucs2_t *wfname)
791 {
792         pstring fname;
793         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
794 }
795
796 /**************************************************************************
797  Wide readdir. Return a structure pointer containing a wide filename.
798 ****************************************************************************/
799
800 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
801 {
802         static SMB_STRUCT_WDIRENT retval;
803         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
804
805         if(!dirval)
806                 return NULL;
807
808         /*
809          * The only POSIX defined member of this struct is d_name.
810          */
811
812         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
813
814         return &retval;
815 }
816
817 /**************************************************************************
818  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
819 ****************************************************************************/
820
821 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
822 {
823         pstring fname;
824         char *p = sys_getwd(fname);
825
826         if(!p)
827                 return NULL;
828
829         return unix_to_unicode(s, p, sizeof(wpstring));
830 }
831
832 /**************************************************************************
833  Wide chown. Just narrow and call sys_xxx.
834 ****************************************************************************/
835
836 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
837 {
838         pstring fname;
839         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
840 }
841
842 /**************************************************************************
843  Wide chroot. Just narrow and call sys_xxx.
844 ****************************************************************************/
845
846 int wsys_chroot(const smb_ucs2_t *wfname)
847 {
848         pstring fname;
849         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
850 }
851
852 /**************************************************************************
853  Wide getpwnam. Return a structure pointer containing wide names.
854 ****************************************************************************/
855
856 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
857 {
858         static SMB_STRUCT_WPASSWD retval;
859         fstring name;
860         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
861
862         if(!pwret)
863                 return NULL;
864
865         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
866         retval.pw_passwd = pwret->pw_passwd;
867         retval.pw_uid = pwret->pw_uid;
868         retval.pw_gid = pwret->pw_gid;
869         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
870         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
871         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
872
873         return &retval;
874 }
875
876 /**************************************************************************
877  Wide getpwuid. Return a structure pointer containing wide names.
878 ****************************************************************************/
879
880 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
881 {
882         static SMB_STRUCT_WPASSWD retval;
883         struct passwd *pwret = sys_getpwuid(uid);
884
885         if(!pwret)
886                 return NULL;
887
888         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
889         retval.pw_passwd = pwret->pw_passwd;
890         retval.pw_uid = pwret->pw_uid;
891         retval.pw_gid = pwret->pw_gid;
892         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
893         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
894         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
895
896         return &retval;
897 }
898
899 /**************************************************************************
900  Extract a command into an arg list. Uses a static pstring for storage.
901  Caller frees returned arg list (which contains pointers into the static pstring).
902 ****************************************************************************/
903
904 static char **extract_args(const char *command)
905 {
906         static pstring trunc_cmd;
907         char *ptr;
908         int argcl;
909         char **argl = NULL;
910         int i;
911
912         pstrcpy(trunc_cmd, command);
913
914         if(!(ptr = strtok(trunc_cmd, " \t"))) {
915                 errno = EINVAL;
916                 return NULL;
917         }
918
919         /*
920          * Count the args.
921          */
922
923         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
924                 argcl++;
925
926         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
927                 return NULL;
928
929         /*
930          * Now do the extraction.
931          */
932
933         pstrcpy(trunc_cmd, command);
934
935         ptr = strtok(trunc_cmd, " \t");
936         i = 0;
937         argl[i++] = ptr;
938
939         while((ptr = strtok(NULL, " \t")) != NULL)
940                 argl[i++] = ptr;
941
942         argl[i++] = NULL;
943         return argl;
944 }
945
946 /**************************************************************************
947  Wrapper for fork. Ensures that mypid is reset. Used so we can write
948  a sys_getpid() that only does a system call *once*.
949 ****************************************************************************/
950
951 static pid_t mypid = (pid_t)-1;
952
953 pid_t sys_fork(void)
954 {
955         pid_t forkret = fork();
956
957         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
958                 mypid = (pid_t) -1;
959
960         return forkret;
961 }
962
963 /**************************************************************************
964  Wrapper for getpid. Ensures we only do a system call *once*.
965 ****************************************************************************/
966
967 pid_t sys_getpid(void)
968 {
969         if (mypid == (pid_t)-1)
970                 mypid = getpid();
971
972         return mypid;
973 }
974
975 /**************************************************************************
976  Wrapper for popen. Safer as it doesn't search a path.
977  Modified from the glibc sources.
978  modified by tridge to return a file descriptor. We must kick our FILE* habit
979 ****************************************************************************/
980
981 typedef struct _popen_list
982 {
983         int fd;
984         pid_t child_pid;
985         struct _popen_list *next;
986 } popen_list;
987
988 static popen_list *popen_chain;
989
990 int sys_popen(const char *command)
991 {
992         int parent_end, child_end;
993         int pipe_fds[2];
994         popen_list *entry = NULL;
995         char **argl = NULL;
996
997         if (pipe(pipe_fds) < 0)
998                 return -1;
999
1000         parent_end = pipe_fds[0];
1001         child_end = pipe_fds[1];
1002
1003         if (!*command) {
1004                 errno = EINVAL;
1005                 goto err_exit;
1006         }
1007
1008         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
1009                 goto err_exit;
1010
1011         ZERO_STRUCTP(entry);
1012
1013         /*
1014          * Extract the command and args into a NULL terminated array.
1015          */
1016
1017         if(!(argl = extract_args(command)))
1018                 goto err_exit;
1019
1020         entry->child_pid = sys_fork();
1021
1022         if (entry->child_pid == -1) {
1023                 goto err_exit;
1024         }
1025
1026         if (entry->child_pid == 0) {
1027
1028                 /*
1029                  * Child !
1030                  */
1031
1032                 int child_std_end = STDOUT_FILENO;
1033                 popen_list *p;
1034
1035                 close(parent_end);
1036                 if (child_end != child_std_end) {
1037                         dup2 (child_end, child_std_end);
1038                         close (child_end);
1039                 }
1040
1041                 /*
1042                  * POSIX.2:  "popen() shall ensure that any streams from previous
1043                  * popen() calls that remain open in the parent process are closed
1044                  * in the new child process."
1045                  */
1046
1047                 for (p = popen_chain; p; p = p->next)
1048                         close(p->fd);
1049
1050                 execv(argl[0], argl);
1051                 _exit (127);
1052         }
1053
1054         /*
1055          * Parent.
1056          */
1057
1058         close (child_end);
1059         free((char *)argl);
1060
1061         /* Link into popen_chain. */
1062         entry->next = popen_chain;
1063         popen_chain = entry;
1064         entry->fd = parent_end;
1065
1066         return entry->fd;
1067
1068 err_exit:
1069
1070         if(entry)
1071                 free((char *)entry);
1072         if(argl)
1073                 free((char *)argl);
1074         close(pipe_fds[0]);
1075         close(pipe_fds[1]);
1076         return -1;
1077 }
1078
1079 /**************************************************************************
1080  Wrapper for pclose. Modified from the glibc sources.
1081 ****************************************************************************/
1082 int sys_pclose(int fd)
1083 {
1084         int wstatus;
1085         popen_list **ptr = &popen_chain;
1086         popen_list *entry = NULL;
1087         pid_t wait_pid;
1088         int status = -1;
1089
1090         /* Unlink from popen_chain. */
1091         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1092                 if ((*ptr)->fd == fd) {
1093                         entry = *ptr;
1094                         *ptr = (*ptr)->next;
1095                         status = 0;
1096                         break;
1097                 }
1098         }
1099
1100         if (status < 0 || close(entry->fd) < 0)
1101                 return -1;
1102
1103         /*
1104          * As Samba is catching and eating child process
1105          * exits we don't really care about the child exit
1106          * code, a -1 with errno = ECHILD will do fine for us.
1107          */
1108
1109         do {
1110                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1111         } while (wait_pid == -1 && errno == EINTR);
1112
1113         free((char *)entry);
1114
1115         if (wait_pid == -1)
1116                 return -1;
1117         return wstatus;
1118 }
1119
1120 /**************************************************************************
1121  Wrappers for dlopen, dlsym, dlclose.
1122 ****************************************************************************/
1123
1124 void *sys_dlopen(const char *name, int flags)
1125 {
1126 #ifdef HAVE_LIBDL
1127         return dlopen(name, flags);
1128 #else
1129         return NULL;
1130 #endif
1131 }
1132
1133 void *sys_dlsym(void *handle, char *symbol)
1134 {
1135 #ifdef HAVE_LIBDL
1136     return dlsym(handle, symbol);
1137 #else
1138     return NULL;
1139 #endif
1140 }
1141
1142 int sys_dlclose (void *handle)
1143 {
1144 #ifdef HAVE_LIBDL
1145         return dlclose(handle);
1146 #else
1147         return 0;
1148 #endif
1149 }