merge from 2.2
[Samba/gbeck.git] / source / lib / system.c
blob0c627b2f659983ae9af53af323dbb7a372d75a91
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Samba system utilities
5 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
22 #include "includes.h"
24 extern int DEBUGLEVEL;
27 The idea is that this file will eventually have wrappers around all
28 important system calls in samba. The aims are:
30 - to enable easier porting by putting OS dependent stuff in here
32 - to allow for hooks into other "pseudo-filesystems"
34 - to allow easier integration of things like the japanese extensions
36 - to support the philosophy of Samba to expose the features of
37 the OS within the SMB model. In general whatever file/printer/variable
38 expansions/etc make sense to the OS should be acceptable to Samba.
43 /*******************************************************************
44 A wrapper for usleep in case we don't have one.
45 ********************************************************************/
47 int sys_usleep(long usecs)
49 #ifndef HAVE_USLEEP
50 struct timeval tval;
51 #endif
54 * We need this braindamage as the glibc usleep
55 * is not SPEC1170 complient... grumble... JRA.
58 if(usecs < 0 || usecs > 1000000) {
59 errno = EINVAL;
60 return -1;
63 #if HAVE_USLEEP
64 usleep(usecs);
65 return 0;
66 #else /* HAVE_USLEEP */
68 * Fake it with select...
70 tval.tv_sec = 0;
71 tval.tv_usec = usecs/1000;
72 select(0,NULL,NULL,NULL,&tval);
73 return 0;
74 #endif /* HAVE_USLEEP */
77 /*******************************************************************
78 A stat() wrapper that will deal with 64 bit filesizes.
79 ********************************************************************/
81 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
83 int ret;
84 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
85 ret = stat64(fname, sbuf);
86 #else
87 ret = stat(fname, sbuf);
88 #endif
89 /* we always want directories to appear zero size */
90 if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
91 return ret;
94 /*******************************************************************
95 An fstat() wrapper that will deal with 64 bit filesizes.
96 ********************************************************************/
98 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
100 int ret;
101 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
102 ret = fstat64(fd, sbuf);
103 #else
104 ret = fstat(fd, sbuf);
105 #endif
106 /* we always want directories to appear zero size */
107 if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
108 return ret;
111 /*******************************************************************
112 An lstat() wrapper that will deal with 64 bit filesizes.
113 ********************************************************************/
115 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
117 int ret;
118 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
119 ret = lstat64(fname, sbuf);
120 #else
121 ret = lstat(fname, sbuf);
122 #endif
123 /* we always want directories to appear zero size */
124 if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
125 return ret;
128 /*******************************************************************
129 An ftruncate() wrapper that will deal with 64 bit filesizes.
130 ********************************************************************/
132 int sys_ftruncate(int fd, SMB_OFF_T offset)
134 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
135 return ftruncate64(fd, offset);
136 #else
137 return ftruncate(fd, offset);
138 #endif
141 /*******************************************************************
142 An lseek() wrapper that will deal with 64 bit filesizes.
143 ********************************************************************/
145 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
147 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
148 return lseek64(fd, offset, whence);
149 #else
150 return lseek(fd, offset, whence);
151 #endif
154 /*******************************************************************
155 An fseek() wrapper that will deal with 64 bit filesizes.
156 ********************************************************************/
158 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
160 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
161 return fseek64(fp, offset, whence);
162 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
163 return fseeko64(fp, offset, whence);
164 #else
165 return fseek(fp, offset, whence);
166 #endif
169 /*******************************************************************
170 An ftell() wrapper that will deal with 64 bit filesizes.
171 ********************************************************************/
173 SMB_OFF_T sys_ftell(FILE *fp)
175 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
176 return (SMB_OFF_T)ftell64(fp);
177 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
178 return (SMB_OFF_T)ftello64(fp);
179 #else
180 return (SMB_OFF_T)ftell(fp);
181 #endif
184 /*******************************************************************
185 A creat() wrapper that will deal with 64 bit filesizes.
186 ********************************************************************/
188 int sys_creat(const char *path, mode_t mode)
190 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
191 return creat64(path, mode);
192 #else
194 * If creat64 isn't defined then ensure we call a potential open64.
195 * JRA.
197 return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
198 #endif
201 /*******************************************************************
202 An open() wrapper that will deal with 64 bit filesizes.
203 ********************************************************************/
205 int sys_open(const char *path, int oflag, mode_t mode)
207 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
208 return open64(path, oflag, mode);
209 #else
210 return open(path, oflag, mode);
211 #endif
214 /*******************************************************************
215 An fopen() wrapper that will deal with 64 bit filesizes.
216 ********************************************************************/
218 FILE *sys_fopen(const char *path, const char *type)
220 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
221 return fopen64(path, type);
222 #else
223 return fopen(path, type);
224 #endif
227 /*******************************************************************
228 A readdir wrapper that will deal with 64 bit filesizes.
229 ********************************************************************/
231 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
233 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
234 return readdir64(dirp);
235 #else
236 return readdir(dirp);
237 #endif
240 /*******************************************************************
241 The wait() calls vary between systems
242 ********************************************************************/
244 int sys_waitpid(pid_t pid,int *status,int options)
246 #ifdef HAVE_WAITPID
247 return waitpid(pid,status,options);
248 #else /* HAVE_WAITPID */
249 return wait4(pid, status, options, NULL);
250 #endif /* HAVE_WAITPID */
253 /*******************************************************************
254 system wrapper for getwd
255 ********************************************************************/
256 char *sys_getwd(char *s)
258 char *wd;
259 #ifdef HAVE_GETCWD
260 wd = (char *)getcwd(s, sizeof (pstring));
261 #else
262 wd = (char *)getwd(s);
263 #endif
264 return wd;
267 /*******************************************************************
268 chown isn't used much but OS/2 doesn't have it
269 ********************************************************************/
271 int sys_chown(const char *fname,uid_t uid,gid_t gid)
273 #ifndef HAVE_CHOWN
274 static int done;
275 if (!done) {
276 DEBUG(1,("WARNING: no chown!\n"));
277 done=1;
279 #else
280 return(chown(fname,uid,gid));
281 #endif
284 /*******************************************************************
285 os/2 also doesn't have chroot
286 ********************************************************************/
287 int sys_chroot(const char *dname)
289 #ifndef HAVE_CHROOT
290 static int done;
291 if (!done) {
292 DEBUG(1,("WARNING: no chroot!\n"));
293 done=1;
295 errno = ENOSYS;
296 return -1;
297 #else
298 return(chroot(dname));
299 #endif
302 /**************************************************************************
303 A wrapper for gethostbyname() that tries avoids looking up hostnames
304 in the root domain, which can cause dial-on-demand links to come up for no
305 apparent reason.
306 ****************************************************************************/
307 struct hostent *sys_gethostbyname(const char *name)
309 #ifdef REDUCE_ROOT_DNS_LOOKUPS
310 char query[256], hostname[256];
311 char *domain;
313 /* Does this name have any dots in it? If so, make no change */
315 if (strchr(name, '.'))
316 return(gethostbyname(name));
318 /* Get my hostname, which should have domain name
319 attached. If not, just do the gethostname on the
320 original string.
323 gethostname(hostname, sizeof(hostname) - 1);
324 hostname[sizeof(hostname) - 1] = 0;
325 if ((domain = strchr(hostname, '.')) == NULL)
326 return(gethostbyname(name));
328 /* Attach domain name to query and do modified query.
329 If names too large, just do gethostname on the
330 original string.
333 if((strlen(name) + strlen(domain)) >= sizeof(query))
334 return(gethostbyname(name));
336 slprintf(query, sizeof(query)-1, "%s%s", name, domain);
337 return(gethostbyname(query));
338 #else /* REDUCE_ROOT_DNS_LOOKUPS */
339 return(gethostbyname(name));
340 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
344 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
345 /**************************************************************************
346 Try and abstract process capabilities (for systems that have them).
347 ****************************************************************************/
348 static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
350 if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
352 cap_t cap = cap_get_proc();
354 if (cap == NULL) {
355 DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
356 strerror(errno)));
357 return False;
360 if(enable)
361 cap->cap_effective |= CAP_NETWORK_MGT;
362 else
363 cap->cap_effective &= ~CAP_NETWORK_MGT;
365 if (cap_set_proc(cap) == -1) {
366 DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
367 strerror(errno)));
368 cap_free(cap);
369 return False;
372 cap_free(cap);
374 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
376 return True;
379 /**************************************************************************
380 Try and abstract inherited process capabilities (for systems that have them).
381 ****************************************************************************/
383 static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
385 if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
387 cap_t cap = cap_get_proc();
389 if (cap == NULL) {
390 DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
391 strerror(errno)));
392 return False;
395 if(enable)
396 cap->cap_inheritable |= CAP_NETWORK_MGT;
397 else
398 cap->cap_inheritable &= ~CAP_NETWORK_MGT;
400 if (cap_set_proc(cap) == -1) {
401 DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n",
402 strerror(errno)));
403 cap_free(cap);
404 return False;
407 cap_free(cap);
409 DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
411 return True;
413 #endif
415 /****************************************************************************
416 gain the oplock capability from the kernel if possible
417 ****************************************************************************/
418 void oplock_set_capability(BOOL this_process, BOOL inherit)
420 #if HAVE_KERNEL_OPLOCKS_IRIX
421 set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
422 set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
423 #endif
426 /**************************************************************************
427 Wrapper for random().
428 ****************************************************************************/
430 long sys_random(void)
432 #if defined(HAVE_RANDOM)
433 return (long)random();
434 #elif defined(HAVE_RAND)
435 return (long)rand();
436 #else
437 DEBUG(0,("Error - no random function available !\n"));
438 exit(1);
439 #endif
442 /**************************************************************************
443 Wrapper for srandom().
444 ****************************************************************************/
446 void sys_srandom(unsigned int seed)
448 #if defined(HAVE_SRANDOM)
449 srandom(seed);
450 #elif defined(HAVE_SRAND)
451 srand(seed);
452 #else
453 DEBUG(0,("Error - no srandom function available !\n"));
454 exit(1);
455 #endif
458 /**************************************************************************
459 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
460 ****************************************************************************/
462 int groups_max(void)
464 #if defined(SYSCONF_SC_NGROUPS_MAX)
465 int ret = sysconf(_SC_NGROUPS_MAX);
466 return (ret == -1) ? NGROUPS_MAX : ret;
467 #else
468 return NGROUPS_MAX;
469 #endif
472 /**************************************************************************
473 Wrapper for getgroups. Deals with broken (int) case.
474 ****************************************************************************/
476 int sys_getgroups(int setlen, gid_t *gidset)
478 #if !defined(HAVE_BROKEN_GETGROUPS)
479 return getgroups(setlen, gidset);
480 #else
482 GID_T gid;
483 GID_T *group_list;
484 int i, ngroups;
486 if(setlen == 0) {
487 return getgroups(setlen, &gid);
491 * Broken case. We need to allocate a
492 * GID_T array of size setlen.
495 if(setlen < 0) {
496 errno = EINVAL;
497 return -1;
500 if (setlen == 0)
501 setlen = groups_max();
503 if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
504 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
505 return -1;
508 if((ngroups = getgroups(setlen, group_list)) < 0) {
509 int saved_errno = errno;
510 free((char *)group_list);
511 errno = saved_errno;
512 return -1;
515 for(i = 0; i < ngroups; i++)
516 gidset[i] = (gid_t)group_list[i];
518 free((char *)group_list);
519 return ngroups;
520 #endif /* HAVE_BROKEN_GETGROUPS */
523 #ifdef HAVE_SETGROUPS
525 /**************************************************************************
526 Wrapper for setgroups. Deals with broken (int) case. Automatically used
527 if we have broken getgroups.
528 ****************************************************************************/
530 int sys_setgroups(int setlen, gid_t *gidset)
532 #if !defined(HAVE_BROKEN_GETGROUPS)
533 return setgroups(setlen, gidset);
534 #else
536 GID_T *group_list;
537 int i ;
539 if (setlen == 0)
540 return 0 ;
542 if (setlen < 0 || setlen > groups_max()) {
543 errno = EINVAL;
544 return -1;
548 * Broken case. We need to allocate a
549 * GID_T array of size setlen.
552 if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
553 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
554 return -1;
557 for(i = 0; i < setlen; i++)
558 group_list[i] = (GID_T) gidset[i];
560 if(setgroups(setlen, group_list) != 0) {
561 int saved_errno = errno;
562 free((char *)group_list);
563 errno = saved_errno;
564 return -1;
567 free((char *)group_list);
568 return 0 ;
569 #endif /* HAVE_BROKEN_GETGROUPS */
572 #endif /* HAVE_SETGROUPS */
575 * We only wrap pw_name and pw_passwd for now as these
576 * are the only potentially modified fields.
579 /**************************************************************************
580 Helper function for getpwnam/getpwuid wrappers.
581 ****************************************************************************/
583 struct saved_pw {
584 fstring pw_name;
585 fstring pw_passwd;
586 struct passwd pass;
589 static struct saved_pw pw_mod; /* This is the structure returned - can be modified. */
590 static struct saved_pw pw_cache; /* This is the structure saved - used to check cache. */
592 static int num_lookups; /* Counter so we don't always use cache. */
593 #ifndef PW_RET_CACHE_MAX_LOOKUPS
594 #define PW_RET_CACHE_MAX_LOOKUPS 100
595 #endif
597 static struct passwd *setup_pwret(struct passwd *pass)
599 if (pass == NULL) {
600 /* Clear the caches. */
601 memset(&pw_cache, '\0', sizeof(struct saved_pw));
602 memset(&pw_mod, '\0', sizeof(struct saved_pw));
603 num_lookups = 0;
604 return NULL;
607 /* this gets the uid, gid and null pointers */
609 memcpy((char *)&pw_mod.pass, pass, sizeof(struct passwd));
610 fstrcpy(pw_mod.pw_name, pass->pw_name);
611 pw_mod.pass.pw_name = pw_mod.pw_name;
612 fstrcpy(pw_mod.pw_passwd, pass->pw_passwd);
613 pw_mod.pass.pw_passwd = pw_mod.pw_passwd;
616 if (pass != &pw_cache.pass) {
618 /* If it's a cache miss we must also refill the cache. */
620 memcpy((char *)&pw_cache.pass, pass, sizeof(struct passwd));
621 fstrcpy(pw_cache.pw_name, pass->pw_name);
622 pw_cache.pass.pw_name = pw_cache.pw_name;
623 fstrcpy(pw_cache.pw_passwd, pass->pw_passwd);
624 pw_cache.pass.pw_passwd = pw_cache.pw_passwd;
626 num_lookups = 1;
628 } else {
630 /* Cache hit. */
632 num_lookups++;
633 num_lookups = (num_lookups % PW_RET_CACHE_MAX_LOOKUPS);
636 return &pw_mod.pass;
639 /**************************************************************************
640 Wrappers for setpwent(), getpwent() and endpwent()
641 ****************************************************************************/
643 void sys_setpwent(void)
645 setup_pwret(NULL); /* Clear cache. */
646 setpwent();
649 struct passwd *sys_getpwent(void)
651 return setup_pwret(getpwent());
654 void sys_endpwent(void)
656 setup_pwret(NULL); /* Clear cache. */
657 endpwent();
660 /**************************************************************************
661 Wrapper for getpwnam(). Always returns a static that can be modified.
662 ****************************************************************************/
664 struct passwd *sys_getpwnam(const char *name)
666 if (!name || !name[0])
667 return NULL;
669 /* check for a cache hit first */
670 if (num_lookups && pw_cache.pass.pw_name && !strcmp(name, pw_cache.pass.pw_name)) {
671 return setup_pwret(&pw_cache.pass);
674 return setup_pwret(getpwnam(name));
677 /**************************************************************************
678 Wrapper for getpwuid(). Always returns a static that can be modified.
679 ****************************************************************************/
681 struct passwd *sys_getpwuid(uid_t uid)
683 if (num_lookups && pw_cache.pass.pw_name && (uid == pw_cache.pass.pw_uid)) {
684 return setup_pwret(&pw_cache.pass);
687 return setup_pwret(getpwuid(uid));
690 /**************************************************************************
691 The following are the UNICODE versions of *all* system interface functions
692 called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
693 which currently are left as ascii as they are not used other than in name
694 resolution.
695 ****************************************************************************/
697 /**************************************************************************
698 Wide stat. Just narrow and call sys_xxx.
699 ****************************************************************************/
701 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
703 pstring fname;
704 return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
707 /**************************************************************************
708 Wide lstat. Just narrow and call sys_xxx.
709 ****************************************************************************/
711 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
713 pstring fname;
714 return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
717 /**************************************************************************
718 Wide creat. Just narrow and call sys_xxx.
719 ****************************************************************************/
721 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
723 pstring fname;
724 return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
727 /**************************************************************************
728 Wide open. Just narrow and call sys_xxx.
729 ****************************************************************************/
731 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
733 pstring fname;
734 return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
737 /**************************************************************************
738 Wide fopen. Just narrow and call sys_xxx.
739 ****************************************************************************/
741 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
743 pstring fname;
744 return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
747 /**************************************************************************
748 Wide opendir. Just narrow and call sys_xxx.
749 ****************************************************************************/
751 DIR *wsys_opendir(const smb_ucs2_t *wfname)
753 pstring fname;
754 return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
757 /**************************************************************************
758 Wide readdir. Return a structure pointer containing a wide filename.
759 ****************************************************************************/
761 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
763 static SMB_STRUCT_WDIRENT retval;
764 SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
766 if(!dirval)
767 return NULL;
770 * The only POSIX defined member of this struct is d_name.
773 unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
775 return &retval;
778 /**************************************************************************
779 Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
780 ****************************************************************************/
782 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
784 pstring fname;
785 char *p = sys_getwd(fname);
787 if(!p)
788 return NULL;
790 return unix_to_unicode(s, p, sizeof(wpstring));
793 /**************************************************************************
794 Wide chown. Just narrow and call sys_xxx.
795 ****************************************************************************/
797 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
799 pstring fname;
800 return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
803 /**************************************************************************
804 Wide chroot. Just narrow and call sys_xxx.
805 ****************************************************************************/
807 int wsys_chroot(const smb_ucs2_t *wfname)
809 pstring fname;
810 return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
813 /**************************************************************************
814 Wide getpwnam. Return a structure pointer containing wide names.
815 ****************************************************************************/
817 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
819 static SMB_STRUCT_WPASSWD retval;
820 fstring name;
821 struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
823 if(!pwret)
824 return NULL;
826 unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
827 retval.pw_passwd = pwret->pw_passwd;
828 retval.pw_uid = pwret->pw_uid;
829 retval.pw_gid = pwret->pw_gid;
830 unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
831 unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
832 unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
834 return &retval;
837 /**************************************************************************
838 Wide getpwuid. Return a structure pointer containing wide names.
839 ****************************************************************************/
841 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
843 static SMB_STRUCT_WPASSWD retval;
844 struct passwd *pwret = sys_getpwuid(uid);
846 if(!pwret)
847 return NULL;
849 unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
850 retval.pw_passwd = pwret->pw_passwd;
851 retval.pw_uid = pwret->pw_uid;
852 retval.pw_gid = pwret->pw_gid;
853 unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
854 unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
855 unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
857 return &retval;
860 /**************************************************************************
861 Extract a command into an arg list. Uses a static pstring for storage.
862 Caller frees returned arg list (which contains pointers into the static pstring).
863 ****************************************************************************/
865 static char **extract_args(const char *command)
867 static pstring trunc_cmd;
868 char *ptr;
869 int argcl;
870 char **argl = NULL;
871 int i;
873 pstrcpy(trunc_cmd, command);
875 if(!(ptr = strtok(trunc_cmd, " \t"))) {
876 errno = EINVAL;
877 return NULL;
881 * Count the args.
884 for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
885 argcl++;
887 if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
888 return NULL;
891 * Now do the extraction.
894 pstrcpy(trunc_cmd, command);
896 ptr = strtok(trunc_cmd, " \t");
897 i = 0;
898 argl[i++] = ptr;
900 while((ptr = strtok(NULL, " \t")) != NULL)
901 argl[i++] = ptr;
903 argl[i++] = NULL;
904 return argl;
907 /**************************************************************************
908 Wrapper for fork. Ensures that mypid is reset. Used so we can write
909 a sys_getpid() that only does a system call *once*.
910 ****************************************************************************/
912 static pid_t mypid = (pid_t)-1;
914 pid_t sys_fork(void)
916 pid_t forkret = fork();
918 if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
919 mypid = (pid_t) -1;
921 return forkret;
924 /**************************************************************************
925 Wrapper for getpid. Ensures we only do a system call *once*.
926 ****************************************************************************/
928 pid_t sys_getpid(void)
930 if (mypid == (pid_t)-1)
931 mypid = getpid();
933 return mypid;
936 /**************************************************************************
937 Wrapper for popen. Safer as it doesn't search a path.
938 Modified from the glibc sources.
939 modified by tridge to return a file descriptor. We must kick our FILE* habit
940 ****************************************************************************/
942 typedef struct _popen_list
944 int fd;
945 pid_t child_pid;
946 struct _popen_list *next;
947 } popen_list;
949 static popen_list *popen_chain;
951 int sys_popen(const char *command)
953 int parent_end, child_end;
954 int pipe_fds[2];
955 popen_list *entry = NULL;
956 char **argl = NULL;
958 if (pipe(pipe_fds) < 0)
959 return -1;
961 parent_end = pipe_fds[0];
962 child_end = pipe_fds[1];
964 if (!*command) {
965 errno = EINVAL;
966 goto err_exit;
969 if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
970 goto err_exit;
972 ZERO_STRUCTP(entry);
975 * Extract the command and args into a NULL terminated array.
978 if(!(argl = extract_args(command)))
979 goto err_exit;
981 entry->child_pid = sys_fork();
983 if (entry->child_pid == -1) {
984 goto err_exit;
987 if (entry->child_pid == 0) {
990 * Child !
993 int child_std_end = STDOUT_FILENO;
994 popen_list *p;
996 close(parent_end);
997 if (child_end != child_std_end) {
998 dup2 (child_end, child_std_end);
999 close (child_end);
1003 * POSIX.2: "popen() shall ensure that any streams from previous
1004 * popen() calls that remain open in the parent process are closed
1005 * in the new child process."
1008 for (p = popen_chain; p; p = p->next)
1009 close(p->fd);
1011 execv(argl[0], argl);
1012 _exit (127);
1016 * Parent.
1019 close (child_end);
1020 free((char *)argl);
1022 /* Link into popen_chain. */
1023 entry->next = popen_chain;
1024 popen_chain = entry;
1025 entry->fd = parent_end;
1027 return entry->fd;
1029 err_exit:
1031 if(entry)
1032 free((char *)entry);
1033 if(argl)
1034 free((char *)argl);
1035 close(pipe_fds[0]);
1036 close(pipe_fds[1]);
1037 return -1;
1040 /**************************************************************************
1041 Wrapper for pclose. Modified from the glibc sources.
1042 ****************************************************************************/
1043 int sys_pclose(int fd)
1045 int wstatus;
1046 popen_list **ptr = &popen_chain;
1047 popen_list *entry = NULL;
1048 pid_t wait_pid;
1049 int status = -1;
1051 /* Unlink from popen_chain. */
1052 for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1053 if ((*ptr)->fd == fd) {
1054 entry = *ptr;
1055 *ptr = (*ptr)->next;
1056 status = 0;
1057 break;
1061 if (status < 0 || close(entry->fd) < 0)
1062 return -1;
1065 * As Samba is catching and eating child process
1066 * exits we don't really care about the child exit
1067 * code, a -1 with errno = ECHILD will do fine for us.
1070 do {
1071 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1072 } while (wait_pid == -1 && errno == EINTR);
1074 free((char *)entry);
1076 if (wait_pid == -1)
1077 return -1;
1078 return wstatus;
1081 /**************************************************************************
1082 Wrappers for dlopen, dlsym, dlclose.
1083 ****************************************************************************/
1085 void *sys_dlopen(const char *name, int flags)
1087 #ifdef HAVE_LIBDL
1088 return dlopen(name, flags);
1089 #else
1090 return NULL;
1091 #endif
1094 void *sys_dlsym(void *handle, char *symbol)
1096 #ifdef HAVE_LIBDL
1097 return dlsym(handle, symbol);
1098 #else
1099 return NULL;
1100 #endif
1103 int sys_dlclose (void *handle)
1105 #ifdef HAVE_LIBDL
1106 return dlclose(handle);
1107 #else
1108 return 0;
1109 #endif