first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[kai/samba.git] / source3 / 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 #if defined(HAVE_MMAP)
327
328 /*******************************************************************
329  An mmap() wrapper that will deal with 64 bit filesizes.
330 ********************************************************************/
331
332 void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, SMB_OFF_T offset)
333 {
334 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_MMAP64)
335   return mmap64(addr, len, prot, flags, fd, offset);
336 #else
337   return mmap(addr, len, prot, flags, fd, offset);
338 #endif
339 }
340
341 #endif /* HAVE_MMAP */
342
343 /*******************************************************************
344  A readdir wrapper that will deal with 64 bit filesizes.
345 ********************************************************************/
346
347 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
348 {
349 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
350   return readdir64(dirp);
351 #else
352   return readdir(dirp);
353 #endif
354 }
355
356 /*******************************************************************
357 The wait() calls vary between systems
358 ********************************************************************/
359
360 int sys_waitpid(pid_t pid,int *status,int options)
361 {
362 #ifdef HAVE_WAITPID
363   return waitpid(pid,status,options);
364 #else /* HAVE_WAITPID */
365   return wait4(pid, status, options, NULL);
366 #endif /* HAVE_WAITPID */
367 }
368
369 /*******************************************************************
370 system wrapper for getwd
371 ********************************************************************/
372 char *sys_getwd(char *s)
373 {
374     char *wd;
375 #ifdef HAVE_GETCWD
376     wd = (char *)getcwd(s, sizeof (pstring));
377 #else
378     wd = (char *)getwd(s);
379 #endif
380     return wd;
381 }
382
383 /*******************************************************************
384 chown isn't used much but OS/2 doesn't have it
385 ********************************************************************/
386
387 int sys_chown(const char *fname,uid_t uid,gid_t gid)
388 {
389 #ifndef HAVE_CHOWN
390         static int done;
391         if (!done) {
392                 DEBUG(1,("WARNING: no chown!\n"));
393                 done=1;
394         }
395 #else
396         return(chown(fname,uid,gid));
397 #endif
398 }
399
400 /*******************************************************************
401 os/2 also doesn't have chroot
402 ********************************************************************/
403 int sys_chroot(const char *dname)
404 {
405 #ifndef HAVE_CHROOT
406         static int done;
407         if (!done) {
408                 DEBUG(1,("WARNING: no chroot!\n"));
409                 done=1;
410         }
411 #else
412         return(chroot(dname));
413 #endif
414 }
415
416 /**************************************************************************
417 A wrapper for gethostbyname() that tries avoids looking up hostnames 
418 in the root domain, which can cause dial-on-demand links to come up for no
419 apparent reason.
420 ****************************************************************************/
421 struct hostent *sys_gethostbyname(const char *name)
422 {
423 #ifdef REDUCE_ROOT_DNS_LOOKUPS
424   char query[256], hostname[256];
425   char *domain;
426
427   /* Does this name have any dots in it? If so, make no change */
428
429   if (strchr(name, '.'))
430     return(gethostbyname(name));
431
432   /* Get my hostname, which should have domain name 
433      attached. If not, just do the gethostname on the
434      original string. 
435   */
436
437   gethostname(hostname, sizeof(hostname) - 1);
438   hostname[sizeof(hostname) - 1] = 0;
439   if ((domain = strchr(hostname, '.')) == NULL)
440     return(gethostbyname(name));
441
442   /* Attach domain name to query and do modified query.
443      If names too large, just do gethostname on the
444      original string.
445   */
446
447   if((strlen(name) + strlen(domain)) >= sizeof(query))
448     return(gethostbyname(name));
449
450   slprintf(query, sizeof(query)-1, "%s%s", name, domain);
451   return(gethostbyname(query));
452 #else /* REDUCE_ROOT_DNS_LOOKUPS */
453   return(gethostbyname(name));
454 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
455 }
456
457
458 /**************************************************************************
459  Try and abstract process capabilities (for systems that have them).
460 ****************************************************************************/
461
462 BOOL set_process_capability( uint32 cap_flag, BOOL enable )
463 {
464 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
465   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
466   {
467     cap_t cap = cap_get_proc();
468
469     if (cap == NULL) {
470       DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
471             strerror(errno)));
472       return False;
473     }
474
475     if(enable)
476       cap->cap_effective |= CAP_NETWORK_MGT;
477     else
478       cap->cap_effective &= ~CAP_NETWORK_MGT;
479
480     if (cap_set_proc(cap) == -1) {
481       DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
482             strerror(errno)));
483       cap_free(cap);
484       return False;
485     }
486
487     cap_free(cap);
488
489     DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
490   }
491 #endif
492   return True;
493 }
494
495 /**************************************************************************
496  Try and abstract inherited process capabilities (for systems that have them).
497 ****************************************************************************/
498
499 BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
500 {
501 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
502   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
503   {
504     cap_t cap = cap_get_proc();
505
506     if (cap == NULL) {
507       DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
508             strerror(errno)));
509       return False;
510     }
511
512     if(enable)
513       cap->cap_inheritable |= CAP_NETWORK_MGT;
514     else
515       cap->cap_inheritable &= ~CAP_NETWORK_MGT;
516
517     if (cap_set_proc(cap) == -1) {
518       DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
519             strerror(errno)));
520       cap_free(cap);
521       return False;
522     }
523
524     cap_free(cap);
525
526     DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
527   }
528 #endif
529   return True;
530 }
531
532 /**************************************************************************
533  Wrapper for random().
534 ****************************************************************************/
535
536 long sys_random(void)
537 {
538 #if defined(HAVE_RANDOM)
539   return (long)random();
540 #elif defined(HAVE_RAND)
541   return (long)rand();
542 #else
543   DEBUG(0,("Error - no random function available !\n"));
544   exit(1);
545 #endif
546 }
547
548 /**************************************************************************
549  Wrapper for srandom().
550 ****************************************************************************/
551
552 void sys_srandom(unsigned int seed)
553 {
554 #if defined(HAVE_SRANDOM)
555   srandom(seed);
556 #elif defined(HAVE_SRAND)
557   srand(seed);
558 #else
559   DEBUG(0,("Error - no srandom function available !\n"));
560   exit(1);
561 #endif
562 }
563
564 /**************************************************************************
565  Wrapper for getgroups. Deals with broken (int) case.
566 ****************************************************************************/
567
568 int sys_getgroups(int setlen, gid_t *gidset)
569 {
570 #if !defined(HAVE_BROKEN_GETGROUPS)
571   return getgroups(setlen, gidset);
572 #else
573
574   GID_T gid;
575   GID_T *group_list;
576   int i, ngroups;
577
578   if(setlen == 0) {
579     return getgroups(setlen, &gid);
580   }
581
582   /*
583    * Broken case. We need to allocate a
584    * GID_T array of size setlen.
585    */
586
587   if(setlen < 0) {
588     errno = EINVAL; 
589     return -1;
590   } 
591
592   if (setlen == 0)
593     setlen = 1;
594
595   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
596     DEBUG(0,("sys_getgroups: Malloc fail.\n"));
597     return -1;
598   }
599
600   if((ngroups = getgroups(setlen, group_list)) < 0) {
601     int saved_errno = errno;
602     free((char *)group_list);
603     errno = saved_errno;
604     return -1;
605   }
606
607   for(i = 0; i < ngroups; i++)
608     gidset[i] = (gid_t)group_list[i];
609
610   free((char *)group_list);
611   return ngroups;
612 #endif /* HAVE_BROKEN_GETGROUPS */
613 }
614
615 #ifdef HAVE_SETGROUPS
616
617 /**************************************************************************
618  Wrapper for setgroups. Deals with broken (int) case. Automatically used
619  if we have broken getgroups.
620 ****************************************************************************/
621
622 int sys_setgroups(int setlen, gid_t *gidset)
623 {
624 #if !defined(HAVE_BROKEN_GETGROUPS)
625   return setgroups(setlen, gidset);
626 #else
627
628   GID_T *group_list;
629   int i ; 
630
631   if (setlen == 0)
632     return 0 ;
633
634 #ifdef NGROUPS_MAX
635   if (setlen > NGROUPS_MAX) {
636     errno = EINVAL; 
637     return -1;   
638   }
639 #endif
640
641   /*
642    * Broken case. We need to allocate a
643    * GID_T array of size setlen.
644    */
645
646   if (setlen == 0)
647     setlen = 1;
648
649   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
650     DEBUG(0,("sys_setgroups: Malloc fail.\n"));
651     return -1;    
652   }
653  
654   for(i = 0; i < setlen; i++) 
655     group_list[i] = (GID_T) gidset[i]; 
656
657   if(setgroups(setlen, group_list) != 0) {
658     int saved_errno = errno;
659     free((char *)group_list);
660     errno = saved_errno;
661     return -1;
662   }
663  
664   free((char *)group_list);
665   return 0 ;
666 #endif /* HAVE_BROKEN_GETGROUPS */
667 }
668
669 #endif /* HAVE_SETGROUPS */
670
671 /*
672  * We only wrap pw_name and pw_passwd for now as these
673  * are the only potentially modified fields.
674  */
675
676 /**************************************************************************
677  Helper function for getpwnam/getpwuid wrappers.
678 ****************************************************************************/
679
680 static struct passwd *setup_pwret(struct passwd *pass)
681 {
682         static pstring pw_name;
683         static pstring pw_passwd;
684         static struct passwd pw_ret;
685
686         if (pass == NULL)
687         {
688                 return NULL;
689         }
690
691         memcpy((char *)&pw_ret, pass, sizeof(struct passwd));
692
693         if (pass->pw_name)
694         {
695                 pw_ret.pw_name = pw_name;
696                 pstrcpy(pw_ret.pw_name, pass->pw_name);
697         }
698
699         if (pass->pw_passwd)
700         {
701                 pw_ret.pw_passwd = pw_passwd;
702                 pstrcpy(pw_ret.pw_passwd, pass->pw_passwd);
703         }
704
705         return &pw_ret;
706 }
707
708 /**************************************************************************
709  Wrapper for getpwnam(). Always returns a static that can be modified.
710 ****************************************************************************/
711
712 struct passwd *sys_getpwnam(const char *name)
713 {
714         return setup_pwret(getpwnam(name));
715 }
716
717 /**************************************************************************
718  Wrapper for getpwuid(). Always returns a static that can be modified.
719 ****************************************************************************/
720
721 struct passwd *sys_getpwuid(uid_t uid)
722 {
723         return setup_pwret(getpwuid(uid));
724 }