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