r11845: Removed error code list as it isn't correct for Linux.
[kai/samba.git] / source3 / 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         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1389                 if(retval > size) {
1390                         errno = ERANGE;
1391                         return -1;
1392                 }
1393                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1394                         return retval;
1395         }
1396
1397         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1398         return -1;
1399 #elif defined(HAVE_ATTR_GET)
1400         int retval, flags = 0;
1401         int valuelength = (int)size;
1402         char *attrname = strchr(name,'.') + 1;
1403         
1404         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1405
1406         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1407
1408         return retval ? retval : valuelength;
1409 #else
1410         errno = ENOSYS;
1411         return -1;
1412 #endif
1413 }
1414
1415 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1416 {
1417 #if defined(HAVE_LGETXATTR)
1418         return lgetxattr(path, name, value, size);
1419 #elif defined(HAVE_EXTATTR_GET_LINK)
1420         char *s;
1421         ssize_t retval;
1422         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1423                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1424         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1425
1426         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1427                 if(retval > size) {
1428                         errno = ERANGE;
1429                         return -1;
1430                 }
1431                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1432                         return retval;
1433         }
1434         
1435         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1436         return -1;
1437 #elif defined(HAVE_ATTR_GET)
1438         int retval, flags = ATTR_DONTFOLLOW;
1439         int valuelength = (int)size;
1440         char *attrname = strchr(name,'.') + 1;
1441         
1442         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1443
1444         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1445
1446         return retval ? retval : valuelength;
1447 #else
1448         errno = ENOSYS;
1449         return -1;
1450 #endif
1451 }
1452
1453 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1454 {
1455 #if defined(HAVE_FGETXATTR)
1456         return fgetxattr(filedes, name, value, size);
1457 #elif defined(HAVE_EXTATTR_GET_FD)
1458         char *s;
1459         ssize_t retval;
1460         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1461                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1462         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1463
1464         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1465                 if(retval > size) {
1466                         errno = ERANGE;
1467                         return -1;
1468                 }
1469                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1470                         return retval;
1471         }
1472         
1473         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1474         return -1;
1475 #elif defined(HAVE_ATTR_GETF)
1476         int retval, flags = 0;
1477         int valuelength = (int)size;
1478         char *attrname = strchr(name,'.') + 1;
1479         
1480         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1481
1482         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1483
1484         return retval ? retval : valuelength;
1485 #else
1486         errno = ENOSYS;
1487         return -1;
1488 #endif
1489 }
1490
1491 #if defined(HAVE_EXTATTR_LIST_FILE)
1492
1493 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1494
1495 static struct {
1496         int space;
1497         const char *name;
1498         size_t len;
1499
1500 extattr[] = {
1501         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1502         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1503 };
1504
1505 typedef union {
1506         const char *path;
1507         int filedes;
1508 } extattr_arg;
1509
1510 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1511 {
1512         ssize_t list_size, total_size = 0;
1513         int i, t, len;
1514         char *buf;
1515         /* Iterate through extattr(2) namespaces */
1516         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1517                 switch(type) {
1518 #if defined(HAVE_EXTATTR_LIST_FILE)
1519                         case 0:
1520                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1521                                 break;
1522 #endif
1523 #if defined(HAVE_EXTATTR_LIST_LINK)
1524                         case 1:
1525                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1526                                 break;
1527 #endif
1528 #if defined(HAVE_EXTATTR_LIST_FD)
1529                         case 2:
1530                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1531                                 break;
1532 #endif
1533                         default:
1534                                 errno = ENOSYS;
1535                                 return -1;
1536                 }
1537                 /* Some error happend. Errno should be set by the previous call */
1538                 if(list_size < 0)
1539                         return -1;
1540                 /* No attributes */
1541                 if(list_size == 0)
1542                         continue;
1543                 /* XXX: Call with an empty buffer may be used to calculate
1544                    necessary buffer size. Unfortunately, we can't say, how
1545                    many attributes were returned, so here is the potential
1546                    problem with the emulation.
1547                 */
1548                 if(list == NULL) {
1549                         /* Take the worse case of one char attribute names - 
1550                            two bytes per name plus one more for sanity.
1551                         */
1552                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1553                         continue;
1554                 }
1555                 /* Count necessary offset to fit namespace prefixes */
1556                 len = 0;
1557                 for(i = 0; i < list_size; i += list[i] + 1)
1558                         len += extattr[t].len;
1559
1560                 total_size += list_size + len;
1561                 /* Buffer is too small to fit the results */
1562                 if(total_size > size) {
1563                         errno = ERANGE;
1564                         return -1;
1565                 }
1566                 /* Shift results back, so we can prepend prefixes */
1567                 buf = memmove(list + len, list, list_size);
1568
1569                 for(i = 0; i < list_size; i += len + 1) {
1570                         len = buf[i];
1571                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1572                         list += extattr[t].len;
1573                         strncpy(list, buf + i + 1, len);
1574                         list[len] = '\0';
1575                         list += len + 1;
1576                 }
1577                 size -= total_size;
1578         }
1579         return total_size;
1580 }
1581
1582 #endif
1583
1584 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1585 static char attr_buffer[ATTR_MAX_VALUELEN];
1586
1587 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1588 {
1589         int retval = 0, index;
1590         attrlist_cursor_t *cursor = 0;
1591         int total_size = 0;
1592         attrlist_t * al = (attrlist_t *)attr_buffer;
1593         attrlist_ent_t *ae;
1594         size_t ent_size, left = size;
1595         char *bp = list;
1596
1597         while (True) {
1598             if (filedes)
1599                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1600             else
1601                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1602             if (retval) break;
1603             for (index = 0; index < al->al_count; index++) {
1604                 ae = ATTR_ENTRY(attr_buffer, index);
1605                 ent_size = strlen(ae->a_name) + sizeof("user.");
1606                 if (left >= ent_size) {
1607                     strncpy(bp, "user.", sizeof("user."));
1608                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1609                     bp += ent_size;
1610                     left -= ent_size;
1611                 } else if (size) {
1612                     errno = ERANGE;
1613                     retval = -1;
1614                     break;
1615                 }
1616                 total_size += ent_size;
1617             }
1618             if (al->al_more == 0) break;
1619         }
1620         if (retval == 0) {
1621             flags |= ATTR_ROOT;
1622             cursor = 0;
1623             while (True) {
1624                 if (filedes)
1625                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1626                 else
1627                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1628                 if (retval) break;
1629                 for (index = 0; index < al->al_count; index++) {
1630                     ae = ATTR_ENTRY(attr_buffer, index);
1631                     ent_size = strlen(ae->a_name) + sizeof("system.");
1632                     if (left >= ent_size) {
1633                         strncpy(bp, "system.", sizeof("system."));
1634                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1635                         bp += ent_size;
1636                         left -= ent_size;
1637                     } else if (size) {
1638                         errno = ERANGE;
1639                         retval = -1;
1640                         break;
1641                     }
1642                     total_size += ent_size;
1643                 }
1644                 if (al->al_more == 0) break;
1645             }
1646         }
1647         return (ssize_t)(retval ? retval : total_size);
1648 }
1649
1650 #endif
1651
1652 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1653 {
1654 #if defined(HAVE_LISTXATTR)
1655         return listxattr(path, list, size);
1656 #elif defined(HAVE_EXTATTR_LIST_FILE)
1657         extattr_arg arg;
1658         arg.path = path;
1659         return bsd_attr_list(0, arg, list, size);
1660 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1661         return irix_attr_list(path, 0, list, size, 0);
1662 #else
1663         errno = ENOSYS;
1664         return -1;
1665 #endif
1666 }
1667
1668 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1669 {
1670 #if defined(HAVE_LLISTXATTR)
1671         return llistxattr(path, list, size);
1672 #elif defined(HAVE_EXTATTR_LIST_LINK)
1673         extattr_arg arg;
1674         arg.path = path;
1675         return bsd_attr_list(1, arg, list, size);
1676 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1677         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1678 #else
1679         errno = ENOSYS;
1680         return -1;
1681 #endif
1682 }
1683
1684 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1685 {
1686 #if defined(HAVE_FLISTXATTR)
1687         return flistxattr(filedes, list, size);
1688 #elif defined(HAVE_EXTATTR_LIST_FD)
1689         extattr_arg arg;
1690         arg.filedes = filedes;
1691         return bsd_attr_list(2, arg, list, size);
1692 #elif defined(HAVE_ATTR_LISTF)
1693         return irix_attr_list(NULL, filedes, list, size, 0);
1694 #else
1695         errno = ENOSYS;
1696         return -1;
1697 #endif
1698 }
1699
1700 int sys_removexattr (const char *path, const char *name)
1701 {
1702 #if defined(HAVE_REMOVEXATTR)
1703         return removexattr(path, name);
1704 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1705         char *s;
1706         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1707                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1708         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1709
1710         return extattr_delete_file(path, attrnamespace, attrname);
1711 #elif defined(HAVE_ATTR_REMOVE)
1712         int flags = 0;
1713         char *attrname = strchr(name,'.') + 1;
1714         
1715         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1716
1717         return attr_remove(path, attrname, flags);
1718 #else
1719         errno = ENOSYS;
1720         return -1;
1721 #endif
1722 }
1723
1724 int sys_lremovexattr (const char *path, const char *name)
1725 {
1726 #if defined(HAVE_LREMOVEXATTR)
1727         return lremovexattr(path, name);
1728 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1729         char *s;
1730         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1731                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1732         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1733
1734         return extattr_delete_link(path, attrnamespace, attrname);
1735 #elif defined(HAVE_ATTR_REMOVE)
1736         int flags = ATTR_DONTFOLLOW;
1737         char *attrname = strchr(name,'.') + 1;
1738         
1739         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1740
1741         return attr_remove(path, attrname, flags);
1742 #else
1743         errno = ENOSYS;
1744         return -1;
1745 #endif
1746 }
1747
1748 int sys_fremovexattr (int filedes, const char *name)
1749 {
1750 #if defined(HAVE_FREMOVEXATTR)
1751         return fremovexattr(filedes, name);
1752 #elif defined(HAVE_EXTATTR_DELETE_FD)
1753         char *s;
1754         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1755                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1756         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1757
1758         return extattr_delete_fd(filedes, attrnamespace, attrname);
1759 #elif defined(HAVE_ATTR_REMOVEF)
1760         int flags = 0;
1761         char *attrname = strchr(name,'.') + 1;
1762         
1763         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1764
1765         return attr_removef(filedes, attrname, flags);
1766 #else
1767         errno = ENOSYS;
1768         return -1;
1769 #endif
1770 }
1771
1772 #if !defined(HAVE_SETXATTR)
1773 #define XATTR_CREATE  0x1       /* set value, fail if attr already exists */
1774 #define XATTR_REPLACE 0x2       /* set value, fail if attr does not exist */
1775 #endif
1776
1777 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1778 {
1779 #if defined(HAVE_SETXATTR)
1780         return setxattr(path, name, value, size, flags);
1781 #elif defined(HAVE_EXTATTR_SET_FILE)
1782         char *s;
1783         int retval = 0;
1784         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1785                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1786         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1787         if (flags) {
1788                 /* Check attribute existence */
1789                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1790                 if (retval < 0) {
1791                         /* REPLACE attribute, that doesn't exist */
1792                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1793                                 errno = ENOATTR;
1794                                 return -1;
1795                         }
1796                         /* Ignore other errors */
1797                 }
1798                 else {
1799                         /* CREATE attribute, that already exists */
1800                         if (flags & XATTR_CREATE) {
1801                                 errno = EEXIST;
1802                                 return -1;
1803                         }
1804                 }
1805         }
1806         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
1807         return (retval < 0) ? -1 : 0;
1808 #elif defined(HAVE_ATTR_SET)
1809         int myflags = 0;
1810         char *attrname = strchr(name,'.') + 1;
1811         
1812         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1813         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1814         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1815
1816         return attr_set(path, attrname, (const char *)value, size, myflags);
1817 #else
1818         errno = ENOSYS;
1819         return -1;
1820 #endif
1821 }
1822
1823 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1824 {
1825 #if defined(HAVE_LSETXATTR)
1826         return lsetxattr(path, name, value, size, flags);
1827 #elif defined(HAVE_EXTATTR_SET_LINK)
1828         char *s;
1829         int retval = 0;
1830         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1831                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1832         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1833         if (flags) {
1834                 /* Check attribute existence */
1835                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
1836                 if (retval < 0) {
1837                         /* REPLACE attribute, that doesn't exist */
1838                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1839                                 errno = ENOATTR;
1840                                 return -1;
1841                         }
1842                         /* Ignore other errors */
1843                 }
1844                 else {
1845                         /* CREATE attribute, that already exists */
1846                         if (flags & XATTR_CREATE) {
1847                                 errno = EEXIST;
1848                                 return -1;
1849                         }
1850                 }
1851         }
1852
1853         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
1854         return (retval < 0) ? -1 : 0;
1855 #elif defined(HAVE_ATTR_SET)
1856         int myflags = ATTR_DONTFOLLOW;
1857         char *attrname = strchr(name,'.') + 1;
1858         
1859         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1860         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1861         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1862
1863         return attr_set(path, attrname, (const char *)value, size, myflags);
1864 #else
1865         errno = ENOSYS;
1866         return -1;
1867 #endif
1868 }
1869
1870 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
1871 {
1872 #if defined(HAVE_FSETXATTR)
1873         return fsetxattr(filedes, name, value, size, flags);
1874 #elif defined(HAVE_EXTATTR_SET_FD)
1875         char *s;
1876         int retval = 0;
1877         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1878                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1879         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1880         if (flags) {
1881                 /* Check attribute existence */
1882                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
1883                 if (retval < 0) {
1884                         /* REPLACE attribute, that doesn't exist */
1885                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1886                                 errno = ENOATTR;
1887                                 return -1;
1888                         }
1889                         /* Ignore other errors */
1890                 }
1891                 else {
1892                         /* CREATE attribute, that already exists */
1893                         if (flags & XATTR_CREATE) {
1894                                 errno = EEXIST;
1895                                 return -1;
1896                         }
1897                 }
1898         }
1899         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
1900         return (retval < 0) ? -1 : 0;
1901 #elif defined(HAVE_ATTR_SETF)
1902         int myflags = 0;
1903         char *attrname = strchr(name,'.') + 1;
1904         
1905         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1906         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1907         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1908
1909         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
1910 #else
1911         errno = ENOSYS;
1912         return -1;
1913 #endif
1914 }
1915
1916 /****************************************************************************
1917  Return the major devicenumber for UNIX extensions.
1918 ****************************************************************************/
1919                                                                                                                 
1920 uint32 unix_dev_major(SMB_DEV_T dev)
1921 {
1922 #if defined(HAVE_DEVICE_MAJOR_FN)
1923         return (uint32)major(dev);
1924 #else
1925         return (uint32)(dev >> 8);
1926 #endif
1927 }
1928                                                                                                                 
1929 /****************************************************************************
1930  Return the minor devicenumber for UNIX extensions.
1931 ****************************************************************************/
1932                                                                                                                 
1933 uint32 unix_dev_minor(SMB_DEV_T dev)
1934 {
1935 #if defined(HAVE_DEVICE_MINOR_FN)
1936         return (uint32)minor(dev);
1937 #else
1938         return (uint32)(dev & 0xff);
1939 #endif
1940 }
1941
1942 #if defined(WITH_AIO)
1943
1944 /*******************************************************************
1945  An aio_read wrapper that will deal with 64-bit sizes.
1946 ********************************************************************/
1947                                                                                                                                            
1948 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
1949 {
1950 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
1951         return aio_read64(aiocb);
1952 #elif defined(HAVE_AIO_READ)
1953         return aio_read(aiocb);
1954 #else
1955         errno = ENOSYS;
1956         return -1;
1957 #endif
1958 }
1959
1960 /*******************************************************************
1961  An aio_write wrapper that will deal with 64-bit sizes.
1962 ********************************************************************/
1963                                                                                                                                            
1964 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
1965 {
1966 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
1967         return aio_write64(aiocb);
1968 #elif defined(HAVE_AIO_WRITE)
1969         return aio_write(aiocb);
1970 #else
1971         errno = ENOSYS;
1972         return -1;
1973 #endif
1974 }
1975
1976 /*******************************************************************
1977  An aio_return wrapper that will deal with 64-bit sizes.
1978 ********************************************************************/
1979                                                                                                                                            
1980 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
1981 {
1982 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
1983         return aio_return64(aiocb);
1984 #elif defined(HAVE_AIO_RETURN)
1985         return aio_return(aiocb);
1986 #else
1987         errno = ENOSYS;
1988         return -1;
1989 #endif
1990 }
1991
1992 /*******************************************************************
1993  An aio_cancel wrapper that will deal with 64-bit sizes.
1994 ********************************************************************/
1995
1996 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
1997 {
1998 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
1999         return aio_cancel64(fd, aiocb);
2000 #elif defined(HAVE_AIO_CANCEL)
2001         return aio_cancel(fd, aiocb);
2002 #else
2003         errno = ENOSYS;
2004         return -1;
2005 #endif
2006 }
2007
2008 /*******************************************************************
2009  An aio_error wrapper that will deal with 64-bit sizes.
2010 ********************************************************************/
2011
2012 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2013 {
2014 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2015         return aio_error64(aiocb);
2016 #elif defined(HAVE_AIO_ERROR)
2017         return aio_error(aiocb);
2018 #else
2019         errno = ENOSYS;
2020         return -1;
2021 #endif
2022 }
2023
2024 /*******************************************************************
2025  An aio_fsync wrapper that will deal with 64-bit sizes.
2026 ********************************************************************/
2027
2028 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2029 {
2030 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2031         return aio_fsync64(op, aiocb);
2032 #elif defined(HAVE_AIO_FSYNC)
2033         return aio_fsync(op, aiocb);
2034 #else
2035         errno = ENOSYS;
2036         return -1;
2037 #endif
2038 }
2039
2040 /*******************************************************************
2041  An aio_fsync wrapper that will deal with 64-bit sizes.
2042 ********************************************************************/
2043
2044 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2045 {
2046 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2047         return aio_suspend64(cblist, n, timeout);
2048 #elif defined(HAVE_AIO_FSYNC)
2049         return aio_suspend(cblist, n, timeout);
2050 #else
2051         errno = ENOSYS;
2052         return -1;
2053 #endif
2054 }
2055 #else /* !WITH_AIO */
2056
2057 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2058 {
2059         errno = ENOSYS;
2060         return -1;
2061 }
2062
2063 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2064 {
2065         errno = ENOSYS;
2066         return -1;
2067 }
2068
2069 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2070 {
2071         errno = ENOSYS;
2072         return -1;
2073 }
2074
2075 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2076 {
2077         errno = ENOSYS;
2078         return -1;
2079 }
2080
2081 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2082 {
2083         errno = ENOSYS;
2084         return -1;
2085 }
2086
2087 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2088 {
2089         errno = ENOSYS;
2090         return -1;
2091 }
2092
2093 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2094 {
2095         errno = ENOSYS;
2096         return -1;
2097 }
2098 #endif /* WITH_AIO */