r11383: Patch from Alex Masterov <alex@infobit.ru> to fix
[tprouty/samba.git] / source / lib / system.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison  1998-2005
6    Copyright (C) Timur Bakeyev        2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /*
26    The idea is that this file will eventually have wrappers around all
27    important system calls in samba. The aims are:
28
29    - to enable easier porting by putting OS dependent stuff in here
30
31    - to allow for hooks into other "pseudo-filesystems"
32
33    - to allow easier integration of things like the japanese extensions
34
35    - to support the philosophy of Samba to expose the features of
36      the OS within the SMB model. In general whatever file/printer/variable
37      expansions/etc make sense to the OS should be acceptable to Samba.
38 */
39
40
41
42 /*******************************************************************
43  A wrapper for usleep in case we don't have one.
44 ********************************************************************/
45
46 int sys_usleep(long usecs)
47 {
48 #ifndef HAVE_USLEEP
49         struct timeval tval;
50 #endif
51
52         /*
53          * We need this braindamage as the glibc usleep
54          * is not SPEC1170 complient... grumble... JRA.
55          */
56
57         if(usecs < 0 || usecs > 1000000) {
58                 errno = EINVAL;
59                 return -1;
60         }
61
62 #if HAVE_USLEEP
63         usleep(usecs);
64         return 0;
65 #else /* HAVE_USLEEP */
66         /*
67          * Fake it with select...
68          */
69         tval.tv_sec = 0;
70         tval.tv_usec = usecs/1000;
71         select(0,NULL,NULL,NULL,&tval);
72         return 0;
73 #endif /* HAVE_USLEEP */
74 }
75
76 /*******************************************************************
77 A read wrapper that will deal with EINTR.
78 ********************************************************************/
79
80 ssize_t sys_read(int fd, void *buf, size_t count)
81 {
82         ssize_t ret;
83
84         do {
85                 ret = read(fd, buf, count);
86         } while (ret == -1 && errno == EINTR);
87         return ret;
88 }
89
90 /*******************************************************************
91 A write wrapper that will deal with EINTR.
92 ********************************************************************/
93
94 ssize_t sys_write(int fd, const void *buf, size_t count)
95 {
96         ssize_t ret;
97
98         do {
99                 ret = write(fd, buf, count);
100         } while (ret == -1 && errno == EINTR);
101         return ret;
102 }
103
104
105 /*******************************************************************
106 A pread wrapper that will deal with EINTR and 64-bit file offsets.
107 ********************************************************************/
108
109 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
110 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
111 {
112         ssize_t ret;
113
114         do {
115 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
116                 ret = pread64(fd, buf, count, off);
117 #else
118                 ret = pread(fd, buf, count, off);
119 #endif
120         } while (ret == -1 && errno == EINTR);
121         return ret;
122 }
123 #endif
124
125 /*******************************************************************
126 A write wrapper that will deal with EINTR and 64-bit file offsets.
127 ********************************************************************/
128
129 #if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
130 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
131 {
132         ssize_t ret;
133
134         do {
135 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
136                 ret = pwrite64(fd, buf, count, off);
137 #else
138                 ret = pwrite(fd, buf, count, off);
139 #endif
140         } while (ret == -1 && errno == EINTR);
141         return ret;
142 }
143 #endif
144
145 /*******************************************************************
146 A send wrapper that will deal with EINTR.
147 ********************************************************************/
148
149 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
150 {
151         ssize_t ret;
152
153         do {
154                 ret = send(s, msg, len, flags);
155         } while (ret == -1 && errno == EINTR);
156         return ret;
157 }
158
159 /*******************************************************************
160 A sendto wrapper that will deal with EINTR.
161 ********************************************************************/
162
163 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
164 {
165         ssize_t ret;
166
167         do {
168                 ret = sendto(s, msg, len, flags, to, tolen);
169         } while (ret == -1 && errno == EINTR);
170         return ret;
171 }
172
173 /*******************************************************************
174 A recvfrom wrapper that will deal with EINTR.
175 ********************************************************************/
176
177 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
178 {
179         ssize_t ret;
180
181         do {
182                 ret = recvfrom(s, buf, len, flags, from, fromlen);
183         } while (ret == -1 && errno == EINTR);
184         return ret;
185 }
186
187 /*******************************************************************
188 A fcntl wrapper that will deal with EINTR.
189 ********************************************************************/
190
191 int sys_fcntl_ptr(int fd, int cmd, void *arg)
192 {
193         int ret;
194
195         do {
196                 ret = fcntl(fd, cmd, arg);
197         } while (ret == -1 && errno == EINTR);
198         return ret;
199 }
200
201 /*******************************************************************
202 A fcntl wrapper that will deal with EINTR.
203 ********************************************************************/
204
205 int sys_fcntl_long(int fd, int cmd, long arg)
206 {
207         int ret;
208
209         do {
210                 ret = fcntl(fd, cmd, arg);
211         } while (ret == -1 && errno == EINTR);
212         return ret;
213 }
214
215 /*******************************************************************
216 A stat() wrapper that will deal with 64 bit filesizes.
217 ********************************************************************/
218
219 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
220 {
221         int ret;
222 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
223         ret = stat64(fname, sbuf);
224 #else
225         ret = stat(fname, sbuf);
226 #endif
227         /* we always want directories to appear zero size */
228         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
229         return ret;
230 }
231
232 /*******************************************************************
233  An fstat() wrapper that will deal with 64 bit filesizes.
234 ********************************************************************/
235
236 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
237 {
238         int ret;
239 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
240         ret = fstat64(fd, sbuf);
241 #else
242         ret = fstat(fd, sbuf);
243 #endif
244         /* we always want directories to appear zero size */
245         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
246         return ret;
247 }
248
249 /*******************************************************************
250  An lstat() wrapper that will deal with 64 bit filesizes.
251 ********************************************************************/
252
253 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
254 {
255         int ret;
256 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
257         ret = lstat64(fname, sbuf);
258 #else
259         ret = lstat(fname, sbuf);
260 #endif
261         /* we always want directories to appear zero size */
262         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
263         return ret;
264 }
265
266 /*******************************************************************
267  An ftruncate() wrapper that will deal with 64 bit filesizes.
268 ********************************************************************/
269
270 int sys_ftruncate(int fd, SMB_OFF_T offset)
271 {
272 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
273         return ftruncate64(fd, offset);
274 #else
275         return ftruncate(fd, offset);
276 #endif
277 }
278
279 /*******************************************************************
280  An lseek() wrapper that will deal with 64 bit filesizes.
281 ********************************************************************/
282
283 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
284 {
285 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
286         return lseek64(fd, offset, whence);
287 #else
288         return lseek(fd, offset, whence);
289 #endif
290 }
291
292 /*******************************************************************
293  An fseek() wrapper that will deal with 64 bit filesizes.
294 ********************************************************************/
295
296 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
297 {
298 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
299         return fseek64(fp, offset, whence);
300 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
301         return fseeko64(fp, offset, whence);
302 #else
303         return fseek(fp, offset, whence);
304 #endif
305 }
306
307 /*******************************************************************
308  An ftell() wrapper that will deal with 64 bit filesizes.
309 ********************************************************************/
310
311 SMB_OFF_T sys_ftell(FILE *fp)
312 {
313 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
314         return (SMB_OFF_T)ftell64(fp);
315 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
316         return (SMB_OFF_T)ftello64(fp);
317 #else
318         return (SMB_OFF_T)ftell(fp);
319 #endif
320 }
321
322 /*******************************************************************
323  A creat() wrapper that will deal with 64 bit filesizes.
324 ********************************************************************/
325
326 int sys_creat(const char *path, mode_t mode)
327 {
328 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
329         return creat64(path, mode);
330 #else
331         /*
332          * If creat64 isn't defined then ensure we call a potential open64.
333          * JRA.
334          */
335         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
336 #endif
337 }
338
339 /*******************************************************************
340  An open() wrapper that will deal with 64 bit filesizes.
341 ********************************************************************/
342
343 int sys_open(const char *path, int oflag, mode_t mode)
344 {
345 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
346         return open64(path, oflag, mode);
347 #else
348         return open(path, oflag, mode);
349 #endif
350 }
351
352 /*******************************************************************
353  An fopen() wrapper that will deal with 64 bit filesizes.
354 ********************************************************************/
355
356 FILE *sys_fopen(const char *path, const char *type)
357 {
358 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
359         return fopen64(path, type);
360 #else
361         return fopen(path, type);
362 #endif
363 }
364
365 /*******************************************************************
366  An opendir wrapper that will deal with 64 bit filesizes.
367 ********************************************************************/
368
369 SMB_STRUCT_DIR *sys_opendir(const char *name)
370 {
371 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
372         return opendir64(name);
373 #else
374         return opendir(name);
375 #endif
376 }
377
378 /*******************************************************************
379  A readdir wrapper that will deal with 64 bit filesizes.
380 ********************************************************************/
381
382 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
383 {
384 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
385         return readdir64(dirp);
386 #else
387         return readdir(dirp);
388 #endif
389 }
390
391 /*******************************************************************
392  A seekdir wrapper that will deal with 64 bit filesizes.
393 ********************************************************************/
394
395 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
396 {
397 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
398         seekdir64(dirp, offset);
399 #else
400         seekdir(dirp, offset);
401 #endif
402 }
403
404 /*******************************************************************
405  A telldir wrapper that will deal with 64 bit filesizes.
406 ********************************************************************/
407
408 long sys_telldir(SMB_STRUCT_DIR *dirp)
409 {
410 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
411         return (long)telldir64(dirp);
412 #else
413         return (long)telldir(dirp);
414 #endif
415 }
416
417 /*******************************************************************
418  A rewinddir wrapper that will deal with 64 bit filesizes.
419 ********************************************************************/
420
421 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
422 {
423 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
424         rewinddir64(dirp);
425 #else
426         rewinddir(dirp);
427 #endif
428 }
429
430 /*******************************************************************
431  A close wrapper that will deal with 64 bit filesizes.
432 ********************************************************************/
433
434 int sys_closedir(SMB_STRUCT_DIR *dirp)
435 {
436 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
437         return closedir64(dirp);
438 #else
439         return closedir(dirp);
440 #endif
441 }
442
443 /*******************************************************************
444  An mknod() wrapper that will deal with 64 bit filesizes.
445 ********************************************************************/
446
447 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
448 {
449 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
450 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
451         return mknod64(path, mode, dev);
452 #else
453         return mknod(path, mode, dev);
454 #endif
455 #else
456         /* No mknod system call. */
457         errno = ENOSYS;
458         return -1;
459 #endif
460 }
461
462 /*******************************************************************
463  Wrapper for realpath.
464 ********************************************************************/
465
466 char *sys_realpath(const char *path, char *resolved_path)
467 {
468 #if defined(HAVE_REALPATH)
469         return realpath(path, resolved_path);
470 #else
471         /* As realpath is not a system call we can't return ENOSYS. */
472         errno = EINVAL;
473         return NULL;
474 #endif
475 }
476
477 /*******************************************************************
478 The wait() calls vary between systems
479 ********************************************************************/
480
481 int sys_waitpid(pid_t pid,int *status,int options)
482 {
483 #ifdef HAVE_WAITPID
484         return waitpid(pid,status,options);
485 #else /* HAVE_WAITPID */
486         return wait4(pid, status, options, NULL);
487 #endif /* HAVE_WAITPID */
488 }
489
490 /*******************************************************************
491  System wrapper for getwd
492 ********************************************************************/
493
494 char *sys_getwd(char *s)
495 {
496         char *wd;
497 #ifdef HAVE_GETCWD
498         wd = (char *)getcwd(s, sizeof (pstring));
499 #else
500         wd = (char *)getwd(s);
501 #endif
502         return wd;
503 }
504
505 /*******************************************************************
506 system wrapper for symlink
507 ********************************************************************/
508
509 int sys_symlink(const char *oldpath, const char *newpath)
510 {
511 #ifndef HAVE_SYMLINK
512         errno = ENOSYS;
513         return -1;
514 #else
515         return symlink(oldpath, newpath);
516 #endif
517 }
518
519 /*******************************************************************
520 system wrapper for readlink
521 ********************************************************************/
522
523 int sys_readlink(const char *path, char *buf, size_t bufsiz)
524 {
525 #ifndef HAVE_READLINK
526         errno = ENOSYS;
527         return -1;
528 #else
529         return readlink(path, buf, bufsiz);
530 #endif
531 }
532
533 /*******************************************************************
534 system wrapper for link
535 ********************************************************************/
536
537 int sys_link(const char *oldpath, const char *newpath)
538 {
539 #ifndef HAVE_LINK
540         errno = ENOSYS;
541         return -1;
542 #else
543         return link(oldpath, newpath);
544 #endif
545 }
546
547 /*******************************************************************
548 chown isn't used much but OS/2 doesn't have it
549 ********************************************************************/
550
551 int sys_chown(const char *fname,uid_t uid,gid_t gid)
552 {
553 #ifndef HAVE_CHOWN
554         static int done;
555         if (!done) {
556                 DEBUG(1,("WARNING: no chown!\n"));
557                 done=1;
558         }
559         errno = ENOSYS;
560         return -1;
561 #else
562         return(chown(fname,uid,gid));
563 #endif
564 }
565
566 /*******************************************************************
567 os/2 also doesn't have chroot
568 ********************************************************************/
569 int sys_chroot(const char *dname)
570 {
571 #ifndef HAVE_CHROOT
572         static int done;
573         if (!done) {
574                 DEBUG(1,("WARNING: no chroot!\n"));
575                 done=1;
576         }
577         errno = ENOSYS;
578         return -1;
579 #else
580         return(chroot(dname));
581 #endif
582 }
583
584 /**************************************************************************
585 A wrapper for gethostbyname() that tries avoids looking up hostnames 
586 in the root domain, which can cause dial-on-demand links to come up for no
587 apparent reason.
588 ****************************************************************************/
589
590 struct hostent *sys_gethostbyname(const char *name)
591 {
592 #ifdef REDUCE_ROOT_DNS_LOOKUPS
593         char query[256], hostname[256];
594         char *domain;
595
596         /* Does this name have any dots in it? If so, make no change */
597
598         if (strchr_m(name, '.'))
599                 return(gethostbyname(name));
600
601         /* Get my hostname, which should have domain name 
602                 attached. If not, just do the gethostname on the
603                 original string. 
604         */
605
606         gethostname(hostname, sizeof(hostname) - 1);
607         hostname[sizeof(hostname) - 1] = 0;
608         if ((domain = strchr_m(hostname, '.')) == NULL)
609                 return(gethostbyname(name));
610
611         /* Attach domain name to query and do modified query.
612                 If names too large, just do gethostname on the
613                 original string.
614         */
615
616         if((strlen(name) + strlen(domain)) >= sizeof(query))
617                 return(gethostbyname(name));
618
619         slprintf(query, sizeof(query)-1, "%s%s", name, domain);
620         return(gethostbyname(query));
621 #else /* REDUCE_ROOT_DNS_LOOKUPS */
622         return(gethostbyname(name));
623 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
624 }
625
626
627 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
628 /**************************************************************************
629  Try and abstract process capabilities (for systems that have them).
630 ****************************************************************************/
631 static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
632 {
633         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
634                 cap_t cap = cap_get_proc();
635
636                 if (cap == NULL) {
637                         DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
638                                 strerror(errno)));
639                         return False;
640                 }
641
642                 if(enable)
643                         cap->cap_effective |= CAP_NETWORK_MGT;
644                 else
645                         cap->cap_effective &= ~CAP_NETWORK_MGT;
646
647                 if (cap_set_proc(cap) == -1) {
648                         DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
649                                 strerror(errno)));
650                         cap_free(cap);
651                         return False;
652                 }
653
654                 cap_free(cap);
655
656                 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
657         }
658         return True;
659 }
660
661 /**************************************************************************
662  Try and abstract inherited process capabilities (for systems that have them).
663 ****************************************************************************/
664
665 static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
666 {
667         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
668                 cap_t cap = cap_get_proc();
669
670                 if (cap == NULL) {
671                         DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
672                                 strerror(errno)));
673                         return False;
674                 }
675
676                 if(enable)
677                         cap->cap_inheritable |= CAP_NETWORK_MGT;
678                 else
679                         cap->cap_inheritable &= ~CAP_NETWORK_MGT;
680
681                 if (cap_set_proc(cap) == -1) {
682                         DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
683                                 strerror(errno)));
684                         cap_free(cap);
685                         return False;
686                 }
687
688                 cap_free(cap);
689
690                 DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
691         }
692         return True;
693 }
694 #endif
695
696 /****************************************************************************
697  Gain the oplock capability from the kernel if possible.
698 ****************************************************************************/
699
700 void oplock_set_capability(BOOL this_process, BOOL inherit)
701 {
702 #if HAVE_KERNEL_OPLOCKS_IRIX
703         set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
704         set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
705 #endif
706 }
707
708 /**************************************************************************
709  Wrapper for random().
710 ****************************************************************************/
711
712 long sys_random(void)
713 {
714 #if defined(HAVE_RANDOM)
715         return (long)random();
716 #elif defined(HAVE_RAND)
717         return (long)rand();
718 #else
719         DEBUG(0,("Error - no random function available !\n"));
720         exit(1);
721 #endif
722 }
723
724 /**************************************************************************
725  Wrapper for srandom().
726 ****************************************************************************/
727
728 void sys_srandom(unsigned int seed)
729 {
730 #if defined(HAVE_SRANDOM)
731         srandom(seed);
732 #elif defined(HAVE_SRAND)
733         srand(seed);
734 #else
735         DEBUG(0,("Error - no srandom function available !\n"));
736         exit(1);
737 #endif
738 }
739
740 /**************************************************************************
741  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
742 ****************************************************************************/
743
744 int groups_max(void)
745 {
746 #if defined(SYSCONF_SC_NGROUPS_MAX)
747         int ret = sysconf(_SC_NGROUPS_MAX);
748         return (ret == -1) ? NGROUPS_MAX : ret;
749 #else
750         return NGROUPS_MAX;
751 #endif
752 }
753
754 /**************************************************************************
755  Wrapper for getgroups. Deals with broken (int) case.
756 ****************************************************************************/
757
758 int sys_getgroups(int setlen, gid_t *gidset)
759 {
760 #if !defined(HAVE_BROKEN_GETGROUPS)
761         return getgroups(setlen, gidset);
762 #else
763
764         GID_T gid;
765         GID_T *group_list;
766         int i, ngroups;
767
768         if(setlen == 0) {
769                 return getgroups(setlen, &gid);
770         }
771
772         /*
773          * Broken case. We need to allocate a
774          * GID_T array of size setlen.
775          */
776
777         if(setlen < 0) {
778                 errno = EINVAL; 
779                 return -1;
780         } 
781
782         if (setlen == 0)
783                 setlen = groups_max();
784
785         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
786                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
787                 return -1;
788         }
789
790         if((ngroups = getgroups(setlen, group_list)) < 0) {
791                 int saved_errno = errno;
792                 SAFE_FREE(group_list);
793                 errno = saved_errno;
794                 return -1;
795         }
796
797         for(i = 0; i < ngroups; i++)
798                 gidset[i] = (gid_t)group_list[i];
799
800         SAFE_FREE(group_list);
801         return ngroups;
802 #endif /* HAVE_BROKEN_GETGROUPS */
803 }
804
805
806 /**************************************************************************
807  Wrapper for setgroups. Deals with broken (int) case. Automatically used
808  if we have broken getgroups.
809 ****************************************************************************/
810
811 int sys_setgroups(int setlen, gid_t *gidset)
812 {
813 #if !defined(HAVE_SETGROUPS)
814         errno = ENOSYS;
815         return -1;
816 #endif /* HAVE_SETGROUPS */
817
818 #if !defined(HAVE_BROKEN_GETGROUPS)
819         return setgroups(setlen, gidset);
820 #else
821
822         GID_T *group_list;
823         int i ; 
824
825         if (setlen == 0)
826                 return 0 ;
827
828         if (setlen < 0 || setlen > groups_max()) {
829                 errno = EINVAL; 
830                 return -1;   
831         }
832
833         /*
834          * Broken case. We need to allocate a
835          * GID_T array of size setlen.
836          */
837
838         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
839                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
840                 return -1;    
841         }
842  
843         for(i = 0; i < setlen; i++) 
844                 group_list[i] = (GID_T) gidset[i]; 
845
846         if(setgroups(setlen, group_list) != 0) {
847                 int saved_errno = errno;
848                 SAFE_FREE(group_list);
849                 errno = saved_errno;
850                 return -1;
851         }
852  
853         SAFE_FREE(group_list);
854         return 0 ;
855 #endif /* HAVE_BROKEN_GETGROUPS */
856 }
857
858 /**************************************************************************
859  Wrappers for setpwent(), getpwent() and endpwent()
860 ****************************************************************************/
861
862 void sys_setpwent(void)
863 {
864         setpwent();
865 }
866
867 struct passwd *sys_getpwent(void)
868 {
869         return getpwent();
870 }
871
872 void sys_endpwent(void)
873 {
874         endpwent();
875 }
876
877 /**************************************************************************
878  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
879 ****************************************************************************/
880
881 struct passwd *sys_getpwnam(const char *name)
882 {
883         return getpwnam(name);
884 }
885
886 struct passwd *sys_getpwuid(uid_t uid)
887 {
888         return getpwuid(uid);
889 }
890
891 struct group *sys_getgrnam(const char *name)
892 {
893         return getgrnam(name);
894 }
895
896 struct group *sys_getgrgid(gid_t gid)
897 {
898         return getgrgid(gid);
899 }
900
901 #if 0 /* NOT CURRENTLY USED - JRA */
902 /**************************************************************************
903  The following are the UNICODE versions of *all* system interface functions
904  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
905  which currently are left as ascii as they are not used other than in name
906  resolution.
907 ****************************************************************************/
908
909 /**************************************************************************
910  Wide stat. Just narrow and call sys_xxx.
911 ****************************************************************************/
912
913 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
914 {
915         pstring fname;
916         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
917 }
918
919 /**************************************************************************
920  Wide lstat. Just narrow and call sys_xxx.
921 ****************************************************************************/
922
923 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
924 {
925         pstring fname;
926         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
927 }
928
929 /**************************************************************************
930  Wide creat. Just narrow and call sys_xxx.
931 ****************************************************************************/
932
933 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
934 {
935         pstring fname;
936         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
937 }
938
939 /**************************************************************************
940  Wide open. Just narrow and call sys_xxx.
941 ****************************************************************************/
942
943 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
944 {
945         pstring fname;
946         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
947 }
948
949 /**************************************************************************
950  Wide fopen. Just narrow and call sys_xxx.
951 ****************************************************************************/
952
953 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
954 {
955         pstring fname;
956         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
957 }
958
959 /**************************************************************************
960  Wide opendir. Just narrow and call sys_xxx.
961 ****************************************************************************/
962
963 SMB_STRUCT_DIR *wsys_opendir(const smb_ucs2_t *wfname)
964 {
965         pstring fname;
966         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
967 }
968
969 /**************************************************************************
970  Wide readdir. Return a structure pointer containing a wide filename.
971 ****************************************************************************/
972
973 SMB_STRUCT_WDIRENT *wsys_readdir(SMB_STRUCT_DIR *dirp)
974 {
975         static SMB_STRUCT_WDIRENT retval;
976         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
977
978         if(!dirval)
979                 return NULL;
980
981         /*
982          * The only POSIX defined member of this struct is d_name.
983          */
984
985         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
986
987         return &retval;
988 }
989
990 /**************************************************************************
991  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
992 ****************************************************************************/
993
994 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
995 {
996         pstring fname;
997         char *p = sys_getwd(fname);
998
999         if(!p)
1000                 return NULL;
1001
1002         return unix_to_unicode(s, p, sizeof(wpstring));
1003 }
1004
1005 /**************************************************************************
1006  Wide chown. Just narrow and call sys_xxx.
1007 ****************************************************************************/
1008
1009 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
1010 {
1011         pstring fname;
1012         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
1013 }
1014
1015 /**************************************************************************
1016  Wide chroot. Just narrow and call sys_xxx.
1017 ****************************************************************************/
1018
1019 int wsys_chroot(const smb_ucs2_t *wfname)
1020 {
1021         pstring fname;
1022         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
1023 }
1024
1025 /**************************************************************************
1026  Wide getpwnam. Return a structure pointer containing wide names.
1027 ****************************************************************************/
1028
1029 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
1030 {
1031         static SMB_STRUCT_WPASSWD retval;
1032         fstring name;
1033         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
1034
1035         if(!pwret)
1036                 return NULL;
1037
1038         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
1039         retval.pw_passwd = pwret->pw_passwd;
1040         retval.pw_uid = pwret->pw_uid;
1041         retval.pw_gid = pwret->pw_gid;
1042         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
1043         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
1044         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
1045
1046         return &retval;
1047 }
1048
1049 /**************************************************************************
1050  Wide getpwuid. Return a structure pointer containing wide names.
1051 ****************************************************************************/
1052
1053 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
1054 {
1055         static SMB_STRUCT_WPASSWD retval;
1056         struct passwd *pwret = sys_getpwuid(uid);
1057
1058         if(!pwret)
1059                 return NULL;
1060
1061         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
1062         retval.pw_passwd = pwret->pw_passwd;
1063         retval.pw_uid = pwret->pw_uid;
1064         retval.pw_gid = pwret->pw_gid;
1065         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
1066         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
1067         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
1068
1069         return &retval;
1070 }
1071 #endif /* NOT CURRENTLY USED - JRA */
1072
1073 /**************************************************************************
1074  Extract a command into an arg list. Uses a static pstring for storage.
1075  Caller frees returned arg list (which contains pointers into the static pstring).
1076 ****************************************************************************/
1077
1078 static char **extract_args(const char *command)
1079 {
1080         static pstring trunc_cmd;
1081         char *ptr;
1082         int argcl;
1083         char **argl = NULL;
1084         int i;
1085
1086         pstrcpy(trunc_cmd, command);
1087
1088         if(!(ptr = strtok(trunc_cmd, " \t"))) {
1089                 errno = EINVAL;
1090                 return NULL;
1091         }
1092
1093         /*
1094          * Count the args.
1095          */
1096
1097         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
1098                 argcl++;
1099
1100         if((argl = (char **)SMB_MALLOC((argcl + 1) * sizeof(char *))) == NULL)
1101                 return NULL;
1102
1103         /*
1104          * Now do the extraction.
1105          */
1106
1107         pstrcpy(trunc_cmd, command);
1108
1109         ptr = strtok(trunc_cmd, " \t");
1110         i = 0;
1111         argl[i++] = ptr;
1112
1113         while((ptr = strtok(NULL, " \t")) != NULL)
1114                 argl[i++] = ptr;
1115
1116         argl[i++] = NULL;
1117         return argl;
1118 }
1119
1120 /**************************************************************************
1121  Wrapper for fork. Ensures that mypid is reset. Used so we can write
1122  a sys_getpid() that only does a system call *once*.
1123 ****************************************************************************/
1124
1125 static pid_t mypid = (pid_t)-1;
1126
1127 pid_t sys_fork(void)
1128 {
1129         pid_t forkret = fork();
1130
1131         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
1132                 mypid = (pid_t) -1;
1133
1134         return forkret;
1135 }
1136
1137 /**************************************************************************
1138  Wrapper for getpid. Ensures we only do a system call *once*.
1139 ****************************************************************************/
1140
1141 pid_t sys_getpid(void)
1142 {
1143         if (mypid == (pid_t)-1)
1144                 mypid = getpid();
1145
1146         return mypid;
1147 }
1148
1149 /**************************************************************************
1150  Wrapper for popen. Safer as it doesn't search a path.
1151  Modified from the glibc sources.
1152  modified by tridge to return a file descriptor. We must kick our FILE* habit
1153 ****************************************************************************/
1154
1155 typedef struct _popen_list
1156 {
1157         int fd;
1158         pid_t child_pid;
1159         struct _popen_list *next;
1160 } popen_list;
1161
1162 static popen_list *popen_chain;
1163
1164 int sys_popen(const char *command)
1165 {
1166         int parent_end, child_end;
1167         int pipe_fds[2];
1168         popen_list *entry = NULL;
1169         char **argl = NULL;
1170
1171         if (pipe(pipe_fds) < 0)
1172                 return -1;
1173
1174         parent_end = pipe_fds[0];
1175         child_end = pipe_fds[1];
1176
1177         if (!*command) {
1178                 errno = EINVAL;
1179                 goto err_exit;
1180         }
1181
1182         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1183                 goto err_exit;
1184
1185         ZERO_STRUCTP(entry);
1186
1187         /*
1188          * Extract the command and args into a NULL terminated array.
1189          */
1190
1191         if(!(argl = extract_args(command)))
1192                 goto err_exit;
1193
1194         entry->child_pid = sys_fork();
1195
1196         if (entry->child_pid == -1) {
1197                 goto err_exit;
1198         }
1199
1200         if (entry->child_pid == 0) {
1201
1202                 /*
1203                  * Child !
1204                  */
1205
1206                 int child_std_end = STDOUT_FILENO;
1207                 popen_list *p;
1208
1209                 close(parent_end);
1210                 if (child_end != child_std_end) {
1211                         dup2 (child_end, child_std_end);
1212                         close (child_end);
1213                 }
1214
1215                 /*
1216                  * POSIX.2:  "popen() shall ensure that any streams from previous
1217                  * popen() calls that remain open in the parent process are closed
1218                  * in the new child process."
1219                  */
1220
1221                 for (p = popen_chain; p; p = p->next)
1222                         close(p->fd);
1223
1224                 execv(argl[0], argl);
1225                 _exit (127);
1226         }
1227
1228         /*
1229          * Parent.
1230          */
1231
1232         close (child_end);
1233         SAFE_FREE(argl);
1234
1235         /* Link into popen_chain. */
1236         entry->next = popen_chain;
1237         popen_chain = entry;
1238         entry->fd = parent_end;
1239
1240         return entry->fd;
1241
1242 err_exit:
1243
1244         SAFE_FREE(entry);
1245         SAFE_FREE(argl);
1246         close(pipe_fds[0]);
1247         close(pipe_fds[1]);
1248         return -1;
1249 }
1250
1251 /**************************************************************************
1252  Wrapper for pclose. Modified from the glibc sources.
1253 ****************************************************************************/
1254
1255 int sys_pclose(int fd)
1256 {
1257         int wstatus;
1258         popen_list **ptr = &popen_chain;
1259         popen_list *entry = NULL;
1260         pid_t wait_pid;
1261         int status = -1;
1262
1263         /* Unlink from popen_chain. */
1264         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1265                 if ((*ptr)->fd == fd) {
1266                         entry = *ptr;
1267                         *ptr = (*ptr)->next;
1268                         status = 0;
1269                         break;
1270                 }
1271         }
1272
1273         if (status < 0 || close(entry->fd) < 0)
1274                 return -1;
1275
1276         /*
1277          * As Samba is catching and eating child process
1278          * exits we don't really care about the child exit
1279          * code, a -1 with errno = ECHILD will do fine for us.
1280          */
1281
1282         do {
1283                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1284         } while (wait_pid == -1 && errno == EINTR);
1285
1286         SAFE_FREE(entry);
1287
1288         if (wait_pid == -1)
1289                 return -1;
1290         return wstatus;
1291 }
1292
1293 /**************************************************************************
1294  Wrappers for dlopen, dlsym, dlclose.
1295 ****************************************************************************/
1296
1297 void *sys_dlopen(const char *name, int flags)
1298 {
1299 #if defined(HAVE_DLOPEN)
1300         return dlopen(name, flags);
1301 #else
1302         return NULL;
1303 #endif
1304 }
1305
1306 void *sys_dlsym(void *handle, const char *symbol)
1307 {
1308 #if defined(HAVE_DLSYM)
1309     return dlsym(handle, symbol);
1310 #else
1311     return NULL;
1312 #endif
1313 }
1314
1315 int sys_dlclose (void *handle)
1316 {
1317 #if defined(HAVE_DLCLOSE)
1318         return dlclose(handle);
1319 #else
1320         return 0;
1321 #endif
1322 }
1323
1324 const char *sys_dlerror(void)
1325 {
1326 #if defined(HAVE_DLERROR)
1327         return dlerror();
1328 #else
1329         return NULL;
1330 #endif
1331 }
1332
1333 int sys_dup2(int oldfd, int newfd) 
1334 {
1335 #if defined(HAVE_DUP2)
1336         return dup2(oldfd, newfd);
1337 #else
1338         errno = ENOSYS;
1339         return -1;
1340 #endif
1341 }
1342
1343 /**************************************************************************
1344  Wrapper for Admin Logs.
1345 ****************************************************************************/
1346
1347  void sys_adminlog(int priority, const char *format_str, ...) 
1348 {
1349         va_list ap;
1350         int ret;
1351         char *msgbuf = NULL;
1352
1353         va_start( ap, format_str );
1354         ret = vasprintf( &msgbuf, format_str, ap );
1355         va_end( ap );
1356
1357         if (ret == -1)
1358                 return;
1359
1360 #if defined(HAVE_SYSLOG)
1361         syslog( priority, "%s", msgbuf );
1362 #else
1363         DEBUG(0,("%s", msgbuf ));
1364 #endif
1365         SAFE_FREE(msgbuf);
1366 }
1367
1368 /**************************************************************************
1369  Wrappers for extented attribute calls. Based on the Linux package with
1370  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1371 ****************************************************************************/
1372
1373 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1374 {
1375 #if defined(HAVE_GETXATTR)
1376         return getxattr(path, name, value, size);
1377 #elif defined(HAVE_EXTATTR_GET_FILE)
1378         char *s;
1379         ssize_t retval;
1380         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1381                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1382         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1383         /*
1384          * The BSD implementation has a nasty habit of silently truncating
1385          * the returned value to the size of the buffer, so we have to check
1386          * that the buffer is large enough to fit the returned value.
1387          */
1388         retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1389
1390         if(retval > size) {
1391                 errno = ERANGE;
1392                 return -1;
1393         }
1394
1395         return extattr_get_file(path, attrnamespace, attrname, value, size);
1396 #elif defined(HAVE_ATTR_GET)
1397         int retval, flags = 0;
1398         int valuelength = (int)size;
1399         char *attrname = strchr(name,'.') + 1;
1400         
1401         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1402
1403         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1404
1405         return retval ? retval : valuelength;
1406 #else
1407         errno = ENOSYS;
1408         return -1;
1409 #endif
1410 }
1411
1412 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1413 {
1414 #if defined(HAVE_LGETXATTR)
1415         return lgetxattr(path, name, value, size);
1416 #elif defined(HAVE_EXTATTR_GET_LINK)
1417         char *s;
1418         ssize_t retval;
1419         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1420                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1421         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1422
1423         retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
1424
1425         if(retval > size) {
1426                 errno = ERANGE;
1427                 return -1;
1428         }
1429
1430         return extattr_get_link(path, attrnamespace, attrname, value, size);
1431 #elif defined(HAVE_ATTR_GET)
1432         int retval, flags = ATTR_DONTFOLLOW;
1433         int valuelength = (int)size;
1434         char *attrname = strchr(name,'.') + 1;
1435         
1436         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1437
1438         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1439
1440         return retval ? retval : valuelength;
1441 #else
1442         errno = ENOSYS;
1443         return -1;
1444 #endif
1445 }
1446
1447 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1448 {
1449 #if defined(HAVE_FGETXATTR)
1450         return fgetxattr(filedes, name, value, size);
1451 #elif defined(HAVE_EXTATTR_GET_FD)
1452         char *s;
1453         ssize_t retval;
1454         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1455                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1456         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1457
1458         retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
1459
1460         if(retval > size) {
1461                 errno = ERANGE;
1462                 return -1;
1463         }
1464
1465         return extattr_get_fd(filedes, attrnamespace, attrname, value, size);
1466 #elif defined(HAVE_ATTR_GETF)
1467         int retval, flags = 0;
1468         int valuelength = (int)size;
1469         char *attrname = strchr(name,'.') + 1;
1470         
1471         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1472
1473         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1474
1475         return retval ? retval : valuelength;
1476 #else
1477         errno = ENOSYS;
1478         return -1;
1479 #endif
1480 }
1481
1482 #if defined(HAVE_EXTATTR_LIST_FILE)
1483
1484 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1485
1486 static struct {
1487         int space;
1488         const char *name;
1489         size_t len;
1490
1491 extattr[] = {
1492         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1493         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1494 };
1495
1496 typedef union {
1497         const char *path;
1498         int filedes;
1499 } extattr_arg;
1500
1501 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1502 {
1503         ssize_t list_size, total_size = 0;
1504         int i, t, len;
1505         char *buf;
1506         /* Iterate through extattr(2) namespaces */
1507         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1508                 switch(type) {
1509 #if defined(HAVE_EXTATTR_LIST_FILE)
1510                         case 0:
1511                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1512                                 break;
1513 #endif
1514 #if defined(HAVE_EXTATTR_LIST_LINK)
1515                         case 1:
1516                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1517                                 break;
1518 #endif
1519 #if defined(HAVE_EXTATTR_LIST_FD)
1520                         case 2:
1521                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1522                                 break;
1523 #endif
1524                         default:
1525                                 errno = ENOSYS;
1526                                 return -1;
1527                 }
1528                 /* Some error happend. Errno should be set by the previous call */
1529                 if(list_size < 0)
1530                         return -1;
1531                 /* No attributes */
1532                 if(list_size == 0)
1533                         continue;
1534                 /* XXX: Call with an empty buffer may be used to calculate
1535                    necessary buffer size. Unfortunately, we can't say, how
1536                    many attributes were returned, so here is the potential
1537                    problem with the emulation.
1538                 */
1539                 if(list == NULL) {
1540                         /* Take the worse case of one char attribute names - 
1541                            two bytes per name plus one more for sanity.
1542                         */
1543                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1544                         continue;
1545                 }
1546                 /* Count necessary offset to fit namespace prefixes */
1547                 len = 0;
1548                 for(i = 0; i < list_size; i += list[i] + 1)
1549                         len += extattr[t].len;
1550
1551                 total_size += list_size + len;
1552                 /* Buffer is too small to fit the results */
1553                 if(total_size > size) {
1554                         errno = ERANGE;
1555                         return -1;
1556                 }
1557                 /* Shift the results back, so we can prepend prefixes */
1558                 buf = memmove(list + len, list, list_size);
1559
1560                 for(i = 0; i < list_size; i += len + 1) {
1561                         len = buf[i];
1562                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1563                         list += extattr[t].len;
1564                         strncpy(list, buf + i + 1, len);
1565                         list[len] = '\0';
1566                         list += len + 1;
1567                 }
1568                 size -= total_size;
1569         }
1570         return total_size;
1571 }
1572
1573 #endif
1574
1575 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1576 static char attr_buffer[ATTR_MAX_VALUELEN];
1577
1578 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1579 {
1580         int retval = 0, index;
1581         attrlist_cursor_t *cursor = 0;
1582         int total_size = 0;
1583         attrlist_t * al = (attrlist_t *)attr_buffer;
1584         attrlist_ent_t *ae;
1585         size_t ent_size, left = size;
1586         char *bp = list;
1587
1588         while (True) {
1589             if (filedes)
1590                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1591             else
1592                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1593             if (retval) break;
1594             for (index = 0; index < al->al_count; index++) {
1595                 ae = ATTR_ENTRY(attr_buffer, index);
1596                 ent_size = strlen(ae->a_name) + sizeof("user.");
1597                 if (left >= ent_size) {
1598                     strncpy(bp, "user.", sizeof("user."));
1599                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1600                     bp += ent_size;
1601                     left -= ent_size;
1602                 } else if (size) {
1603                     errno = ERANGE;
1604                     retval = -1;
1605                     break;
1606                 }
1607                 total_size += ent_size;
1608             }
1609             if (al->al_more == 0) break;
1610         }
1611         if (retval == 0) {
1612             flags |= ATTR_ROOT;
1613             cursor = 0;
1614             while (True) {
1615                 if (filedes)
1616                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1617                 else
1618                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1619                 if (retval) break;
1620                 for (index = 0; index < al->al_count; index++) {
1621                     ae = ATTR_ENTRY(attr_buffer, index);
1622                     ent_size = strlen(ae->a_name) + sizeof("system.");
1623                     if (left >= ent_size) {
1624                         strncpy(bp, "system.", sizeof("system."));
1625                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1626                         bp += ent_size;
1627                         left -= ent_size;
1628                     } else if (size) {
1629                         errno = ERANGE;
1630                         retval = -1;
1631                         break;
1632                     }
1633                     total_size += ent_size;
1634                 }
1635                 if (al->al_more == 0) break;
1636             }
1637         }
1638         return (ssize_t)(retval ? retval : total_size);
1639 }
1640
1641 #endif
1642
1643 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1644 {
1645 #if defined(HAVE_LISTXATTR)
1646         return listxattr(path, list, size);
1647 #elif defined(HAVE_EXTATTR_LIST_FILE)
1648         extattr_arg arg;
1649         arg.path = path;
1650         return bsd_attr_list(0, arg, list, size);
1651 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1652         return irix_attr_list(path, 0, list, size, 0);
1653 #else
1654         errno = ENOSYS;
1655         return -1;
1656 #endif
1657 }
1658
1659 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1660 {
1661 #if defined(HAVE_LLISTXATTR)
1662         return llistxattr(path, list, size);
1663 #elif defined(HAVE_EXTATTR_LIST_LINK)
1664         extattr_arg arg;
1665         arg.path = path;
1666         return bsd_attr_list(1, arg, list, size);
1667 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1668         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1669 #else
1670         errno = ENOSYS;
1671         return -1;
1672 #endif
1673 }
1674
1675 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1676 {
1677 #if defined(HAVE_FLISTXATTR)
1678         return flistxattr(filedes, list, size);
1679 #elif defined(HAVE_EXTATTR_LIST_FD)
1680         extattr_arg arg;
1681         arg.filedes = filedes;
1682         return bsd_attr_list(2, arg, list, size);
1683 #elif defined(HAVE_ATTR_LISTF)
1684         return irix_attr_list(NULL, filedes, list, size, 0);
1685 #else
1686         errno = ENOSYS;
1687         return -1;
1688 #endif
1689 }
1690
1691 int sys_removexattr (const char *path, const char *name)
1692 {
1693 #if defined(HAVE_REMOVEXATTR)
1694         return removexattr(path, name);
1695 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1696         char *s;
1697         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1698                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1699         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1700
1701         return extattr_delete_file(path, attrnamespace, attrname);
1702 #elif defined(HAVE_ATTR_REMOVE)
1703         int flags = 0;
1704         char *attrname = strchr(name,'.') + 1;
1705         
1706         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1707
1708         return attr_remove(path, attrname, flags);
1709 #else
1710         errno = ENOSYS;
1711         return -1;
1712 #endif
1713 }
1714
1715 int sys_lremovexattr (const char *path, const char *name)
1716 {
1717 #if defined(HAVE_LREMOVEXATTR)
1718         return lremovexattr(path, name);
1719 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1720         char *s;
1721         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1722                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1723         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1724
1725         return extattr_delete_link(path, attrnamespace, attrname);
1726 #elif defined(HAVE_ATTR_REMOVE)
1727         int flags = ATTR_DONTFOLLOW;
1728         char *attrname = strchr(name,'.') + 1;
1729         
1730         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1731
1732         return attr_remove(path, attrname, flags);
1733 #else
1734         errno = ENOSYS;
1735         return -1;
1736 #endif
1737 }
1738
1739 int sys_fremovexattr (int filedes, const char *name)
1740 {
1741 #if defined(HAVE_FREMOVEXATTR)
1742         return fremovexattr(filedes, name);
1743 #elif defined(HAVE_EXTATTR_DELETE_FD)
1744         char *s;
1745         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1746                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1747         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1748
1749         return extattr_delete_fd(filedes, attrnamespace, attrname);
1750 #elif defined(HAVE_ATTR_REMOVEF)
1751         int flags = 0;
1752         char *attrname = strchr(name,'.') + 1;
1753         
1754         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1755
1756         return attr_removef(filedes, attrname, flags);
1757 #else
1758         errno = ENOSYS;
1759         return -1;
1760 #endif
1761 }
1762
1763 #if !defined(HAVE_SETXATTR)
1764 #define XATTR_CREATE  0x1       /* set value, fail if attr already exists */
1765 #define XATTR_REPLACE 0x2       /* set value, fail if attr does not exist */
1766 #endif
1767
1768 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1769 {
1770 #if defined(HAVE_SETXATTR)
1771         return setxattr(path, name, value, size, flags);
1772 #elif defined(HAVE_EXTATTR_SET_FILE)
1773         char *s;
1774         int retval = 0;
1775         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1776                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1777         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1778         if (flags) {
1779                 /* Check attribute existence */
1780                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1781                 if (retval < 0) {
1782                         /* REPLACE attribute, that doesn't exist */
1783                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1784                                 errno = ENOATTR;
1785                                 return -1;
1786                         }
1787                 }
1788                 else {
1789                         /* CREATE attribute, that already exists */
1790                         if (flags & XATTR_CREATE) {
1791                                 errno = EEXIST;
1792                                 return -1;
1793                         }
1794                 }
1795         }
1796         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
1797         return (retval < 0) ? -1 : 0;
1798 #elif defined(HAVE_ATTR_SET)
1799         int myflags = 0;
1800         char *attrname = strchr(name,'.') + 1;
1801         
1802         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1803         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1804         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1805
1806         return attr_set(path, attrname, (const char *)value, size, myflags);
1807 #else
1808         errno = ENOSYS;
1809         return -1;
1810 #endif
1811 }
1812
1813 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1814 {
1815 #if defined(HAVE_LSETXATTR)
1816         return lsetxattr(path, name, value, size, flags);
1817 #elif defined(HAVE_EXTATTR_SET_LINK)
1818         char *s;
1819         int retval = 0;
1820         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1821                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1822         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1823         if (flags) {
1824                 /* Check attribute existence */
1825                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
1826                 if (retval < 0) {
1827                         /* REPLACE attribute, that doesn't exist */
1828                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1829                                 errno = ENOATTR;
1830                                 return -1;
1831                         }
1832                 }
1833                 else {
1834                         /* CREATE attribute, that already exists */
1835                         if (flags & XATTR_CREATE) {
1836                                 errno = EEXIST;
1837                                 return -1;
1838                         }
1839                 }
1840         }
1841
1842         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
1843         return (retval < 0) ? -1 : 0;
1844 #elif defined(HAVE_ATTR_SET)
1845         int myflags = ATTR_DONTFOLLOW;
1846         char *attrname = strchr(name,'.') + 1;
1847         
1848         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1849         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1850         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1851
1852         return attr_set(path, attrname, (const char *)value, size, myflags);
1853 #else
1854         errno = ENOSYS;
1855         return -1;
1856 #endif
1857 }
1858
1859 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
1860 {
1861 #if defined(HAVE_FSETXATTR)
1862         return fsetxattr(filedes, name, value, size, flags);
1863 #elif defined(HAVE_EXTATTR_SET_FD)
1864         char *s;
1865         int retval = 0;
1866         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1867                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1868         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1869         if (flags) {
1870                 /* Check attribute existence */
1871                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
1872                 if (retval < 0) {
1873                         /* REPLACE attribute, that doesn't exist */
1874                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1875                                 errno = ENOATTR;
1876                                 return -1;
1877                         }
1878                 }
1879                 else {
1880                         /* CREATE attribute, that already exists */
1881                         if (flags & XATTR_CREATE) {
1882                                 errno = EEXIST;
1883                                 return -1;
1884                         }
1885                 }
1886         }
1887         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
1888         return (retval < 0) ? -1 : 0;
1889 #elif defined(HAVE_ATTR_SETF)
1890         int myflags = 0;
1891         char *attrname = strchr(name,'.') + 1;
1892         
1893         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1894         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1895         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1896
1897         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
1898 #else
1899         errno = ENOSYS;
1900         return -1;
1901 #endif
1902 }
1903
1904 /****************************************************************************
1905  Return the major devicenumber for UNIX extensions.
1906 ****************************************************************************/
1907                                                                                                                 
1908 uint32 unix_dev_major(SMB_DEV_T dev)
1909 {
1910 #if defined(HAVE_DEVICE_MAJOR_FN)
1911         return (uint32)major(dev);
1912 #else
1913         return (uint32)(dev >> 8);
1914 #endif
1915 }
1916                                                                                                                 
1917 /****************************************************************************
1918  Return the minor devicenumber for UNIX extensions.
1919 ****************************************************************************/
1920                                                                                                                 
1921 uint32 unix_dev_minor(SMB_DEV_T dev)
1922 {
1923 #if defined(HAVE_DEVICE_MINOR_FN)
1924         return (uint32)minor(dev);
1925 #else
1926         return (uint32)(dev & 0xff);
1927 #endif
1928 }
1929
1930 #if defined(WITH_AIO)
1931
1932 /*******************************************************************
1933  An aio_read wrapper that will deal with 64-bit sizes.
1934 ********************************************************************/
1935                                                                                                                                            
1936 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
1937 {
1938 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
1939         return aio_read64(aiocb);
1940 #elif defined(HAVE_AIO_READ)
1941         return aio_read(aiocb);
1942 #else
1943         errno = ENOSYS;
1944         return -1;
1945 #endif
1946 }
1947
1948 /*******************************************************************
1949  An aio_write wrapper that will deal with 64-bit sizes.
1950 ********************************************************************/
1951                                                                                                                                            
1952 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
1953 {
1954 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
1955         return aio_write64(aiocb);
1956 #elif defined(HAVE_AIO_WRITE)
1957         return aio_write(aiocb);
1958 #else
1959         errno = ENOSYS;
1960         return -1;
1961 #endif
1962 }
1963
1964 /*******************************************************************
1965  An aio_return wrapper that will deal with 64-bit sizes.
1966 ********************************************************************/
1967                                                                                                                                            
1968 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
1969 {
1970 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
1971         return aio_return64(aiocb);
1972 #elif defined(HAVE_AIO_RETURN)
1973         return aio_return(aiocb);
1974 #else
1975         errno = ENOSYS;
1976         return -1;
1977 #endif
1978 }
1979
1980 /*******************************************************************
1981  An aio_cancel wrapper that will deal with 64-bit sizes.
1982 ********************************************************************/
1983
1984 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
1985 {
1986 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
1987         return aio_cancel64(fd, aiocb);
1988 #elif defined(HAVE_AIO_CANCEL)
1989         return aio_cancel(fd, aiocb);
1990 #else
1991         errno = ENOSYS;
1992         return -1;
1993 #endif
1994 }
1995
1996 /*******************************************************************
1997  An aio_error wrapper that will deal with 64-bit sizes.
1998 ********************************************************************/
1999
2000 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2001 {
2002 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2003         return aio_error64(aiocb);
2004 #elif defined(HAVE_AIO_ERROR)
2005         return aio_error(aiocb);
2006 #else
2007         errno = ENOSYS;
2008         return -1;
2009 #endif
2010 }
2011
2012 /*******************************************************************
2013  An aio_fsync wrapper that will deal with 64-bit sizes.
2014 ********************************************************************/
2015
2016 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2017 {
2018 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2019         return aio_fsync64(op, aiocb);
2020 #elif defined(HAVE_AIO_FSYNC)
2021         return aio_fsync(op, aiocb);
2022 #else
2023         errno = ENOSYS;
2024         return -1;
2025 #endif
2026 }
2027
2028 /*******************************************************************
2029  An aio_fsync wrapper that will deal with 64-bit sizes.
2030 ********************************************************************/
2031
2032 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2033 {
2034 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2035         return aio_suspend64(cblist, n, timeout);
2036 #elif defined(HAVE_AIO_FSYNC)
2037         return aio_suspend(cblist, n, timeout);
2038 #else
2039         errno = ENOSYS;
2040         return -1;
2041 #endif
2042 }
2043 #else /* !WITH_AIO */
2044
2045 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2046 {
2047         errno = ENOSYS;
2048         return -1;
2049 }
2050
2051 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2052 {
2053         errno = ENOSYS;
2054         return -1;
2055 }
2056
2057 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2058 {
2059         errno = ENOSYS;
2060         return -1;
2061 }
2062
2063 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2064 {
2065         errno = ENOSYS;
2066         return -1;
2067 }
2068
2069 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2070 {
2071         errno = ENOSYS;
2072         return -1;
2073 }
2074
2075 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2076 {
2077         errno = ENOSYS;
2078         return -1;
2079 }
2080
2081 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2082 {
2083         errno = ENOSYS;
2084         return -1;
2085 }
2086 #endif /* WITH_AIO */