2 Unix SMB/Netbios implementation.
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.
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.
42 /*******************************************************************
43 this replaces the normal select() system call
44 return if some data has arrived on one of the file descriptors
46 ********************************************************************/
48 static int pollfd(int fd)
54 #elif defined(TCRDCHK)
55 (void)ioctl(fd, TCRDCHK, &r);
57 (void)ioctl(fd, FIONREAD, &r);
63 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
74 for (i=0;i<maxfd;i++) {
75 if (FD_ISSET(i,fds) && pollfd(i)>0) {
82 memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
86 if (tval && tval->tv_sec < counter) return(0);
92 #else /* !NO_SELECT */
93 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
96 struct pollfd pfd[256];
103 for( i = 0; i < maxfd; i++) {
104 if(FD_ISSET(i,fds)) {
105 struct pollfd *pfdp = &pfd[maxpoll++];
107 pfdp->events = POLLIN;
112 timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
116 pollrtn = poll( &pfd[0], maxpoll, timeout);
117 } while (pollrtn<0 && errno == EINTR);
121 for( i = 0; i < maxpoll; i++)
122 if( pfd[i].revents & POLLIN )
123 FD_SET(pfd[i].fd,fds);
132 if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
134 selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
135 } while (selrtn<0 && errno == EINTR);
139 #endif /* USE_POLL */
140 #endif /* NO_SELECT */
142 /*******************************************************************
143 A wrapper for usleep in case we don't have one.
144 ********************************************************************/
146 int sys_usleep(long usecs)
153 * We need this braindamage as the glibc usleep
154 * is not SPEC1170 complient... grumble... JRA.
157 if(usecs < 0 || usecs > 1000000) {
165 #else /* HAVE_USLEEP */
167 * Fake it with select...
170 tval.tv_usec = usecs/1000;
171 select(0,NULL,NULL,NULL,&tval);
173 #endif /* HAVE_USLEEP */
176 /*******************************************************************
177 A stat() wrapper that will deal with 64 bit filesizes.
178 ********************************************************************/
180 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
183 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
184 ret = stat64(fname, sbuf);
186 ret = stat(fname, sbuf);
188 /* we always want directories to appear zero size */
189 if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
193 /*******************************************************************
194 An fstat() wrapper that will deal with 64 bit filesizes.
195 ********************************************************************/
197 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
200 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
201 ret = fstat64(fd, sbuf);
203 ret = fstat(fd, sbuf);
205 /* we always want directories to appear zero size */
206 if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
210 /*******************************************************************
211 An lstat() wrapper that will deal with 64 bit filesizes.
212 ********************************************************************/
214 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
217 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
218 ret = lstat64(fname, sbuf);
220 ret = lstat(fname, sbuf);
222 /* we always want directories to appear zero size */
223 if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
227 /*******************************************************************
228 An ftruncate() wrapper that will deal with 64 bit filesizes.
229 ********************************************************************/
231 int sys_ftruncate(int fd, SMB_OFF_T offset)
233 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
234 return ftruncate64(fd, offset);
236 return ftruncate(fd, offset);
240 /*******************************************************************
241 An lseek() wrapper that will deal with 64 bit filesizes.
242 ********************************************************************/
244 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
246 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
247 return lseek64(fd, offset, whence);
249 return lseek(fd, offset, whence);
253 /*******************************************************************
254 An fseek() wrapper that will deal with 64 bit filesizes.
255 ********************************************************************/
257 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
259 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
260 return fseek64(fp, offset, whence);
261 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
262 return fseeko64(fp, offset, whence);
264 return fseek(fp, offset, whence);
268 /*******************************************************************
269 An ftell() wrapper that will deal with 64 bit filesizes.
270 ********************************************************************/
272 SMB_OFF_T sys_ftell(FILE *fp)
274 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
275 return (SMB_OFF_T)ftell64(fp);
276 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
277 return (SMB_OFF_T)ftello64(fp);
279 return (SMB_OFF_T)ftell(fp);
283 /*******************************************************************
284 A creat() wrapper that will deal with 64 bit filesizes.
285 ********************************************************************/
287 int sys_creat(const char *path, mode_t mode)
289 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
290 return creat64(path, mode);
293 * If creat64 isn't defined then ensure we call a potential open64.
296 return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
300 /*******************************************************************
301 An open() wrapper that will deal with 64 bit filesizes.
302 ********************************************************************/
304 int sys_open(const char *path, int oflag, mode_t mode)
306 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
307 return open64(path, oflag, mode);
309 return open(path, oflag, mode);
313 /*******************************************************************
314 An fopen() wrapper that will deal with 64 bit filesizes.
315 ********************************************************************/
317 FILE *sys_fopen(const char *path, const char *type)
319 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
320 return fopen64(path, type);
322 return fopen(path, type);
326 /*******************************************************************
327 A readdir wrapper that will deal with 64 bit filesizes.
328 ********************************************************************/
330 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
332 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
333 return readdir64(dirp);
335 return readdir(dirp);
339 /*******************************************************************
340 The wait() calls vary between systems
341 ********************************************************************/
343 int sys_waitpid(pid_t pid,int *status,int options)
346 return waitpid(pid,status,options);
347 #else /* HAVE_WAITPID */
348 return wait4(pid, status, options, NULL);
349 #endif /* HAVE_WAITPID */
352 /*******************************************************************
353 system wrapper for getwd
354 ********************************************************************/
355 char *sys_getwd(char *s)
359 wd = (char *)getcwd(s, sizeof (pstring));
361 wd = (char *)getwd(s);
366 /*******************************************************************
367 chown isn't used much but OS/2 doesn't have it
368 ********************************************************************/
370 int sys_chown(const char *fname,uid_t uid,gid_t gid)
375 DEBUG(1,("WARNING: no chown!\n"));
379 return(chown(fname,uid,gid));
383 /*******************************************************************
384 os/2 also doesn't have chroot
385 ********************************************************************/
386 int sys_chroot(const char *dname)
391 DEBUG(1,("WARNING: no chroot!\n"));
395 return(chroot(dname));
399 /**************************************************************************
400 A wrapper for gethostbyname() that tries avoids looking up hostnames
401 in the root domain, which can cause dial-on-demand links to come up for no
403 ****************************************************************************/
404 struct hostent *sys_gethostbyname(const char *name)
406 #ifdef REDUCE_ROOT_DNS_LOOKUPS
407 char query[256], hostname[256];
410 /* Does this name have any dots in it? If so, make no change */
412 if (strchr(name, '.'))
413 return(gethostbyname(name));
415 /* Get my hostname, which should have domain name
416 attached. If not, just do the gethostname on the
420 gethostname(hostname, sizeof(hostname) - 1);
421 hostname[sizeof(hostname) - 1] = 0;
422 if ((domain = strchr(hostname, '.')) == NULL)
423 return(gethostbyname(name));
425 /* Attach domain name to query and do modified query.
426 If names too large, just do gethostname on the
430 if((strlen(name) + strlen(domain)) >= sizeof(query))
431 return(gethostbyname(name));
433 slprintf(query, sizeof(query)-1, "%s%s", name, domain);
434 return(gethostbyname(query));
435 #else /* REDUCE_ROOT_DNS_LOOKUPS */
436 return(gethostbyname(name));
437 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
441 /**************************************************************************
442 Try and abstract process capabilities (for systems that have them).
443 ****************************************************************************/
445 BOOL set_process_capability( uint32 cap_flag, BOOL enable )
447 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
448 if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
450 cap_t cap = cap_get_proc();
453 DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
459 cap->cap_effective |= CAP_NETWORK_MGT;
461 cap->cap_effective &= ~CAP_NETWORK_MGT;
463 if (cap_set_proc(cap) == -1) {
464 DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
472 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
478 /**************************************************************************
479 Try and abstract inherited process capabilities (for systems that have them).
480 ****************************************************************************/
482 BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
484 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
485 if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
487 cap_t cap = cap_get_proc();
490 DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
496 cap->cap_inheritable |= CAP_NETWORK_MGT;
498 cap->cap_inheritable &= ~CAP_NETWORK_MGT;
500 if (cap_set_proc(cap) == -1) {
501 DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n",
509 DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
515 /**************************************************************************
516 Wrapper for random().
517 ****************************************************************************/
519 long sys_random(void)
521 #if defined(HAVE_RANDOM)
522 return (long)random();
523 #elif defined(HAVE_RAND)
526 DEBUG(0,("Error - no random function available !\n"));
531 /**************************************************************************
532 Wrapper for srandom().
533 ****************************************************************************/
535 void sys_srandom(unsigned int seed)
537 #if defined(HAVE_SRANDOM)
539 #elif defined(HAVE_SRAND)
542 DEBUG(0,("Error - no srandom function available !\n"));
547 /**************************************************************************
548 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
549 ****************************************************************************/
553 #if defined(SYSCONF_SC_NGROUPS_MAX)
554 int ret = sysconf(_SC_NGROUPS_MAX);
555 return (ret == -1) ? NGROUPS_MAX : ret;
561 /**************************************************************************
562 Wrapper for getgroups. Deals with broken (int) case.
563 ****************************************************************************/
565 int sys_getgroups(int setlen, gid_t *gidset)
567 #if !defined(HAVE_BROKEN_GETGROUPS)
568 return getgroups(setlen, gidset);
576 return getgroups(setlen, &gid);
580 * Broken case. We need to allocate a
581 * GID_T array of size setlen.
590 setlen = groups_max();
592 if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
593 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
597 if((ngroups = getgroups(setlen, group_list)) < 0) {
598 int saved_errno = errno;
599 free((char *)group_list);
604 for(i = 0; i < ngroups; i++)
605 gidset[i] = (gid_t)group_list[i];
607 free((char *)group_list);
609 #endif /* HAVE_BROKEN_GETGROUPS */
612 #ifdef HAVE_SETGROUPS
614 /**************************************************************************
615 Wrapper for setgroups. Deals with broken (int) case. Automatically used
616 if we have broken getgroups.
617 ****************************************************************************/
619 int sys_setgroups(int setlen, gid_t *gidset)
621 #if !defined(HAVE_BROKEN_GETGROUPS)
622 return setgroups(setlen, gidset);
631 if (setlen < 0 || setlen > groups_max()) {
637 * Broken case. We need to allocate a
638 * GID_T array of size setlen.
641 if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
642 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
646 for(i = 0; i < setlen; i++)
647 group_list[i] = (GID_T) gidset[i];
649 if(setgroups(setlen, group_list) != 0) {
650 int saved_errno = errno;
651 free((char *)group_list);
656 free((char *)group_list);
658 #endif /* HAVE_BROKEN_GETGROUPS */
661 #endif /* HAVE_SETGROUPS */
664 * We only wrap pw_name and pw_passwd for now as these
665 * are the only potentially modified fields.
668 /**************************************************************************
669 Helper function for getpwnam/getpwuid wrappers.
670 ****************************************************************************/
672 static struct passwd *setup_pwret(struct passwd *pass)
674 static pstring pw_name;
675 static pstring pw_passwd;
676 static struct passwd pw_ret;
683 memcpy((char *)&pw_ret, pass, sizeof(struct passwd));
687 pw_ret.pw_name = pw_name;
688 pstrcpy(pw_ret.pw_name, pass->pw_name);
693 pw_ret.pw_passwd = pw_passwd;
694 pstrcpy(pw_ret.pw_passwd, pass->pw_passwd);
700 /**************************************************************************
701 Wrapper for getpwnam(). Always returns a static that can be modified.
702 ****************************************************************************/
704 struct passwd *sys_getpwnam(const char *name)
706 return setup_pwret(getpwnam(name));
709 /**************************************************************************
710 Wrapper for getpwuid(). Always returns a static that can be modified.
711 ****************************************************************************/
713 struct passwd *sys_getpwuid(uid_t uid)
715 return setup_pwret(getpwuid(uid));
718 /**************************************************************************
719 The following are the UNICODE versions of *all* system interface functions
720 called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
721 which currently are left as ascii as they are not used other than in name
723 ****************************************************************************/
725 /**************************************************************************
726 Wide stat. Just narrow and call sys_xxx.
727 ****************************************************************************/
729 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
732 return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
735 /**************************************************************************
736 Wide lstat. Just narrow and call sys_xxx.
737 ****************************************************************************/
739 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
742 return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
745 /**************************************************************************
746 Wide creat. Just narrow and call sys_xxx.
747 ****************************************************************************/
749 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
752 return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
755 /**************************************************************************
756 Wide open. Just narrow and call sys_xxx.
757 ****************************************************************************/
759 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
762 return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
765 /**************************************************************************
766 Wide fopen. Just narrow and call sys_xxx.
767 ****************************************************************************/
769 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
772 return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
775 /**************************************************************************
776 Wide opendir. Just narrow and call sys_xxx.
777 ****************************************************************************/
779 DIR *wsys_opendir(const smb_ucs2_t *wfname)
782 return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
785 /**************************************************************************
786 Wide readdir. Return a structure pointer containing a wide filename.
787 ****************************************************************************/
789 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
791 static SMB_STRUCT_WDIRENT retval;
792 SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
798 * The only POSIX defined member of this struct is d_name.
801 unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
806 /**************************************************************************
807 Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
808 ****************************************************************************/
810 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
813 char *p = sys_getwd(fname);
818 return unix_to_unicode(s, p, sizeof(wpstring));
821 /**************************************************************************
822 Wide chown. Just narrow and call sys_xxx.
823 ****************************************************************************/
825 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
828 return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
831 /**************************************************************************
832 Wide chroot. Just narrow and call sys_xxx.
833 ****************************************************************************/
835 int wsys_chroot(const smb_ucs2_t *wfname)
838 return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
841 /**************************************************************************
842 Wide getpwnam. Return a structure pointer containing wide names.
843 ****************************************************************************/
845 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
847 static SMB_STRUCT_WPASSWD retval;
849 struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
854 unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
855 retval.pw_passwd = pwret->pw_passwd;
856 retval.pw_uid = pwret->pw_uid;
857 retval.pw_gid = pwret->pw_gid;
858 unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
859 unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
860 unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
865 /**************************************************************************
866 Wide getpwuid. Return a structure pointer containing wide names.
867 ****************************************************************************/
869 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
871 static SMB_STRUCT_WPASSWD retval;
872 struct passwd *pwret = sys_getpwuid(uid);
877 unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
878 retval.pw_passwd = pwret->pw_passwd;
879 retval.pw_uid = pwret->pw_uid;
880 retval.pw_gid = pwret->pw_gid;
881 unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
882 unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
883 unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
888 /**************************************************************************
889 Extract a command into an arg list. Uses a static pstring for storage.
890 Caller frees returned arg list (which contains pointers into the static pstring).
891 ****************************************************************************/
893 static char **extract_args(const char *command)
895 static pstring trunc_cmd;
901 pstrcpy(trunc_cmd, command);
903 if(!(ptr = strtok(trunc_cmd, " \t"))) {
912 for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
915 if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
919 * Now do the extraction.
922 pstrcpy(trunc_cmd, command);
924 ptr = strtok(trunc_cmd, " \t");
928 while((ptr = strtok(NULL, " \t")) != NULL)
935 /**************************************************************************
936 Wrapper for fork. Ensures that mypid is reset. Used so we can write
937 a sys_getpid() that only does a system call *once*.
938 ****************************************************************************/
940 static pid_t mypid = (pid_t)-1;
944 pid_t forkret = fork();
946 if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
952 /**************************************************************************
953 Wrapper for getpid. Ensures we only do a system call *once*.
954 ****************************************************************************/
956 pid_t sys_getpid(void)
958 if (mypid == (pid_t)-1)
964 /**************************************************************************
965 Wrapper for popen. Safer as it doesn't search a path.
966 Modified from the glibc sources.
967 modified by tridge to return a file descriptor. We must kick our FILE* habit
968 ****************************************************************************/
970 typedef struct _popen_list
974 struct _popen_list *next;
977 static popen_list *popen_chain;
979 int sys_popen(const char *command)
981 int parent_end, child_end;
983 popen_list *entry = NULL;
986 if (pipe(pipe_fds) < 0)
989 parent_end = pipe_fds[0];
990 child_end = pipe_fds[1];
997 if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
1001 * Extract the command and args into a NULL terminated array.
1004 if(!(argl = extract_args(command)))
1007 entry->child_pid = sys_fork();
1009 if (entry->child_pid == -1) {
1013 if (entry->child_pid == 0) {
1019 int child_std_end = STDOUT_FILENO;
1023 if (child_end != child_std_end) {
1024 dup2 (child_end, child_std_end);
1029 * POSIX.2: "popen() shall ensure that any streams from previous
1030 * popen() calls that remain open in the parent process are closed
1031 * in the new child process."
1034 for (p = popen_chain; p; p = p->next)
1037 execv(argl[0], argl);
1048 /* Link into popen_chain. */
1049 entry->next = popen_chain;
1050 popen_chain = entry;
1057 free((char *)entry);
1065 /**************************************************************************
1066 Wrapper for pclose. Modified from the glibc sources.
1067 ****************************************************************************/
1068 int sys_pclose(int fd)
1071 popen_list **ptr = &popen_chain;
1072 popen_list *entry = NULL;
1076 /* Unlink from popen_chain. */
1077 for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1078 if ((*ptr)->fd == fd) {
1080 *ptr = (*ptr)->next;
1086 if (status < 0 || close(entry->fd) < 0)
1090 * As Samba is catching and eating child process
1091 * exits we don't really care about the child exit
1092 * code, a -1 with errno = ECHILD will do fine for us.
1096 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1097 } while (wait_pid == -1 && errno == EINTR);
1099 free((char *)entry);