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