Removed version number from file header.
[samba.git] / source3 / 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 stat() wrapper that will deal with 64 bit filesizes.
77 ********************************************************************/
78
79 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
80 {
81         int ret;
82 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
83         ret = stat64(fname, sbuf);
84 #else
85         ret = stat(fname, sbuf);
86 #endif
87         /* we always want directories to appear zero size */
88         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
89         return ret;
90 }
91
92 /*******************************************************************
93  An fstat() wrapper that will deal with 64 bit filesizes.
94 ********************************************************************/
95
96 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
97 {
98         int ret;
99 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
100         ret = fstat64(fd, sbuf);
101 #else
102         ret = fstat(fd, sbuf);
103 #endif
104         /* we always want directories to appear zero size */
105         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
106         return ret;
107 }
108
109 /*******************************************************************
110  An lstat() wrapper that will deal with 64 bit filesizes.
111 ********************************************************************/
112
113 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
114 {
115         int ret;
116 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
117         ret = lstat64(fname, sbuf);
118 #else
119         ret = lstat(fname, sbuf);
120 #endif
121         /* we always want directories to appear zero size */
122         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
123         return ret;
124 }
125
126 /*******************************************************************
127  An ftruncate() wrapper that will deal with 64 bit filesizes.
128 ********************************************************************/
129
130 int sys_ftruncate(int fd, SMB_OFF_T offset)
131 {
132 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
133         return ftruncate64(fd, offset);
134 #else
135         return ftruncate(fd, offset);
136 #endif
137 }
138
139 /*******************************************************************
140  An lseek() wrapper that will deal with 64 bit filesizes.
141 ********************************************************************/
142
143 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
144 {
145 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
146         return lseek64(fd, offset, whence);
147 #else
148         return lseek(fd, offset, whence);
149 #endif
150 }
151
152 /*******************************************************************
153  An fseek() wrapper that will deal with 64 bit filesizes.
154 ********************************************************************/
155
156 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
157 {
158 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
159         return fseek64(fp, offset, whence);
160 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
161         return fseeko64(fp, offset, whence);
162 #else
163         return fseek(fp, offset, whence);
164 #endif
165 }
166
167 /*******************************************************************
168  An ftell() wrapper that will deal with 64 bit filesizes.
169 ********************************************************************/
170
171 SMB_OFF_T sys_ftell(FILE *fp)
172 {
173 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
174         return (SMB_OFF_T)ftell64(fp);
175 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
176         return (SMB_OFF_T)ftello64(fp);
177 #else
178         return (SMB_OFF_T)ftell(fp);
179 #endif
180 }
181
182 /*******************************************************************
183  A creat() wrapper that will deal with 64 bit filesizes.
184 ********************************************************************/
185
186 int sys_creat(const char *path, mode_t mode)
187 {
188 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
189         return creat64(path, mode);
190 #else
191         /*
192          * If creat64 isn't defined then ensure we call a potential open64.
193          * JRA.
194          */
195         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
196 #endif
197 }
198
199 /*******************************************************************
200  An open() wrapper that will deal with 64 bit filesizes.
201 ********************************************************************/
202
203 int sys_open(const char *path, int oflag, mode_t mode)
204 {
205 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
206         return open64(path, oflag, mode);
207 #else
208         return open(path, oflag, mode);
209 #endif
210 }
211
212 /*******************************************************************
213  An fopen() wrapper that will deal with 64 bit filesizes.
214 ********************************************************************/
215
216 FILE *sys_fopen(const char *path, const char *type)
217 {
218 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
219         return fopen64(path, type);
220 #else
221         return fopen(path, type);
222 #endif
223 }
224
225 /*******************************************************************
226  A readdir wrapper that will deal with 64 bit filesizes.
227 ********************************************************************/
228
229 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
230 {
231 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
232         return readdir64(dirp);
233 #else
234         return readdir(dirp);
235 #endif
236 }
237
238 /*******************************************************************
239  An mknod() wrapper that will deal with 64 bit filesizes.
240 ********************************************************************/
241
242 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
243 {
244 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
245 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
246         return mknod64(path, mode, dev);
247 #else
248         return mknod(path, mode, dev);
249 #endif
250 #else
251         /* No mknod system call. */
252         errno = ENOSYS;
253         return -1;
254 #endif
255 }
256
257 /*******************************************************************
258 The wait() calls vary between systems
259 ********************************************************************/
260
261 int sys_waitpid(pid_t pid,int *status,int options)
262 {
263 #ifdef HAVE_WAITPID
264         return waitpid(pid,status,options);
265 #else /* HAVE_WAITPID */
266         return wait4(pid, status, options, NULL);
267 #endif /* HAVE_WAITPID */
268 }
269
270 /*******************************************************************
271  System wrapper for getwd
272 ********************************************************************/
273
274 char *sys_getwd(char *s)
275 {
276         char *wd;
277 #ifdef HAVE_GETCWD
278         wd = (char *)getcwd(s, sizeof (pstring));
279 #else
280         wd = (char *)getwd(s);
281 #endif
282         return wd;
283 }
284
285 /*******************************************************************
286 system wrapper for symlink
287 ********************************************************************/
288
289 int sys_symlink(const char *oldpath, const char *newpath)
290 {
291 #ifndef HAVE_SYMLINK
292         errno = ENOSYS;
293         return -1;
294 #else
295         return symlink(oldpath, newpath);
296 #endif
297 }
298
299 /*******************************************************************
300 system wrapper for readlink
301 ********************************************************************/
302
303 int sys_readlink(const char *path, char *buf, size_t bufsiz)
304 {
305 #ifndef HAVE_READLINK
306         errno = ENOSYS;
307         return -1;
308 #else
309         return readlink(path, buf, bufsiz);
310 #endif
311 }
312
313 /*******************************************************************
314 system wrapper for link
315 ********************************************************************/
316
317 int sys_link(const char *oldpath, const char *newpath)
318 {
319 #ifndef HAVE_LINK
320         errno = ENOSYS;
321         return -1;
322 #else
323         return link(oldpath, newpath);
324 #endif
325 }
326
327 /*******************************************************************
328 chown isn't used much but OS/2 doesn't have it
329 ********************************************************************/
330
331 int sys_chown(const char *fname,uid_t uid,gid_t gid)
332 {
333 #ifndef HAVE_CHOWN
334         static int done;
335         if (!done) {
336                 DEBUG(1,("WARNING: no chown!\n"));
337                 done=1;
338         }
339 #else
340         return(chown(fname,uid,gid));
341 #endif
342 }
343
344 /*******************************************************************
345 os/2 also doesn't have chroot
346 ********************************************************************/
347 int sys_chroot(const char *dname)
348 {
349 #ifndef HAVE_CHROOT
350         static int done;
351         if (!done) {
352                 DEBUG(1,("WARNING: no chroot!\n"));
353                 done=1;
354         }
355         errno = ENOSYS;
356         return -1;
357 #else
358         return(chroot(dname));
359 #endif
360 }
361
362 /**************************************************************************
363 A wrapper for gethostbyname() that tries avoids looking up hostnames 
364 in the root domain, which can cause dial-on-demand links to come up for no
365 apparent reason.
366 ****************************************************************************/
367
368 struct hostent *sys_gethostbyname(const char *name)
369 {
370 #ifdef REDUCE_ROOT_DNS_LOOKUPS
371         char query[256], hostname[256];
372         char *domain;
373
374         /* Does this name have any dots in it? If so, make no change */
375
376         if (strchr_m(name, '.'))
377                 return(gethostbyname(name));
378
379         /* Get my hostname, which should have domain name 
380                 attached. If not, just do the gethostname on the
381                 original string. 
382         */
383
384         gethostname(hostname, sizeof(hostname) - 1);
385         hostname[sizeof(hostname) - 1] = 0;
386         if ((domain = strchr_m(hostname, '.')) == NULL)
387                 return(gethostbyname(name));
388
389         /* Attach domain name to query and do modified query.
390                 If names too large, just do gethostname on the
391                 original string.
392         */
393
394         if((strlen(name) + strlen(domain)) >= sizeof(query))
395                 return(gethostbyname(name));
396
397         slprintf(query, sizeof(query)-1, "%s%s", name, domain);
398         return(gethostbyname(query));
399 #else /* REDUCE_ROOT_DNS_LOOKUPS */
400         return(gethostbyname(name));
401 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
402 }
403
404
405 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
406 /**************************************************************************
407  Try and abstract process capabilities (for systems that have them).
408 ****************************************************************************/
409 static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
410 {
411         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
412                 cap_t cap = cap_get_proc();
413
414                 if (cap == NULL) {
415                         DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
416                                 strerror(errno)));
417                         return False;
418                 }
419
420                 if(enable)
421                         cap->cap_effective |= CAP_NETWORK_MGT;
422                 else
423                         cap->cap_effective &= ~CAP_NETWORK_MGT;
424
425                 if (cap_set_proc(cap) == -1) {
426                         DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
427                                 strerror(errno)));
428                         cap_free(cap);
429                         return False;
430                 }
431
432                 cap_free(cap);
433
434                 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
435         }
436         return True;
437 }
438
439 /**************************************************************************
440  Try and abstract inherited process capabilities (for systems that have them).
441 ****************************************************************************/
442
443 static BOOL set_inherited_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_inherited_process_capability: cap_get_proc failed. Error was %s\n",
450                                 strerror(errno)));
451                         return False;
452                 }
453
454                 if(enable)
455                         cap->cap_inheritable |= CAP_NETWORK_MGT;
456                 else
457                         cap->cap_inheritable &= ~CAP_NETWORK_MGT;
458
459                 if (cap_set_proc(cap) == -1) {
460                         DEBUG(0,("set_inherited_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_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
469         }
470         return True;
471 }
472 #endif
473
474 /****************************************************************************
475  Gain the oplock capability from the kernel if possible.
476 ****************************************************************************/
477
478 void oplock_set_capability(BOOL this_process, BOOL inherit)
479 {
480 #if HAVE_KERNEL_OPLOCKS_IRIX
481         set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
482         set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
483 #endif
484 }
485
486 /**************************************************************************
487  Wrapper for random().
488 ****************************************************************************/
489
490 long sys_random(void)
491 {
492 #if defined(HAVE_RANDOM)
493         return (long)random();
494 #elif defined(HAVE_RAND)
495         return (long)rand();
496 #else
497         DEBUG(0,("Error - no random function available !\n"));
498         exit(1);
499 #endif
500 }
501
502 /**************************************************************************
503  Wrapper for srandom().
504 ****************************************************************************/
505
506 void sys_srandom(unsigned int seed)
507 {
508 #if defined(HAVE_SRANDOM)
509         srandom(seed);
510 #elif defined(HAVE_SRAND)
511         srand(seed);
512 #else
513         DEBUG(0,("Error - no srandom function available !\n"));
514         exit(1);
515 #endif
516 }
517
518 /**************************************************************************
519  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
520 ****************************************************************************/
521
522 int groups_max(void)
523 {
524 #if defined(SYSCONF_SC_NGROUPS_MAX)
525         int ret = sysconf(_SC_NGROUPS_MAX);
526         return (ret == -1) ? NGROUPS_MAX : ret;
527 #else
528         return NGROUPS_MAX;
529 #endif
530 }
531
532 /**************************************************************************
533  Wrapper for getgroups. Deals with broken (int) case.
534 ****************************************************************************/
535
536 int sys_getgroups(int setlen, gid_t *gidset)
537 {
538 #if !defined(HAVE_BROKEN_GETGROUPS)
539         return getgroups(setlen, gidset);
540 #else
541
542         GID_T gid;
543         GID_T *group_list;
544         int i, ngroups;
545
546         if(setlen == 0) {
547                 return getgroups(setlen, &gid);
548         }
549
550         /*
551          * Broken case. We need to allocate a
552          * GID_T array of size setlen.
553          */
554
555         if(setlen < 0) {
556                 errno = EINVAL; 
557                 return -1;
558         } 
559
560         if (setlen == 0)
561                 setlen = groups_max();
562
563         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
564                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
565                 return -1;
566         }
567
568         if((ngroups = getgroups(setlen, group_list)) < 0) {
569                 int saved_errno = errno;
570                 SAFE_FREE(group_list);
571                 errno = saved_errno;
572                 return -1;
573         }
574
575         for(i = 0; i < ngroups; i++)
576                 gidset[i] = (gid_t)group_list[i];
577
578         SAFE_FREE(group_list);
579         return ngroups;
580 #endif /* HAVE_BROKEN_GETGROUPS */
581 }
582
583 #ifdef HAVE_SETGROUPS
584
585 /**************************************************************************
586  Wrapper for setgroups. Deals with broken (int) case. Automatically used
587  if we have broken getgroups.
588 ****************************************************************************/
589
590 int sys_setgroups(int setlen, gid_t *gidset)
591 {
592 #if !defined(HAVE_BROKEN_GETGROUPS)
593         return setgroups(setlen, gidset);
594 #else
595
596         GID_T *group_list;
597         int i ; 
598
599         if (setlen == 0)
600                 return 0 ;
601
602         if (setlen < 0 || setlen > groups_max()) {
603                 errno = EINVAL; 
604                 return -1;   
605         }
606
607         /*
608          * Broken case. We need to allocate a
609          * GID_T array of size setlen.
610          */
611
612         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
613                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
614                 return -1;    
615         }
616  
617         for(i = 0; i < setlen; i++) 
618                 group_list[i] = (GID_T) gidset[i]; 
619
620         if(setgroups(setlen, group_list) != 0) {
621                 int saved_errno = errno;
622                 SAFE_FREE(group_list);
623                 errno = saved_errno;
624                 return -1;
625         }
626  
627         SAFE_FREE(group_list);
628         return 0 ;
629 #endif /* HAVE_BROKEN_GETGROUPS */
630 }
631
632 #endif /* HAVE_SETGROUPS */
633
634 /*
635  * We only wrap pw_name and pw_passwd for now as these
636  * are the only potentially modified fields.
637  */
638
639 /**************************************************************************
640  Helper function for getpwnam/getpwuid wrappers.
641 ****************************************************************************/
642
643 struct saved_pw {
644         fstring         pw_name;
645         fstring         pw_passwd;
646         fstring         pw_gecos;
647         pstring         pw_dir;
648         pstring         pw_shell;
649         struct passwd pass;
650 };
651
652 static struct saved_pw pw_mod; /* This is the structure returned - can be modified. */
653 static struct saved_pw pw_cache; /* This is the structure saved - used to check cache. */
654
655 static int num_lookups; /* Counter so we don't always use cache. */
656 #ifndef PW_RET_CACHE_MAX_LOOKUPS
657 #define PW_RET_CACHE_MAX_LOOKUPS 100
658 #endif
659
660 static void copy_pwent(struct saved_pw *dst, struct passwd *pass)
661 {
662         memcpy((char *)&dst->pass, pass, sizeof(struct passwd));
663
664         fstrcpy(dst->pw_name, pass->pw_name);
665         dst->pass.pw_name = dst->pw_name;
666
667         fstrcpy(dst->pw_passwd, pass->pw_passwd);
668         dst->pass.pw_passwd = dst->pw_passwd;
669
670         fstrcpy(dst->pw_gecos, pass->pw_gecos);
671         dst->pass.pw_gecos = dst->pw_gecos;
672
673         pstrcpy(dst->pw_dir, pass->pw_dir);
674         dst->pass.pw_dir = dst->pw_dir;
675
676         pstrcpy(dst->pw_shell, pass->pw_shell);
677         dst->pass.pw_shell = dst->pw_shell;
678 }
679
680 static struct passwd *setup_pwret(struct passwd *pass)
681 {
682         if (pass == NULL) {
683                 /* Clear the caches. */
684                 memset(&pw_cache, '\0', sizeof(struct saved_pw));
685                 memset(&pw_mod, '\0', sizeof(struct saved_pw));
686                 num_lookups = 0;
687                 return NULL;
688         }
689
690         copy_pwent( &pw_mod, pass);
691
692         if (pass != &pw_cache.pass) {
693
694                 /* If it's a cache miss we must also refill the cache. */
695
696                 copy_pwent( &pw_cache, pass);
697                 num_lookups = 1;
698
699         } else {
700
701                 /* Cache hit. */
702
703                 num_lookups++;
704                 num_lookups = (num_lookups % PW_RET_CACHE_MAX_LOOKUPS);
705         }
706
707         return &pw_mod.pass;
708 }
709
710 /**************************************************************************
711  Wrappers for setpwent(), getpwent() and endpwent()
712 ****************************************************************************/
713
714 void sys_setpwent(void)
715 {
716         setup_pwret(NULL); /* Clear cache. */
717         setpwent();
718 }
719
720 struct passwd *sys_getpwent(void)
721 {
722         return setup_pwret(getpwent());
723 }
724
725 void sys_endpwent(void)
726 {
727         setup_pwret(NULL); /* Clear cache. */
728         endpwent();
729 }
730
731 /**************************************************************************
732  Wrapper for getpwnam(). Always returns a static that can be modified.
733 ****************************************************************************/
734
735 struct passwd *sys_getpwnam(const char *name)
736 {
737         if (!name || !name[0])
738                 return NULL;
739
740         /* check for a cache hit first */
741         if (num_lookups && pw_cache.pass.pw_name && !strcmp(name, pw_cache.pass.pw_name)) {
742                 return setup_pwret(&pw_cache.pass);
743         }
744
745         return setup_pwret(getpwnam(name));
746 }
747
748 /**************************************************************************
749  Wrapper for getpwuid(). Always returns a static that can be modified.
750 ****************************************************************************/
751
752 struct passwd *sys_getpwuid(uid_t uid)
753 {
754         if (num_lookups && pw_cache.pass.pw_name && (uid == pw_cache.pass.pw_uid)) {
755                 return setup_pwret(&pw_cache.pass);
756         }
757         
758         return setup_pwret(getpwuid(uid));
759 }
760
761 #if 0 /* NOT CURRENTLY USED - JRA */
762 /**************************************************************************
763  The following are the UNICODE versions of *all* system interface functions
764  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
765  which currently are left as ascii as they are not used other than in name
766  resolution.
767 ****************************************************************************/
768
769 /**************************************************************************
770  Wide stat. Just narrow and call sys_xxx.
771 ****************************************************************************/
772
773 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
774 {
775         pstring fname;
776         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
777 }
778
779 /**************************************************************************
780  Wide lstat. Just narrow and call sys_xxx.
781 ****************************************************************************/
782
783 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
784 {
785         pstring fname;
786         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
787 }
788
789 /**************************************************************************
790  Wide creat. Just narrow and call sys_xxx.
791 ****************************************************************************/
792
793 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
794 {
795         pstring fname;
796         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
797 }
798
799 /**************************************************************************
800  Wide open. Just narrow and call sys_xxx.
801 ****************************************************************************/
802
803 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
804 {
805         pstring fname;
806         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
807 }
808
809 /**************************************************************************
810  Wide fopen. Just narrow and call sys_xxx.
811 ****************************************************************************/
812
813 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
814 {
815         pstring fname;
816         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
817 }
818
819 /**************************************************************************
820  Wide opendir. Just narrow and call sys_xxx.
821 ****************************************************************************/
822
823 DIR *wsys_opendir(const smb_ucs2_t *wfname)
824 {
825         pstring fname;
826         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
827 }
828
829 /**************************************************************************
830  Wide readdir. Return a structure pointer containing a wide filename.
831 ****************************************************************************/
832
833 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
834 {
835         static SMB_STRUCT_WDIRENT retval;
836         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
837
838         if(!dirval)
839                 return NULL;
840
841         /*
842          * The only POSIX defined member of this struct is d_name.
843          */
844
845         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
846
847         return &retval;
848 }
849
850 /**************************************************************************
851  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
852 ****************************************************************************/
853
854 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
855 {
856         pstring fname;
857         char *p = sys_getwd(fname);
858
859         if(!p)
860                 return NULL;
861
862         return unix_to_unicode(s, p, sizeof(wpstring));
863 }
864
865 /**************************************************************************
866  Wide chown. Just narrow and call sys_xxx.
867 ****************************************************************************/
868
869 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
870 {
871         pstring fname;
872         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
873 }
874
875 /**************************************************************************
876  Wide chroot. Just narrow and call sys_xxx.
877 ****************************************************************************/
878
879 int wsys_chroot(const smb_ucs2_t *wfname)
880 {
881         pstring fname;
882         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
883 }
884
885 /**************************************************************************
886  Wide getpwnam. Return a structure pointer containing wide names.
887 ****************************************************************************/
888
889 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
890 {
891         static SMB_STRUCT_WPASSWD retval;
892         fstring name;
893         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
894
895         if(!pwret)
896                 return NULL;
897
898         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
899         retval.pw_passwd = pwret->pw_passwd;
900         retval.pw_uid = pwret->pw_uid;
901         retval.pw_gid = pwret->pw_gid;
902         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
903         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
904         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
905
906         return &retval;
907 }
908
909 /**************************************************************************
910  Wide getpwuid. Return a structure pointer containing wide names.
911 ****************************************************************************/
912
913 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
914 {
915         static SMB_STRUCT_WPASSWD retval;
916         struct passwd *pwret = sys_getpwuid(uid);
917
918         if(!pwret)
919                 return NULL;
920
921         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
922         retval.pw_passwd = pwret->pw_passwd;
923         retval.pw_uid = pwret->pw_uid;
924         retval.pw_gid = pwret->pw_gid;
925         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
926         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
927         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
928
929         return &retval;
930 }
931 #endif /* NOT CURRENTLY USED - JRA */
932
933 /**************************************************************************
934  Extract a command into an arg list. Uses a static pstring for storage.
935  Caller frees returned arg list (which contains pointers into the static pstring).
936 ****************************************************************************/
937
938 static char **extract_args(const char *command)
939 {
940         static pstring trunc_cmd;
941         char *ptr;
942         int argcl;
943         char **argl = NULL;
944         int i;
945
946         pstrcpy(trunc_cmd, command);
947
948         if(!(ptr = strtok(trunc_cmd, " \t"))) {
949                 errno = EINVAL;
950                 return NULL;
951         }
952
953         /*
954          * Count the args.
955          */
956
957         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
958                 argcl++;
959
960         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
961                 return NULL;
962
963         /*
964          * Now do the extraction.
965          */
966
967         pstrcpy(trunc_cmd, command);
968
969         ptr = strtok(trunc_cmd, " \t");
970         i = 0;
971         argl[i++] = ptr;
972
973         while((ptr = strtok(NULL, " \t")) != NULL)
974                 argl[i++] = ptr;
975
976         argl[i++] = NULL;
977         return argl;
978 }
979
980 /**************************************************************************
981  Wrapper for fork. Ensures that mypid is reset. Used so we can write
982  a sys_getpid() that only does a system call *once*.
983 ****************************************************************************/
984
985 static pid_t mypid = (pid_t)-1;
986
987 pid_t sys_fork(void)
988 {
989         pid_t forkret = fork();
990
991         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
992                 mypid = (pid_t) -1;
993
994         return forkret;
995 }
996
997 /**************************************************************************
998  Wrapper for getpid. Ensures we only do a system call *once*.
999 ****************************************************************************/
1000
1001 pid_t sys_getpid(void)
1002 {
1003         if (mypid == (pid_t)-1)
1004                 mypid = getpid();
1005
1006         return mypid;
1007 }
1008
1009 /**************************************************************************
1010  Wrapper for popen. Safer as it doesn't search a path.
1011  Modified from the glibc sources.
1012  modified by tridge to return a file descriptor. We must kick our FILE* habit
1013 ****************************************************************************/
1014
1015 typedef struct _popen_list
1016 {
1017         int fd;
1018         pid_t child_pid;
1019         struct _popen_list *next;
1020 } popen_list;
1021
1022 static popen_list *popen_chain;
1023
1024 int sys_popen(const char *command)
1025 {
1026         int parent_end, child_end;
1027         int pipe_fds[2];
1028         popen_list *entry = NULL;
1029         char **argl = NULL;
1030
1031         if (pipe(pipe_fds) < 0)
1032                 return -1;
1033
1034         parent_end = pipe_fds[0];
1035         child_end = pipe_fds[1];
1036
1037         if (!*command) {
1038                 errno = EINVAL;
1039                 goto err_exit;
1040         }
1041
1042         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
1043                 goto err_exit;
1044
1045         ZERO_STRUCTP(entry);
1046
1047         /*
1048          * Extract the command and args into a NULL terminated array.
1049          */
1050
1051         if(!(argl = extract_args(command)))
1052                 goto err_exit;
1053
1054         entry->child_pid = sys_fork();
1055
1056         if (entry->child_pid == -1) {
1057                 goto err_exit;
1058         }
1059
1060         if (entry->child_pid == 0) {
1061
1062                 /*
1063                  * Child !
1064                  */
1065
1066                 int child_std_end = STDOUT_FILENO;
1067                 popen_list *p;
1068
1069                 close(parent_end);
1070                 if (child_end != child_std_end) {
1071                         dup2 (child_end, child_std_end);
1072                         close (child_end);
1073                 }
1074
1075                 /*
1076                  * POSIX.2:  "popen() shall ensure that any streams from previous
1077                  * popen() calls that remain open in the parent process are closed
1078                  * in the new child process."
1079                  */
1080
1081                 for (p = popen_chain; p; p = p->next)
1082                         close(p->fd);
1083
1084                 execv(argl[0], argl);
1085                 _exit (127);
1086         }
1087
1088         /*
1089          * Parent.
1090          */
1091
1092         close (child_end);
1093         SAFE_FREE(argl);
1094
1095         /* Link into popen_chain. */
1096         entry->next = popen_chain;
1097         popen_chain = entry;
1098         entry->fd = parent_end;
1099
1100         return entry->fd;
1101
1102 err_exit:
1103
1104         SAFE_FREE(entry);
1105         SAFE_FREE(argl);
1106         close(pipe_fds[0]);
1107         close(pipe_fds[1]);
1108         return -1;
1109 }
1110
1111 /**************************************************************************
1112  Wrapper for pclose. Modified from the glibc sources.
1113 ****************************************************************************/
1114
1115 int sys_pclose(int fd)
1116 {
1117         int wstatus;
1118         popen_list **ptr = &popen_chain;
1119         popen_list *entry = NULL;
1120         pid_t wait_pid;
1121         int status = -1;
1122
1123         /* Unlink from popen_chain. */
1124         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1125                 if ((*ptr)->fd == fd) {
1126                         entry = *ptr;
1127                         *ptr = (*ptr)->next;
1128                         status = 0;
1129                         break;
1130                 }
1131         }
1132
1133         if (status < 0 || close(entry->fd) < 0)
1134                 return -1;
1135
1136         /*
1137          * As Samba is catching and eating child process
1138          * exits we don't really care about the child exit
1139          * code, a -1 with errno = ECHILD will do fine for us.
1140          */
1141
1142         do {
1143                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1144         } while (wait_pid == -1 && errno == EINTR);
1145
1146         SAFE_FREE(entry);
1147
1148         if (wait_pid == -1)
1149                 return -1;
1150         return wstatus;
1151 }
1152
1153 /**************************************************************************
1154  Wrappers for dlopen, dlsym, dlclose.
1155 ****************************************************************************/
1156
1157 void *sys_dlopen(const char *name, int flags)
1158 {
1159 #ifdef HAVE_LIBDL
1160         return dlopen(name, flags);
1161 #else
1162         return NULL;
1163 #endif
1164 }
1165
1166 void *sys_dlsym(void *handle, char *symbol)
1167 {
1168 #ifdef HAVE_LIBDL
1169     return dlsym(handle, symbol);
1170 #else
1171     return NULL;
1172 #endif
1173 }
1174
1175 int sys_dlclose (void *handle)
1176 {
1177 #ifdef HAVE_LIBDL
1178         return dlclose(handle);
1179 #else
1180         return 0;
1181 #endif
1182 }
1183
1184 const char *sys_dlerror(void)
1185 {
1186 #ifdef HAVE_LIBDL
1187         return dlerror();
1188 #else
1189         return NULL;
1190 #endif
1191 }