sys_popen got damaged when converted from FILE * to int fd I think.
[tprouty/samba.git] / source / 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 static struct passwd *setup_pwret(struct passwd *pass)
584 {
585         static pstring pw_name;
586         static pstring pw_passwd;
587         static struct passwd pw_ret;
588
589         if (pass == NULL)
590         {
591                 return NULL;
592         }
593
594         memcpy((char *)&pw_ret, pass, sizeof(struct passwd));
595
596         if (pass->pw_name)
597         {
598                 pw_ret.pw_name = pw_name;
599                 pstrcpy(pw_ret.pw_name, pass->pw_name);
600         }
601
602         if (pass->pw_passwd)
603         {
604                 pw_ret.pw_passwd = pw_passwd;
605                 pstrcpy(pw_ret.pw_passwd, pass->pw_passwd);
606         }
607
608         return &pw_ret;
609 }
610
611 /**************************************************************************
612  Wrapper for getpwnam(). Always returns a static that can be modified.
613 ****************************************************************************/
614
615 struct passwd *sys_getpwnam(const char *name)
616 {
617         return setup_pwret(getpwnam(name));
618 }
619
620 /**************************************************************************
621  Wrapper for getpwuid(). Always returns a static that can be modified.
622 ****************************************************************************/
623
624 struct passwd *sys_getpwuid(uid_t uid)
625 {
626         return setup_pwret(getpwuid(uid));
627 }
628
629 /**************************************************************************
630  The following are the UNICODE versions of *all* system interface functions
631  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
632  which currently are left as ascii as they are not used other than in name
633  resolution.
634 ****************************************************************************/
635
636 /**************************************************************************
637  Wide stat. Just narrow and call sys_xxx.
638 ****************************************************************************/
639
640 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
641 {
642         pstring fname;
643         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
644 }
645
646 /**************************************************************************
647  Wide lstat. Just narrow and call sys_xxx.
648 ****************************************************************************/
649
650 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
651 {
652         pstring fname;
653         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
654 }
655
656 /**************************************************************************
657  Wide creat. Just narrow and call sys_xxx.
658 ****************************************************************************/
659
660 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
661 {
662         pstring fname;
663         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
664 }
665
666 /**************************************************************************
667  Wide open. Just narrow and call sys_xxx.
668 ****************************************************************************/
669
670 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
671 {
672         pstring fname;
673         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
674 }
675
676 /**************************************************************************
677  Wide fopen. Just narrow and call sys_xxx.
678 ****************************************************************************/
679
680 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
681 {
682         pstring fname;
683         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
684 }
685
686 /**************************************************************************
687  Wide opendir. Just narrow and call sys_xxx.
688 ****************************************************************************/
689
690 DIR *wsys_opendir(const smb_ucs2_t *wfname)
691 {
692         pstring fname;
693         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
694 }
695
696 /**************************************************************************
697  Wide readdir. Return a structure pointer containing a wide filename.
698 ****************************************************************************/
699
700 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
701 {
702         static SMB_STRUCT_WDIRENT retval;
703         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
704
705         if(!dirval)
706                 return NULL;
707
708         /*
709          * The only POSIX defined member of this struct is d_name.
710          */
711
712         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
713
714         return &retval;
715 }
716
717 /**************************************************************************
718  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
719 ****************************************************************************/
720
721 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
722 {
723         pstring fname;
724         char *p = sys_getwd(fname);
725
726         if(!p)
727                 return NULL;
728
729         return unix_to_unicode(s, p, sizeof(wpstring));
730 }
731
732 /**************************************************************************
733  Wide chown. Just narrow and call sys_xxx.
734 ****************************************************************************/
735
736 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
737 {
738         pstring fname;
739         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
740 }
741
742 /**************************************************************************
743  Wide chroot. Just narrow and call sys_xxx.
744 ****************************************************************************/
745
746 int wsys_chroot(const smb_ucs2_t *wfname)
747 {
748         pstring fname;
749         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
750 }
751
752 /**************************************************************************
753  Wide getpwnam. Return a structure pointer containing wide names.
754 ****************************************************************************/
755
756 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
757 {
758         static SMB_STRUCT_WPASSWD retval;
759         fstring name;
760         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
761
762         if(!pwret)
763                 return NULL;
764
765         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
766         retval.pw_passwd = pwret->pw_passwd;
767         retval.pw_uid = pwret->pw_uid;
768         retval.pw_gid = pwret->pw_gid;
769         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
770         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
771         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
772
773         return &retval;
774 }
775
776 /**************************************************************************
777  Wide getpwuid. Return a structure pointer containing wide names.
778 ****************************************************************************/
779
780 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
781 {
782         static SMB_STRUCT_WPASSWD retval;
783         struct passwd *pwret = sys_getpwuid(uid);
784
785         if(!pwret)
786                 return NULL;
787
788         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
789         retval.pw_passwd = pwret->pw_passwd;
790         retval.pw_uid = pwret->pw_uid;
791         retval.pw_gid = pwret->pw_gid;
792         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
793         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
794         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
795
796         return &retval;
797 }
798
799 /**************************************************************************
800  Extract a command into an arg list. Uses a static pstring for storage.
801  Caller frees returned arg list (which contains pointers into the static pstring).
802 ****************************************************************************/
803
804 static char **extract_args(const char *command)
805 {
806         static pstring trunc_cmd;
807         char *ptr;
808         int argcl;
809         char **argl = NULL;
810         int i;
811
812         pstrcpy(trunc_cmd, command);
813
814         if(!(ptr = strtok(trunc_cmd, " \t"))) {
815                 errno = EINVAL;
816                 return NULL;
817         }
818
819         /*
820          * Count the args.
821          */
822
823         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
824                 argcl++;
825
826         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
827                 return NULL;
828
829         /*
830          * Now do the extraction.
831          */
832
833         pstrcpy(trunc_cmd, command);
834
835         ptr = strtok(trunc_cmd, " \t");
836         i = 0;
837         argl[i++] = ptr;
838
839         while((ptr = strtok(NULL, " \t")) != NULL)
840                 argl[i++] = ptr;
841
842         argl[i++] = NULL;
843         return argl;
844 }
845
846 /**************************************************************************
847  Wrapper for fork. Ensures that mypid is reset. Used so we can write
848  a sys_getpid() that only does a system call *once*.
849 ****************************************************************************/
850
851 static pid_t mypid = (pid_t)-1;
852
853 pid_t sys_fork(void)
854 {
855         pid_t forkret = fork();
856
857         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
858                 mypid = (pid_t) -1;
859
860         return forkret;
861 }
862
863 /**************************************************************************
864  Wrapper for getpid. Ensures we only do a system call *once*.
865 ****************************************************************************/
866
867 pid_t sys_getpid(void)
868 {
869         if (mypid == (pid_t)-1)
870                 mypid = getpid();
871
872         return mypid;
873 }
874
875 /**************************************************************************
876  Wrapper for popen. Safer as it doesn't search a path.
877  Modified from the glibc sources.
878  modified by tridge to return a file descriptor. We must kick our FILE* habit
879 ****************************************************************************/
880
881 typedef struct _popen_list
882 {
883         int fd;
884         pid_t child_pid;
885         struct _popen_list *next;
886 } popen_list;
887
888 static popen_list *popen_chain;
889
890 int sys_popen(const char *command)
891 {
892         int parent_end, child_end;
893         int pipe_fds[2];
894         popen_list *entry = NULL;
895         char **argl = NULL;
896
897         if (pipe(pipe_fds) < 0)
898                 return -1;
899
900         parent_end = pipe_fds[0];
901         child_end = pipe_fds[1];
902
903         if (!*command) {
904                 errno = EINVAL;
905                 goto err_exit;
906         }
907
908         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
909                 goto err_exit;
910
911         ZERO_STRUCTP(entry);
912
913         /*
914          * Extract the command and args into a NULL terminated array.
915          */
916
917         if(!(argl = extract_args(command)))
918                 goto err_exit;
919
920         entry->child_pid = sys_fork();
921
922         if (entry->child_pid == -1) {
923                 goto err_exit;
924         }
925
926         if (entry->child_pid == 0) {
927
928                 /*
929                  * Child !
930                  */
931
932                 int child_std_end = STDOUT_FILENO;
933                 popen_list *p;
934
935                 close(parent_end);
936                 if (child_end != child_std_end) {
937                         dup2 (child_end, child_std_end);
938                         close (child_end);
939                 }
940
941                 /*
942                  * POSIX.2:  "popen() shall ensure that any streams from previous
943                  * popen() calls that remain open in the parent process are closed
944                  * in the new child process."
945                  */
946
947                 for (p = popen_chain; p; p = p->next)
948                         close(p->fd);
949
950                 execv(argl[0], argl);
951                 _exit (127);
952         }
953
954         /*
955          * Parent.
956          */
957
958         close (child_end);
959         free((char *)argl);
960
961         /* Link into popen_chain. */
962         entry->next = popen_chain;
963         popen_chain = entry;
964         entry->fd = parent_end;
965
966         return entry->fd;
967
968 err_exit:
969
970         if(entry)
971                 free((char *)entry);
972         if(argl)
973                 free((char *)argl);
974         close(pipe_fds[0]);
975         close(pipe_fds[1]);
976         return -1;
977 }
978
979 /**************************************************************************
980  Wrapper for pclose. Modified from the glibc sources.
981 ****************************************************************************/
982 int sys_pclose(int fd)
983 {
984         int wstatus;
985         popen_list **ptr = &popen_chain;
986         popen_list *entry = NULL;
987         pid_t wait_pid;
988         int status = -1;
989
990         /* Unlink from popen_chain. */
991         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
992                 if ((*ptr)->fd == fd) {
993                         entry = *ptr;
994                         *ptr = (*ptr)->next;
995                         status = 0;
996                         break;
997                 }
998         }
999
1000         if (status < 0 || close(entry->fd) < 0)
1001                 return -1;
1002
1003         /*
1004          * As Samba is catching and eating child process
1005          * exits we don't really care about the child exit
1006          * code, a -1 with errno = ECHILD will do fine for us.
1007          */
1008
1009         do {
1010                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1011         } while (wait_pid == -1 && errno == EINTR);
1012
1013         free((char *)entry);
1014
1015         if (wait_pid == -1)
1016                 return -1;
1017         return wstatus;
1018 }