Added sys_fork() and sys_getpid() functions to stop the overhead
[tprouty/samba.git] / source / lib / system.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba system utilities
5    Copyright (C) Andrew Tridgell 1992-1998
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 extern int DEBUGLEVEL;
25
26 /*
27    The idea is that this file will eventually have wrappers around all
28    important system calls in samba. The aims are:
29
30    - to enable easier porting by putting OS dependent stuff in here
31
32    - to allow for hooks into other "pseudo-filesystems"
33
34    - to allow easier integration of things like the japanese extensions
35
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.
39 */
40
41
42 /*******************************************************************
43 this replaces the normal select() system call
44 return if some data has arrived on one of the file descriptors
45 return -1 means error
46 ********************************************************************/
47 #ifndef HAVE_SELECT
48 static int pollfd(int fd)
49 {
50   int     r=0;
51
52 #ifdef HAS_RDCHK
53   r = rdchk(fd);
54 #elif defined(TCRDCHK)
55   (void)ioctl(fd, TCRDCHK, &r);
56 #else
57   (void)ioctl(fd, FIONREAD, &r);
58 #endif
59
60   return(r);
61 }
62
63 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
64 {
65   fd_set fds2;
66   int counter=0;
67   int found=0;
68
69   FD_ZERO(&fds2);
70
71   while (1) 
72   {
73     int i;
74     for (i=0;i<maxfd;i++) {
75       if (FD_ISSET(i,fds) && pollfd(i)>0) {
76         found++;
77         FD_SET(i,&fds2);
78       }
79     }
80
81     if (found) {
82       memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
83       return(found);
84     }
85       
86     if (tval && tval->tv_sec < counter) return(0);
87       sleep(1);
88       counter++;
89   }
90 }
91
92 #else /* !NO_SELECT */
93 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
94 {
95 #ifdef USE_POLL
96   struct pollfd pfd[256];
97   int i;
98   int maxpoll;
99   int timeout;
100   int pollrtn;
101
102   maxpoll = 0;
103   for( i = 0; i < maxfd; i++) {
104     if(FD_ISSET(i,fds)) {
105       struct pollfd *pfdp = &pfd[maxpoll++];
106       pfdp->fd = i;
107       pfdp->events = POLLIN;
108       pfdp->revents = 0;
109     }
110   }
111
112   timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
113                 -1;
114   errno = 0;
115   do {
116     pollrtn = poll( &pfd[0], maxpoll, timeout);
117   } while (pollrtn<0 && errno == EINTR);
118
119   FD_ZERO(fds);
120
121   for( i = 0; i < maxpoll; i++)
122     if( pfd[i].revents & POLLIN )
123       FD_SET(pfd[i].fd,fds);
124
125   return pollrtn;
126 #else /* USE_POLL */
127
128   struct timeval t2;
129   int selrtn;
130
131   do {
132     if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
133     errno = 0;
134     selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
135   } while (selrtn<0 && errno == EINTR);
136
137   return(selrtn);
138 }
139 #endif /* USE_POLL */
140 #endif /* NO_SELECT */
141
142 /*******************************************************************
143  A wrapper for usleep in case we don't have one.
144 ********************************************************************/
145
146 int sys_usleep(long usecs)
147 {
148 #ifndef HAVE_USLEEP
149   struct timeval tval;
150 #endif
151
152   /*
153    * We need this braindamage as the glibc usleep
154    * is not SPEC1170 complient... grumble... JRA.
155    */
156
157   if(usecs < 0 || usecs > 1000000) {
158     errno = EINVAL;
159     return -1;
160   }
161
162 #if HAVE_USLEEP
163   usleep(usecs);
164   return 0;
165 #else /* HAVE_USLEEP */
166   /*
167    * Fake it with select...
168    */
169   tval.tv_sec = 0;
170   tval.tv_usec = usecs/1000;
171   select(0,NULL,NULL,NULL,&tval);
172   return 0;
173 #endif /* HAVE_USLEEP */
174 }
175
176 /*******************************************************************
177 A stat() wrapper that will deal with 64 bit filesizes.
178 ********************************************************************/
179
180 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
181 {
182         int ret;
183 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
184         ret = stat64(fname, sbuf);
185 #else
186         ret = stat(fname, sbuf);
187 #endif
188         /* we always want directories to appear zero size */
189         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
190         return ret;
191 }
192
193 /*******************************************************************
194  An fstat() wrapper that will deal with 64 bit filesizes.
195 ********************************************************************/
196
197 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
198 {
199         int ret;
200 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
201         ret = fstat64(fd, sbuf);
202 #else
203         ret = fstat(fd, sbuf);
204 #endif
205         /* we always want directories to appear zero size */
206         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
207         return ret;
208 }
209
210 /*******************************************************************
211  An lstat() wrapper that will deal with 64 bit filesizes.
212 ********************************************************************/
213
214 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
215 {
216         int ret;
217 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
218         ret = lstat64(fname, sbuf);
219 #else
220         ret = lstat(fname, sbuf);
221 #endif
222         /* we always want directories to appear zero size */
223         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
224         return ret;
225 }
226
227 /*******************************************************************
228  An ftruncate() wrapper that will deal with 64 bit filesizes.
229 ********************************************************************/
230
231 int sys_ftruncate(int fd, SMB_OFF_T offset)
232 {
233 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
234   return ftruncate64(fd, offset);
235 #else
236   return ftruncate(fd, offset);
237 #endif
238 }
239
240 /*******************************************************************
241  An lseek() wrapper that will deal with 64 bit filesizes.
242 ********************************************************************/
243
244 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
245 {
246 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
247   return lseek64(fd, offset, whence);
248 #else
249   return lseek(fd, offset, whence);
250 #endif
251 }
252
253 /*******************************************************************
254  An fseek() wrapper that will deal with 64 bit filesizes.
255 ********************************************************************/
256
257 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
258 {
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);
263 #else
264   return fseek(fp, offset, whence);
265 #endif
266 }
267
268 /*******************************************************************
269  An ftell() wrapper that will deal with 64 bit filesizes.
270 ********************************************************************/
271
272 SMB_OFF_T sys_ftell(FILE *fp)
273 {
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);
278 #else
279   return (SMB_OFF_T)ftell(fp);
280 #endif
281 }
282
283 /*******************************************************************
284  A creat() wrapper that will deal with 64 bit filesizes.
285 ********************************************************************/
286
287 int sys_creat(const char *path, mode_t mode)
288 {
289 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
290   return creat64(path, mode);
291 #else
292   /*
293    * If creat64 isn't defined then ensure we call a potential open64.
294    * JRA.
295    */
296   return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
297 #endif
298 }
299
300 /*******************************************************************
301  An open() wrapper that will deal with 64 bit filesizes.
302 ********************************************************************/
303
304 int sys_open(const char *path, int oflag, mode_t mode)
305 {
306 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
307   return open64(path, oflag, mode);
308 #else
309   return open(path, oflag, mode);
310 #endif
311 }
312
313 /*******************************************************************
314  An fopen() wrapper that will deal with 64 bit filesizes.
315 ********************************************************************/
316
317 FILE *sys_fopen(const char *path, const char *type)
318 {
319 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
320   return fopen64(path, type);
321 #else
322   return fopen(path, type);
323 #endif
324 }
325
326 /*******************************************************************
327  A readdir wrapper that will deal with 64 bit filesizes.
328 ********************************************************************/
329
330 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
331 {
332 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
333   return readdir64(dirp);
334 #else
335   return readdir(dirp);
336 #endif
337 }
338
339 /*******************************************************************
340 The wait() calls vary between systems
341 ********************************************************************/
342
343 int sys_waitpid(pid_t pid,int *status,int options)
344 {
345 #ifdef HAVE_WAITPID
346   return waitpid(pid,status,options);
347 #else /* HAVE_WAITPID */
348   return wait4(pid, status, options, NULL);
349 #endif /* HAVE_WAITPID */
350 }
351
352 /*******************************************************************
353 system wrapper for getwd
354 ********************************************************************/
355 char *sys_getwd(char *s)
356 {
357     char *wd;
358 #ifdef HAVE_GETCWD
359     wd = (char *)getcwd(s, sizeof (pstring));
360 #else
361     wd = (char *)getwd(s);
362 #endif
363     return wd;
364 }
365
366 /*******************************************************************
367 chown isn't used much but OS/2 doesn't have it
368 ********************************************************************/
369
370 int sys_chown(const char *fname,uid_t uid,gid_t gid)
371 {
372 #ifndef HAVE_CHOWN
373         static int done;
374         if (!done) {
375                 DEBUG(1,("WARNING: no chown!\n"));
376                 done=1;
377         }
378 #else
379         return(chown(fname,uid,gid));
380 #endif
381 }
382
383 /*******************************************************************
384 os/2 also doesn't have chroot
385 ********************************************************************/
386 int sys_chroot(const char *dname)
387 {
388 #ifndef HAVE_CHROOT
389         static int done;
390         if (!done) {
391                 DEBUG(1,("WARNING: no chroot!\n"));
392                 done=1;
393         }
394 #else
395         return(chroot(dname));
396 #endif
397 }
398
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
402 apparent reason.
403 ****************************************************************************/
404 struct hostent *sys_gethostbyname(const char *name)
405 {
406 #ifdef REDUCE_ROOT_DNS_LOOKUPS
407   char query[256], hostname[256];
408   char *domain;
409
410   /* Does this name have any dots in it? If so, make no change */
411
412   if (strchr(name, '.'))
413     return(gethostbyname(name));
414
415   /* Get my hostname, which should have domain name 
416      attached. If not, just do the gethostname on the
417      original string. 
418   */
419
420   gethostname(hostname, sizeof(hostname) - 1);
421   hostname[sizeof(hostname) - 1] = 0;
422   if ((domain = strchr(hostname, '.')) == NULL)
423     return(gethostbyname(name));
424
425   /* Attach domain name to query and do modified query.
426      If names too large, just do gethostname on the
427      original string.
428   */
429
430   if((strlen(name) + strlen(domain)) >= sizeof(query))
431     return(gethostbyname(name));
432
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 */
438 }
439
440
441 /**************************************************************************
442  Try and abstract process capabilities (for systems that have them).
443 ****************************************************************************/
444
445 BOOL set_process_capability( uint32 cap_flag, BOOL enable )
446 {
447 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
448   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
449   {
450     cap_t cap = cap_get_proc();
451
452     if (cap == NULL) {
453       DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
454             strerror(errno)));
455       return False;
456     }
457
458     if(enable)
459       cap->cap_effective |= CAP_NETWORK_MGT;
460     else
461       cap->cap_effective &= ~CAP_NETWORK_MGT;
462
463     if (cap_set_proc(cap) == -1) {
464       DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
465             strerror(errno)));
466       cap_free(cap);
467       return False;
468     }
469
470     cap_free(cap);
471
472     DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
473   }
474 #endif
475   return True;
476 }
477
478 /**************************************************************************
479  Try and abstract inherited process capabilities (for systems that have them).
480 ****************************************************************************/
481
482 BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
483 {
484 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
485   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
486   {
487     cap_t cap = cap_get_proc();
488
489     if (cap == NULL) {
490       DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
491             strerror(errno)));
492       return False;
493     }
494
495     if(enable)
496       cap->cap_inheritable |= CAP_NETWORK_MGT;
497     else
498       cap->cap_inheritable &= ~CAP_NETWORK_MGT;
499
500     if (cap_set_proc(cap) == -1) {
501       DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
502             strerror(errno)));
503       cap_free(cap);
504       return False;
505     }
506
507     cap_free(cap);
508
509     DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
510   }
511 #endif
512   return True;
513 }
514
515 /**************************************************************************
516  Wrapper for random().
517 ****************************************************************************/
518
519 long sys_random(void)
520 {
521 #if defined(HAVE_RANDOM)
522   return (long)random();
523 #elif defined(HAVE_RAND)
524   return (long)rand();
525 #else
526   DEBUG(0,("Error - no random function available !\n"));
527   exit(1);
528 #endif
529 }
530
531 /**************************************************************************
532  Wrapper for srandom().
533 ****************************************************************************/
534
535 void sys_srandom(unsigned int seed)
536 {
537 #if defined(HAVE_SRANDOM)
538   srandom(seed);
539 #elif defined(HAVE_SRAND)
540   srand(seed);
541 #else
542   DEBUG(0,("Error - no srandom function available !\n"));
543   exit(1);
544 #endif
545 }
546
547 /**************************************************************************
548  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
549 ****************************************************************************/
550
551 int groups_max(void)
552 {
553 #if defined(SYSCONF_SC_NGROUPS_MAX)
554   int ret = sysconf(_SC_NGROUPS_MAX);
555   return (ret == -1) ? NGROUPS_MAX : ret;
556 #else
557   return NGROUPS_MAX;
558 #endif
559 }
560
561 /**************************************************************************
562  Wrapper for getgroups. Deals with broken (int) case.
563 ****************************************************************************/
564
565 int sys_getgroups(int setlen, gid_t *gidset)
566 {
567 #if !defined(HAVE_BROKEN_GETGROUPS)
568   return getgroups(setlen, gidset);
569 #else
570
571   GID_T gid;
572   GID_T *group_list;
573   int i, ngroups;
574
575   if(setlen == 0) {
576     return getgroups(setlen, &gid);
577   }
578
579   /*
580    * Broken case. We need to allocate a
581    * GID_T array of size setlen.
582    */
583
584   if(setlen < 0) {
585     errno = EINVAL; 
586     return -1;
587   } 
588
589   if (setlen == 0)
590     setlen = groups_max();
591
592   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
593     DEBUG(0,("sys_getgroups: Malloc fail.\n"));
594     return -1;
595   }
596
597   if((ngroups = getgroups(setlen, group_list)) < 0) {
598     int saved_errno = errno;
599     free((char *)group_list);
600     errno = saved_errno;
601     return -1;
602   }
603
604   for(i = 0; i < ngroups; i++)
605     gidset[i] = (gid_t)group_list[i];
606
607   free((char *)group_list);
608   return ngroups;
609 #endif /* HAVE_BROKEN_GETGROUPS */
610 }
611
612 #ifdef HAVE_SETGROUPS
613
614 /**************************************************************************
615  Wrapper for setgroups. Deals with broken (int) case. Automatically used
616  if we have broken getgroups.
617 ****************************************************************************/
618
619 int sys_setgroups(int setlen, gid_t *gidset)
620 {
621 #if !defined(HAVE_BROKEN_GETGROUPS)
622   return setgroups(setlen, gidset);
623 #else
624
625   GID_T *group_list;
626   int i ; 
627
628   if (setlen == 0)
629     return 0 ;
630
631   if (setlen < 0 || setlen > groups_max()) {
632     errno = EINVAL; 
633     return -1;   
634   }
635
636   /*
637    * Broken case. We need to allocate a
638    * GID_T array of size setlen.
639    */
640
641   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
642     DEBUG(0,("sys_setgroups: Malloc fail.\n"));
643     return -1;    
644   }
645  
646   for(i = 0; i < setlen; i++) 
647     group_list[i] = (GID_T) gidset[i]; 
648
649   if(setgroups(setlen, group_list) != 0) {
650     int saved_errno = errno;
651     free((char *)group_list);
652     errno = saved_errno;
653     return -1;
654   }
655  
656   free((char *)group_list);
657   return 0 ;
658 #endif /* HAVE_BROKEN_GETGROUPS */
659 }
660
661 #endif /* HAVE_SETGROUPS */
662
663 /*
664  * We only wrap pw_name and pw_passwd for now as these
665  * are the only potentially modified fields.
666  */
667
668 /**************************************************************************
669  Helper function for getpwnam/getpwuid wrappers.
670 ****************************************************************************/
671
672 static struct passwd *setup_pwret(struct passwd *pass)
673 {
674         static pstring pw_name;
675         static pstring pw_passwd;
676         static struct passwd pw_ret;
677
678         if (pass == NULL)
679         {
680                 return NULL;
681         }
682
683         memcpy((char *)&pw_ret, pass, sizeof(struct passwd));
684
685         if (pass->pw_name)
686         {
687                 pw_ret.pw_name = pw_name;
688                 pstrcpy(pw_ret.pw_name, pass->pw_name);
689         }
690
691         if (pass->pw_passwd)
692         {
693                 pw_ret.pw_passwd = pw_passwd;
694                 pstrcpy(pw_ret.pw_passwd, pass->pw_passwd);
695         }
696
697         return &pw_ret;
698 }
699
700 /**************************************************************************
701  Wrapper for getpwnam(). Always returns a static that can be modified.
702 ****************************************************************************/
703
704 struct passwd *sys_getpwnam(const char *name)
705 {
706         return setup_pwret(getpwnam(name));
707 }
708
709 /**************************************************************************
710  Wrapper for getpwuid(). Always returns a static that can be modified.
711 ****************************************************************************/
712
713 struct passwd *sys_getpwuid(uid_t uid)
714 {
715         return setup_pwret(getpwuid(uid));
716 }
717
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
722  resolution.
723 ****************************************************************************/
724
725 /**************************************************************************
726  Wide stat. Just narrow and call sys_xxx.
727 ****************************************************************************/
728
729 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
730 {
731         pstring fname;
732         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
733 }
734
735 /**************************************************************************
736  Wide lstat. Just narrow and call sys_xxx.
737 ****************************************************************************/
738
739 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
740 {
741         pstring fname;
742         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
743 }
744
745 /**************************************************************************
746  Wide creat. Just narrow and call sys_xxx.
747 ****************************************************************************/
748
749 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
750 {
751         pstring fname;
752         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
753 }
754
755 /**************************************************************************
756  Wide open. Just narrow and call sys_xxx.
757 ****************************************************************************/
758
759 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
760 {
761         pstring fname;
762         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
763 }
764
765 /**************************************************************************
766  Wide fopen. Just narrow and call sys_xxx.
767 ****************************************************************************/
768
769 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
770 {
771         pstring fname;
772         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
773 }
774
775 /**************************************************************************
776  Wide opendir. Just narrow and call sys_xxx.
777 ****************************************************************************/
778
779 DIR *wsys_opendir(const smb_ucs2_t *wfname)
780 {
781         pstring fname;
782         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
783 }
784
785 /**************************************************************************
786  Wide readdir. Return a structure pointer containing a wide filename.
787 ****************************************************************************/
788
789 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
790 {
791         static SMB_STRUCT_WDIRENT retval;
792         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
793
794         if(!dirval)
795                 return NULL;
796
797         /*
798          * The only POSIX defined member of this struct is d_name.
799          */
800
801         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
802
803         return &retval;
804 }
805
806 /**************************************************************************
807  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
808 ****************************************************************************/
809
810 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
811 {
812         pstring fname;
813         char *p = sys_getwd(fname);
814
815         if(!p)
816                 return NULL;
817
818         return unix_to_unicode(s, p, sizeof(wpstring));
819 }
820
821 /**************************************************************************
822  Wide chown. Just narrow and call sys_xxx.
823 ****************************************************************************/
824
825 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
826 {
827         pstring fname;
828         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
829 }
830
831 /**************************************************************************
832  Wide chroot. Just narrow and call sys_xxx.
833 ****************************************************************************/
834
835 int wsys_chroot(const smb_ucs2_t *wfname)
836 {
837         pstring fname;
838         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
839 }
840
841 /**************************************************************************
842  Wide getpwnam. Return a structure pointer containing wide names.
843 ****************************************************************************/
844
845 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
846 {
847         static SMB_STRUCT_WPASSWD retval;
848         fstring name;
849         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
850
851         if(!pwret)
852                 return NULL;
853
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));
861
862         return &retval;
863 }
864
865 /**************************************************************************
866  Wide getpwuid. Return a structure pointer containing wide names.
867 ****************************************************************************/
868
869 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
870 {
871         static SMB_STRUCT_WPASSWD retval;
872         struct passwd *pwret = sys_getpwuid(uid);
873
874         if(!pwret)
875                 return NULL;
876
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));
884
885         return &retval;
886 }
887
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 ****************************************************************************/
892
893 static char **extract_args(const char *command)
894 {
895         static pstring trunc_cmd;
896         char *ptr;
897         int argcl;
898         char **argl = NULL;
899         int i;
900
901         pstrcpy(trunc_cmd, command);
902
903         if(!(ptr = strtok(trunc_cmd, " \t"))) {
904                 errno = EINVAL;
905                 return NULL;
906         }
907
908         /*
909          * Count the args.
910          */
911
912         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
913                 argcl++;
914
915         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
916                 return NULL;
917
918         /*
919          * Now do the extraction.
920          */
921
922         pstrcpy(trunc_cmd, command);
923
924         ptr = strtok(trunc_cmd, " \t");
925         i = 0;
926         argl[i++] = ptr;
927
928         while((ptr = strtok(NULL, " \t")) != NULL)
929                 argl[i++] = ptr;
930
931         argl[i++] = NULL;
932         return argl;
933 }
934
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 ****************************************************************************/
939
940 static pid_t mypid = (pid_t)-1;
941
942 pid_t sys_fork(void)
943 {
944         pid_t forkret = fork();
945
946         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
947                 mypid = (pid_t) -1;
948
949         return forkret;
950 }
951
952 /**************************************************************************
953  Wrapper for getpid. Ensures we only do a system call *once*.
954 ****************************************************************************/
955
956 pid_t sys_getpid(void)
957 {
958         if (mypid == (pid_t)-1)
959                 mypid = getpid();
960
961         return mypid;
962 }
963
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 ****************************************************************************/
969
970 typedef struct _popen_list
971 {
972         int fd;
973         pid_t child_pid;
974         struct _popen_list *next;
975 } popen_list;
976
977 static popen_list *popen_chain;
978
979 int sys_popen(const char *command)
980 {
981         int parent_end, child_end;
982         int pipe_fds[2];
983         popen_list *entry = NULL;
984         char **argl = NULL;
985
986         if (pipe(pipe_fds) < 0)
987                 return -1;
988
989         parent_end = pipe_fds[0];
990         child_end = pipe_fds[1];
991
992         if (!*command) {
993                 errno = EINVAL;
994                 goto err_exit;
995         }
996
997         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
998                 goto err_exit;
999
1000         /*
1001          * Extract the command and args into a NULL terminated array.
1002          */
1003
1004         if(!(argl = extract_args(command)))
1005                 goto err_exit;
1006
1007         entry->child_pid = sys_fork();
1008
1009         if (entry->child_pid == -1) {
1010                 goto err_exit;
1011         }
1012
1013         if (entry->child_pid == 0) {
1014
1015                 /*
1016                  * Child !
1017                  */
1018
1019                 int child_std_end = STDOUT_FILENO;
1020                 popen_list *p;
1021
1022                 close(parent_end);
1023                 if (child_end != child_std_end) {
1024                         dup2 (child_end, child_std_end);
1025                         close (child_end);
1026                 }
1027
1028                 /*
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."
1032                  */
1033
1034                 for (p = popen_chain; p; p = p->next)
1035                         close(p->fd);
1036
1037                 execv(argl[0], argl);
1038                 _exit (127);
1039         }
1040
1041         /*
1042          * Parent.
1043          */
1044
1045         close (child_end);
1046         free((char *)argl);
1047
1048         /* Link into popen_chain. */
1049         entry->next = popen_chain;
1050         popen_chain = entry;
1051
1052         return entry->fd;
1053
1054 err_exit:
1055
1056         if(entry)
1057                 free((char *)entry);
1058         if(argl)
1059                 free((char *)argl);
1060         close(pipe_fds[0]);
1061         close(pipe_fds[1]);
1062         return -1;
1063 }
1064
1065 /**************************************************************************
1066  Wrapper for pclose. Modified from the glibc sources.
1067 ****************************************************************************/
1068 int sys_pclose(int fd)
1069 {
1070         int wstatus;
1071         popen_list **ptr = &popen_chain;
1072         popen_list *entry = NULL;
1073         pid_t wait_pid;
1074         int status = -1;
1075
1076         /* Unlink from popen_chain. */
1077         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1078                 if ((*ptr)->fd == fd) {
1079                         entry = *ptr;
1080                         *ptr = (*ptr)->next;
1081                         status = 0;
1082                         break;
1083                 }
1084         }
1085
1086         if (status < 0 || close(entry->fd) < 0)
1087                 return -1;
1088
1089         /*
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.
1093          */
1094
1095         do {
1096                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1097         } while (wait_pid == -1 && errno == EINTR);
1098
1099         free((char *)entry);
1100
1101         if (wait_pid == -1)
1102                 return -1;
1103         return wstatus;
1104 }