Move sys_readlink() to libreplace.
[amitay/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    Copyright (C) Bjoern Jacke    2006-2007
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24
25 #ifdef HAVE_SYS_PRCTL_H
26 #include <sys/prctl.h>
27 #endif
28
29 /*
30    The idea is that this file will eventually have wrappers around all
31    important system calls in samba. The aims are:
32
33    - to enable easier porting by putting OS dependent stuff in here
34
35    - to allow for hooks into other "pseudo-filesystems"
36
37    - to allow easier integration of things like the japanese extensions
38
39    - to support the philosophy of Samba to expose the features of
40      the OS within the SMB model. In general whatever file/printer/variable
41      expansions/etc make sense to the OS should be acceptable to Samba.
42 */
43
44
45
46 /*******************************************************************
47  A wrapper for memalign
48 ********************************************************************/
49
50 void *sys_memalign( size_t align, size_t size )
51 {
52 #if defined(HAVE_POSIX_MEMALIGN)
53         void *p = NULL;
54         int ret = posix_memalign( &p, align, size );
55         if ( ret == 0 )
56                 return p;
57                 
58         return NULL;
59 #elif defined(HAVE_MEMALIGN)
60         return memalign( align, size );
61 #else
62         /* On *BSD systems memaligns doesn't exist, but memory will
63          * be aligned on allocations of > pagesize. */
64 #if defined(SYSCONF_SC_PAGESIZE)
65         size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
66 #elif defined(HAVE_GETPAGESIZE)
67         size_t pagesize = (size_t)getpagesize();
68 #else
69         size_t pagesize = (size_t)-1;
70 #endif
71         if (pagesize == (size_t)-1) {
72                 DEBUG(0,("memalign functionalaity not available on this platform!\n"));
73                 return NULL;
74         }
75         if (size < pagesize) {
76                 size = pagesize;
77         }
78         return SMB_MALLOC(size);
79 #endif
80 }
81
82 /*******************************************************************
83  A wrapper for usleep in case we don't have one.
84 ********************************************************************/
85
86 int sys_usleep(long usecs)
87 {
88 #ifndef HAVE_USLEEP
89         struct timeval tval;
90 #endif
91
92         /*
93          * We need this braindamage as the glibc usleep
94          * is not SPEC1170 complient... grumble... JRA.
95          */
96
97         if(usecs < 0 || usecs > 1000000) {
98                 errno = EINVAL;
99                 return -1;
100         }
101
102 #if HAVE_USLEEP
103         usleep(usecs);
104         return 0;
105 #else /* HAVE_USLEEP */
106         /*
107          * Fake it with select...
108          */
109         tval.tv_sec = 0;
110         tval.tv_usec = usecs/1000;
111         select(0,NULL,NULL,NULL,&tval);
112         return 0;
113 #endif /* HAVE_USLEEP */
114 }
115
116 /*******************************************************************
117 A read wrapper that will deal with EINTR.
118 ********************************************************************/
119
120 ssize_t sys_read(int fd, void *buf, size_t count)
121 {
122         ssize_t ret;
123
124         do {
125                 ret = read(fd, buf, count);
126         } while (ret == -1 && errno == EINTR);
127         return ret;
128 }
129
130 /*******************************************************************
131 A write wrapper that will deal with EINTR.
132 ********************************************************************/
133
134 ssize_t sys_write(int fd, const void *buf, size_t count)
135 {
136         ssize_t ret;
137
138         do {
139                 ret = write(fd, buf, count);
140         } while (ret == -1 && errno == EINTR);
141         return ret;
142 }
143
144 /*******************************************************************
145 A pread wrapper that will deal with EINTR and 64-bit file offsets.
146 ********************************************************************/
147
148 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
149 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
150 {
151         ssize_t ret;
152
153         do {
154 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
155                 ret = pread64(fd, buf, count, off);
156 #else
157                 ret = pread(fd, buf, count, off);
158 #endif
159         } while (ret == -1 && errno == EINTR);
160         return ret;
161 }
162 #endif
163
164 /*******************************************************************
165 A write wrapper that will deal with EINTR and 64-bit file offsets.
166 ********************************************************************/
167
168 #if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
169 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
170 {
171         ssize_t ret;
172
173         do {
174 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
175                 ret = pwrite64(fd, buf, count, off);
176 #else
177                 ret = pwrite(fd, buf, count, off);
178 #endif
179         } while (ret == -1 && errno == EINTR);
180         return ret;
181 }
182 #endif
183
184 /*******************************************************************
185 A send wrapper that will deal with EINTR.
186 ********************************************************************/
187
188 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
189 {
190         ssize_t ret;
191
192         do {
193                 ret = send(s, msg, len, flags);
194         } while (ret == -1 && errno == EINTR);
195         return ret;
196 }
197
198 /*******************************************************************
199 A sendto wrapper that will deal with EINTR.
200 ********************************************************************/
201
202 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
203 {
204         ssize_t ret;
205
206         do {
207                 ret = sendto(s, msg, len, flags, to, tolen);
208         } while (ret == -1 && errno == EINTR);
209         return ret;
210 }
211
212 /*******************************************************************
213 A recv wrapper that will deal with EINTR.
214 ********************************************************************/
215
216 ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
217 {
218         ssize_t ret;
219
220         do {
221                 ret = recv(fd, buf, count, flags);
222         } while (ret == -1 && errno == EINTR);
223         return ret;
224 }
225
226 /*******************************************************************
227 A recvfrom wrapper that will deal with EINTR.
228 ********************************************************************/
229
230 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
231 {
232         ssize_t ret;
233
234         do {
235                 ret = recvfrom(s, buf, len, flags, from, fromlen);
236         } while (ret == -1 && errno == EINTR);
237         return ret;
238 }
239
240 /*******************************************************************
241 A fcntl wrapper that will deal with EINTR.
242 ********************************************************************/
243
244 int sys_fcntl_ptr(int fd, int cmd, void *arg)
245 {
246         int ret;
247
248         do {
249                 ret = fcntl(fd, cmd, arg);
250         } while (ret == -1 && errno == EINTR);
251         return ret;
252 }
253
254 /*******************************************************************
255 A fcntl wrapper that will deal with EINTR.
256 ********************************************************************/
257
258 int sys_fcntl_long(int fd, int cmd, long arg)
259 {
260         int ret;
261
262         do {
263                 ret = fcntl(fd, cmd, arg);
264         } while (ret == -1 && errno == EINTR);
265         return ret;
266 }
267
268 /*******************************************************************
269 A stat() wrapper that will deal with 64 bit filesizes.
270 ********************************************************************/
271
272 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
273 {
274         int ret;
275 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
276         ret = stat64(fname, sbuf);
277 #else
278         ret = stat(fname, sbuf);
279 #endif
280         /* we always want directories to appear zero size */
281         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
282         return ret;
283 }
284
285 /*******************************************************************
286  An fstat() wrapper that will deal with 64 bit filesizes.
287 ********************************************************************/
288
289 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
290 {
291         int ret;
292 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
293         ret = fstat64(fd, sbuf);
294 #else
295         ret = fstat(fd, sbuf);
296 #endif
297         /* we always want directories to appear zero size */
298         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
299         return ret;
300 }
301
302 /*******************************************************************
303  An lstat() wrapper that will deal with 64 bit filesizes.
304 ********************************************************************/
305
306 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
307 {
308         int ret;
309 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
310         ret = lstat64(fname, sbuf);
311 #else
312         ret = lstat(fname, sbuf);
313 #endif
314         /* we always want directories to appear zero size */
315         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
316         return ret;
317 }
318
319 /*******************************************************************
320  An ftruncate() wrapper that will deal with 64 bit filesizes.
321 ********************************************************************/
322
323 int sys_ftruncate(int fd, SMB_OFF_T offset)
324 {
325 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
326         return ftruncate64(fd, offset);
327 #else
328         return ftruncate(fd, offset);
329 #endif
330 }
331
332 /*******************************************************************
333  An lseek() wrapper that will deal with 64 bit filesizes.
334 ********************************************************************/
335
336 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
337 {
338 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
339         return lseek64(fd, offset, whence);
340 #else
341         return lseek(fd, offset, whence);
342 #endif
343 }
344
345 /*******************************************************************
346  An fseek() wrapper that will deal with 64 bit filesizes.
347 ********************************************************************/
348
349 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
350 {
351 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
352         return fseek64(fp, offset, whence);
353 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
354         return fseeko64(fp, offset, whence);
355 #else
356         return fseek(fp, offset, whence);
357 #endif
358 }
359
360 /*******************************************************************
361  An ftell() wrapper that will deal with 64 bit filesizes.
362 ********************************************************************/
363
364 SMB_OFF_T sys_ftell(FILE *fp)
365 {
366 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
367         return (SMB_OFF_T)ftell64(fp);
368 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
369         return (SMB_OFF_T)ftello64(fp);
370 #else
371         return (SMB_OFF_T)ftell(fp);
372 #endif
373 }
374
375 /*******************************************************************
376  A creat() wrapper that will deal with 64 bit filesizes.
377 ********************************************************************/
378
379 int sys_creat(const char *path, mode_t mode)
380 {
381 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
382         return creat64(path, mode);
383 #else
384         /*
385          * If creat64 isn't defined then ensure we call a potential open64.
386          * JRA.
387          */
388         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
389 #endif
390 }
391
392 /*******************************************************************
393  An open() wrapper that will deal with 64 bit filesizes.
394 ********************************************************************/
395
396 int sys_open(const char *path, int oflag, mode_t mode)
397 {
398 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
399         return open64(path, oflag, mode);
400 #else
401         return open(path, oflag, mode);
402 #endif
403 }
404
405 /*******************************************************************
406  An fopen() wrapper that will deal with 64 bit filesizes.
407 ********************************************************************/
408
409 FILE *sys_fopen(const char *path, const char *type)
410 {
411 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
412         return fopen64(path, type);
413 #else
414         return fopen(path, type);
415 #endif
416 }
417
418
419 /*******************************************************************
420  A flock() wrapper that will perform the kernel flock.
421 ********************************************************************/
422
423 void kernel_flock(int fd, uint32 share_mode)
424 {
425 #if HAVE_KERNEL_SHARE_MODES
426         int kernel_mode = 0;
427         if (share_mode == FILE_SHARE_WRITE) {
428                 kernel_mode = LOCK_MAND|LOCK_WRITE;
429         } else if (share_mode == FILE_SHARE_READ) {
430                 kernel_mode = LOCK_MAND|LOCK_READ;
431         } else if (share_mode == FILE_SHARE_NONE) {
432                 kernel_mode = LOCK_MAND;
433         }
434         if (kernel_mode) {
435                 flock(fd, kernel_mode);
436         }
437 #endif
438         ;
439 }
440
441
442
443 /*******************************************************************
444  An opendir wrapper that will deal with 64 bit filesizes.
445 ********************************************************************/
446
447 SMB_STRUCT_DIR *sys_opendir(const char *name)
448 {
449 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
450         return opendir64(name);
451 #else
452         return opendir(name);
453 #endif
454 }
455
456 /*******************************************************************
457  A readdir wrapper that will deal with 64 bit filesizes.
458 ********************************************************************/
459
460 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
461 {
462 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
463         return readdir64(dirp);
464 #else
465         return readdir(dirp);
466 #endif
467 }
468
469 /*******************************************************************
470  A seekdir wrapper that will deal with 64 bit filesizes.
471 ********************************************************************/
472
473 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
474 {
475 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
476         seekdir64(dirp, offset);
477 #else
478         seekdir(dirp, offset);
479 #endif
480 }
481
482 /*******************************************************************
483  A telldir wrapper that will deal with 64 bit filesizes.
484 ********************************************************************/
485
486 long sys_telldir(SMB_STRUCT_DIR *dirp)
487 {
488 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
489         return (long)telldir64(dirp);
490 #else
491         return (long)telldir(dirp);
492 #endif
493 }
494
495 /*******************************************************************
496  A rewinddir wrapper that will deal with 64 bit filesizes.
497 ********************************************************************/
498
499 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
500 {
501 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
502         rewinddir64(dirp);
503 #else
504         rewinddir(dirp);
505 #endif
506 }
507
508 /*******************************************************************
509  A close wrapper that will deal with 64 bit filesizes.
510 ********************************************************************/
511
512 int sys_closedir(SMB_STRUCT_DIR *dirp)
513 {
514 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
515         return closedir64(dirp);
516 #else
517         return closedir(dirp);
518 #endif
519 }
520
521 /*******************************************************************
522  An mknod() wrapper that will deal with 64 bit filesizes.
523 ********************************************************************/
524
525 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
526 {
527 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
528 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
529         return mknod64(path, mode, dev);
530 #else
531         return mknod(path, mode, dev);
532 #endif
533 #else
534         /* No mknod system call. */
535         errno = ENOSYS;
536         return -1;
537 #endif
538 }
539
540 /*******************************************************************
541  Wrapper for realpath.
542 ********************************************************************/
543
544 char *sys_realpath(const char *path, char *resolved_path)
545 {
546 #if defined(HAVE_REALPATH)
547         return realpath(path, resolved_path);
548 #else
549         /* As realpath is not a system call we can't return ENOSYS. */
550         errno = EINVAL;
551         return NULL;
552 #endif
553 }
554
555 /*******************************************************************
556 The wait() calls vary between systems
557 ********************************************************************/
558
559 int sys_waitpid(pid_t pid,int *status,int options)
560 {
561 #ifdef HAVE_WAITPID
562         return waitpid(pid,status,options);
563 #else /* HAVE_WAITPID */
564         return wait4(pid, status, options, NULL);
565 #endif /* HAVE_WAITPID */
566 }
567
568 /*******************************************************************
569  System wrapper for getwd
570 ********************************************************************/
571
572 char *sys_getwd(char *s)
573 {
574         char *wd;
575 #ifdef HAVE_GETCWD
576         wd = (char *)getcwd(s, PATH_MAX);
577 #else
578         wd = (char *)getwd(s);
579 #endif
580         return wd;
581 }
582
583 /*******************************************************************
584 system wrapper for symlink
585 ********************************************************************/
586
587 int sys_symlink(const char *oldpath, const char *newpath)
588 {
589 #ifndef HAVE_SYMLINK
590         errno = ENOSYS;
591         return -1;
592 #else
593         return symlink(oldpath, newpath);
594 #endif
595 }
596
597 /*******************************************************************
598  Wrapper for lchown.
599 ********************************************************************/
600
601 int sys_lchown(const char *fname,uid_t uid,gid_t gid)
602 {
603 #ifndef HAVE_LCHOWN
604         static int done;
605         if (!done) {
606                 DEBUG(1,("WARNING: no lchown!\n"));
607                 done=1;
608         }
609         errno = ENOSYS;
610         return -1;
611 #else
612         return(lchown(fname,uid,gid));
613 #endif
614 }
615
616 /*******************************************************************
617 os/2 also doesn't have chroot
618 ********************************************************************/
619 int sys_chroot(const char *dname)
620 {
621 #ifndef HAVE_CHROOT
622         static int done;
623         if (!done) {
624                 DEBUG(1,("WARNING: no chroot!\n"));
625                 done=1;
626         }
627         errno = ENOSYS;
628         return -1;
629 #else
630         return(chroot(dname));
631 #endif
632 }
633
634 #if defined(HAVE_POSIX_CAPABILITIES)
635
636 /**************************************************************************
637  Try and abstract process capabilities (for systems that have them).
638 ****************************************************************************/
639
640 /* Set the POSIX capabilities needed for the given purpose into the effective
641  * capability set of the current process. Make sure they are always removed
642  * from the inheritable set, because there is no circumstance in which our
643  * children should inherit our elevated privileges.
644  */
645 static bool set_process_capability(enum smbd_capability capability,
646                                    bool enable)
647 {
648         cap_value_t cap_vals[2] = {0};
649         int num_cap_vals = 0;
650
651         cap_t cap;
652
653 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
654         /* On Linux, make sure that any capabilities we grab are sticky
655          * across UID changes. We expect that this would allow us to keep both
656          * the effective and permitted capability sets, but as of circa 2.6.16,
657          * only the permitted set is kept. It is a bug (which we work around)
658          * that the effective set is lost, but we still require the effective
659          * set to be kept.
660          */
661         if (!prctl(PR_GET_KEEPCAPS)) {
662                 prctl(PR_SET_KEEPCAPS, 1);
663         }
664 #endif
665
666         cap = cap_get_proc();
667         if (cap == NULL) {
668                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
669                         strerror(errno)));
670                 return False;
671         }
672
673         switch (capability) {
674                 case KERNEL_OPLOCK_CAPABILITY:
675 #ifdef CAP_NETWORK_MGT
676                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
677                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
678 #endif
679                         break;
680                 case DMAPI_ACCESS_CAPABILITY:
681 #ifdef CAP_DEVICE_MGT
682                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
683                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
684 #elif CAP_MKNOD
685                         /* Linux has CAP_MKNOD for DMAPI access. */
686                         cap_vals[num_cap_vals++] = CAP_MKNOD;
687 #endif
688                         break;
689                 case LEASE_CAPABILITY:
690 #ifdef CAP_LEASE
691                         cap_vals[num_cap_vals++] = CAP_LEASE;
692 #endif
693                         break;
694         }
695
696         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
697
698         if (num_cap_vals == 0) {
699                 cap_free(cap);
700                 return True;
701         }
702
703         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
704                 enable ? CAP_SET : CAP_CLEAR);
705
706         /* We never want to pass capabilities down to our children, so make
707          * sure they are not inherited.
708          */
709         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
710
711         if (cap_set_proc(cap) == -1) {
712                 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
713                         strerror(errno)));
714                 cap_free(cap);
715                 return False;
716         }
717
718         cap_free(cap);
719         return True;
720 }
721
722 #endif /* HAVE_POSIX_CAPABILITIES */
723
724 /****************************************************************************
725  Gain the oplock capability from the kernel if possible.
726 ****************************************************************************/
727
728 void set_effective_capability(enum smbd_capability capability)
729 {
730 #if defined(HAVE_POSIX_CAPABILITIES)
731         set_process_capability(capability, True);
732 #endif /* HAVE_POSIX_CAPABILITIES */
733 }
734
735 void drop_effective_capability(enum smbd_capability capability)
736 {
737 #if defined(HAVE_POSIX_CAPABILITIES)
738         set_process_capability(capability, False);
739 #endif /* HAVE_POSIX_CAPABILITIES */
740 }
741
742 /**************************************************************************
743  Wrapper for random().
744 ****************************************************************************/
745
746 long sys_random(void)
747 {
748 #if defined(HAVE_RANDOM)
749         return (long)random();
750 #elif defined(HAVE_RAND)
751         return (long)rand();
752 #else
753         DEBUG(0,("Error - no random function available !\n"));
754         exit(1);
755 #endif
756 }
757
758 /**************************************************************************
759  Wrapper for srandom().
760 ****************************************************************************/
761
762 void sys_srandom(unsigned int seed)
763 {
764 #if defined(HAVE_SRANDOM)
765         srandom(seed);
766 #elif defined(HAVE_SRAND)
767         srand(seed);
768 #else
769         DEBUG(0,("Error - no srandom function available !\n"));
770         exit(1);
771 #endif
772 }
773
774 /**************************************************************************
775  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
776 ****************************************************************************/
777
778 int groups_max(void)
779 {
780 #if defined(SYSCONF_SC_NGROUPS_MAX)
781         int ret = sysconf(_SC_NGROUPS_MAX);
782         return (ret == -1) ? NGROUPS_MAX : ret;
783 #else
784         return NGROUPS_MAX;
785 #endif
786 }
787
788 /**************************************************************************
789  Wrap setgroups and getgroups for systems that declare getgroups() as
790  returning an array of gid_t, but actuall return an array of int.
791 ****************************************************************************/
792
793 #if defined(HAVE_BROKEN_GETGROUPS)
794 static int sys_broken_getgroups(int setlen, gid_t *gidset)
795 {
796         GID_T gid;
797         GID_T *group_list;
798         int i, ngroups;
799
800         if(setlen == 0) {
801                 return getgroups(setlen, &gid);
802         }
803
804         /*
805          * Broken case. We need to allocate a
806          * GID_T array of size setlen.
807          */
808
809         if(setlen < 0) {
810                 errno = EINVAL; 
811                 return -1;
812         } 
813
814         if (setlen == 0)
815                 setlen = groups_max();
816
817         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
818                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
819                 return -1;
820         }
821
822         if((ngroups = getgroups(setlen, group_list)) < 0) {
823                 int saved_errno = errno;
824                 SAFE_FREE(group_list);
825                 errno = saved_errno;
826                 return -1;
827         }
828
829         for(i = 0; i < ngroups; i++)
830                 gidset[i] = (gid_t)group_list[i];
831
832         SAFE_FREE(group_list);
833         return ngroups;
834 }
835
836 static int sys_broken_setgroups(int setlen, gid_t *gidset)
837 {
838         GID_T *group_list;
839         int i ; 
840
841         if (setlen == 0)
842                 return 0 ;
843
844         if (setlen < 0 || setlen > groups_max()) {
845                 errno = EINVAL; 
846                 return -1;   
847         }
848
849         /*
850          * Broken case. We need to allocate a
851          * GID_T array of size setlen.
852          */
853
854         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
855                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
856                 return -1;    
857         }
858  
859         for(i = 0; i < setlen; i++) 
860                 group_list[i] = (GID_T) gidset[i]; 
861
862         if(setgroups(setlen, group_list) != 0) {
863                 int saved_errno = errno;
864                 SAFE_FREE(group_list);
865                 errno = saved_errno;
866                 return -1;
867         }
868  
869         SAFE_FREE(group_list);
870         return 0 ;
871 }
872
873 #endif /* HAVE_BROKEN_GETGROUPS */
874
875 /* This is a list of systems that require the first GID passed to setgroups(2)
876  * to be the effective GID. If your system is one of these, add it here.
877  */
878 #if defined (FREEBSD) || defined (DARWINOS)
879 #define USE_BSD_SETGROUPS
880 #endif
881
882 #if defined(USE_BSD_SETGROUPS)
883 /* Depending on the particular BSD implementation, the first GID that is
884  * passed to setgroups(2) will either be ignored or will set the credential's
885  * effective GID. In either case, the right thing to do is to guarantee that
886  * gidset[0] is the effective GID.
887  */
888 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
889 {
890         gid_t *new_gidset = NULL;
891         int max;
892         int ret;
893
894         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
895         max = groups_max();
896
897         /* No group list, just make sure we are setting the efective GID. */
898         if (setlen == 0) {
899                 return setgroups(1, &primary_gid);
900         }
901
902         /* If the primary gid is not the first array element, grow the array
903          * and insert it at the front.
904          */
905         if (gidset[0] != primary_gid) {
906                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
907                 if (new_gidset == NULL) {
908                         return -1;
909                 }
910
911                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
912                 new_gidset[0] = primary_gid;
913                 setlen++;
914         }
915
916         if (setlen > max) {
917                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
918                         setlen, max));
919                 setlen = max;
920         }
921
922 #if defined(HAVE_BROKEN_GETGROUPS)
923         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
924 #else
925         ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
926 #endif
927
928         if (new_gidset) {
929                 int errsav = errno;
930                 SAFE_FREE(new_gidset);
931                 errno = errsav;
932         }
933
934         return ret;
935 }
936
937 #endif /* USE_BSD_SETGROUPS */
938
939 /**************************************************************************
940  Wrapper for getgroups. Deals with broken (int) case.
941 ****************************************************************************/
942
943 int sys_getgroups(int setlen, gid_t *gidset)
944 {
945 #if defined(HAVE_BROKEN_GETGROUPS)
946         return sys_broken_getgroups(setlen, gidset);
947 #else
948         return getgroups(setlen, gidset);
949 #endif
950 }
951
952 /**************************************************************************
953  Wrapper for setgroups. Deals with broken (int) case and BSD case.
954 ****************************************************************************/
955
956 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
957 {
958 #if !defined(HAVE_SETGROUPS)
959         errno = ENOSYS;
960         return -1;
961 #endif /* HAVE_SETGROUPS */
962
963 #if defined(USE_BSD_SETGROUPS)
964         return sys_bsd_setgroups(primary_gid, setlen, gidset);
965 #elif defined(HAVE_BROKEN_GETGROUPS)
966         return sys_broken_setgroups(setlen, gidset);
967 #else
968         return setgroups(setlen, gidset);
969 #endif
970 }
971
972 /**************************************************************************
973  Wrappers for setpwent(), getpwent() and endpwent()
974 ****************************************************************************/
975
976 void sys_setpwent(void)
977 {
978         setpwent();
979 }
980
981 struct passwd *sys_getpwent(void)
982 {
983         return getpwent();
984 }
985
986 void sys_endpwent(void)
987 {
988         endpwent();
989 }
990
991 /**************************************************************************
992  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
993 ****************************************************************************/
994
995
996 struct passwd *sys_getpwnam(const char *name)
997 {
998         return getpwnam(name);
999 }
1000
1001 struct passwd *sys_getpwuid(uid_t uid)
1002 {
1003         return getpwuid(uid);
1004 }
1005
1006 struct group *sys_getgrnam(const char *name)
1007 {
1008         return getgrnam(name);
1009 }
1010
1011 struct group *sys_getgrgid(gid_t gid)
1012 {
1013         return getgrgid(gid);
1014 }
1015
1016 /**************************************************************************
1017  Extract a command into an arg list.
1018 ****************************************************************************/
1019
1020 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1021 {
1022         char *trunc_cmd;
1023         char *saveptr;
1024         char *ptr;
1025         int argcl;
1026         char **argl = NULL;
1027         int i;
1028
1029         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1030                 DEBUG(0, ("talloc failed\n"));
1031                 goto nomem;
1032         }
1033
1034         if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1035                 TALLOC_FREE(trunc_cmd);
1036                 errno = EINVAL;
1037                 return NULL;
1038         }
1039
1040         /*
1041          * Count the args.
1042          */
1043
1044         for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1045                 argcl++;
1046
1047         TALLOC_FREE(trunc_cmd);
1048
1049         if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1050                 goto nomem;
1051         }
1052
1053         /*
1054          * Now do the extraction.
1055          */
1056
1057         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1058                 goto nomem;
1059         }
1060
1061         ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1062         i = 0;
1063
1064         if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1065                 goto nomem;
1066         }
1067
1068         while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1069
1070                 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1071                         goto nomem;
1072                 }
1073         }
1074
1075         argl[i++] = NULL;
1076         return argl;
1077
1078  nomem:
1079         DEBUG(0, ("talloc failed\n"));
1080         TALLOC_FREE(trunc_cmd);
1081         TALLOC_FREE(argl);
1082         errno = ENOMEM;
1083         return NULL;
1084 }
1085
1086 /**************************************************************************
1087  Wrapper for fork. Ensures that mypid is reset. Used so we can write
1088  a sys_getpid() that only does a system call *once*.
1089 ****************************************************************************/
1090
1091 static pid_t mypid = (pid_t)-1;
1092
1093 pid_t sys_fork(void)
1094 {
1095         pid_t forkret = fork();
1096
1097         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
1098                 mypid = (pid_t) -1;
1099
1100         return forkret;
1101 }
1102
1103 /**************************************************************************
1104  Wrapper for getpid. Ensures we only do a system call *once*.
1105 ****************************************************************************/
1106
1107 pid_t sys_getpid(void)
1108 {
1109         if (mypid == (pid_t)-1)
1110                 mypid = getpid();
1111
1112         return mypid;
1113 }
1114
1115 /**************************************************************************
1116  Wrapper for popen. Safer as it doesn't search a path.
1117  Modified from the glibc sources.
1118  modified by tridge to return a file descriptor. We must kick our FILE* habit
1119 ****************************************************************************/
1120
1121 typedef struct _popen_list
1122 {
1123         int fd;
1124         pid_t child_pid;
1125         struct _popen_list *next;
1126 } popen_list;
1127
1128 static popen_list *popen_chain;
1129
1130 int sys_popen(const char *command)
1131 {
1132         int parent_end, child_end;
1133         int pipe_fds[2];
1134         popen_list *entry = NULL;
1135         char **argl = NULL;
1136
1137         if (pipe(pipe_fds) < 0)
1138                 return -1;
1139
1140         parent_end = pipe_fds[0];
1141         child_end = pipe_fds[1];
1142
1143         if (!*command) {
1144                 errno = EINVAL;
1145                 goto err_exit;
1146         }
1147
1148         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1149                 goto err_exit;
1150
1151         ZERO_STRUCTP(entry);
1152
1153         /*
1154          * Extract the command and args into a NULL terminated array.
1155          */
1156
1157         if(!(argl = extract_args(NULL, command)))
1158                 goto err_exit;
1159
1160         entry->child_pid = sys_fork();
1161
1162         if (entry->child_pid == -1) {
1163                 goto err_exit;
1164         }
1165
1166         if (entry->child_pid == 0) {
1167
1168                 /*
1169                  * Child !
1170                  */
1171
1172                 int child_std_end = STDOUT_FILENO;
1173                 popen_list *p;
1174
1175                 close(parent_end);
1176                 if (child_end != child_std_end) {
1177                         dup2 (child_end, child_std_end);
1178                         close (child_end);
1179                 }
1180
1181                 /*
1182                  * POSIX.2:  "popen() shall ensure that any streams from previous
1183                  * popen() calls that remain open in the parent process are closed
1184                  * in the new child process."
1185                  */
1186
1187                 for (p = popen_chain; p; p = p->next)
1188                         close(p->fd);
1189
1190                 execv(argl[0], argl);
1191                 _exit (127);
1192         }
1193
1194         /*
1195          * Parent.
1196          */
1197
1198         close (child_end);
1199         TALLOC_FREE(argl);
1200
1201         /* Link into popen_chain. */
1202         entry->next = popen_chain;
1203         popen_chain = entry;
1204         entry->fd = parent_end;
1205
1206         return entry->fd;
1207
1208 err_exit:
1209
1210         SAFE_FREE(entry);
1211         SAFE_FREE(argl);
1212         close(pipe_fds[0]);
1213         close(pipe_fds[1]);
1214         return -1;
1215 }
1216
1217 /**************************************************************************
1218  Wrapper for pclose. Modified from the glibc sources.
1219 ****************************************************************************/
1220
1221 int sys_pclose(int fd)
1222 {
1223         int wstatus;
1224         popen_list **ptr = &popen_chain;
1225         popen_list *entry = NULL;
1226         pid_t wait_pid;
1227         int status = -1;
1228
1229         /* Unlink from popen_chain. */
1230         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1231                 if ((*ptr)->fd == fd) {
1232                         entry = *ptr;
1233                         *ptr = (*ptr)->next;
1234                         status = 0;
1235                         break;
1236                 }
1237         }
1238
1239         if (status < 0 || close(entry->fd) < 0)
1240                 return -1;
1241
1242         /*
1243          * As Samba is catching and eating child process
1244          * exits we don't really care about the child exit
1245          * code, a -1 with errno = ECHILD will do fine for us.
1246          */
1247
1248         do {
1249                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1250         } while (wait_pid == -1 && errno == EINTR);
1251
1252         SAFE_FREE(entry);
1253
1254         if (wait_pid == -1)
1255                 return -1;
1256         return wstatus;
1257 }
1258
1259 /**************************************************************************
1260  Wrappers for dlopen, dlsym, dlclose.
1261 ****************************************************************************/
1262
1263 void *sys_dlopen(const char *name, int flags)
1264 {
1265 #if defined(HAVE_DLOPEN)
1266         return dlopen(name, flags);
1267 #else
1268         return NULL;
1269 #endif
1270 }
1271
1272 void *sys_dlsym(void *handle, const char *symbol)
1273 {
1274 #if defined(HAVE_DLSYM)
1275     return dlsym(handle, symbol);
1276 #else
1277     return NULL;
1278 #endif
1279 }
1280
1281 int sys_dlclose (void *handle)
1282 {
1283 #if defined(HAVE_DLCLOSE)
1284         return dlclose(handle);
1285 #else
1286         return 0;
1287 #endif
1288 }
1289
1290 const char *sys_dlerror(void)
1291 {
1292 #if defined(HAVE_DLERROR)
1293         return dlerror();
1294 #else
1295         return NULL;
1296 #endif
1297 }
1298
1299 int sys_dup2(int oldfd, int newfd) 
1300 {
1301 #if defined(HAVE_DUP2)
1302         return dup2(oldfd, newfd);
1303 #else
1304         errno = ENOSYS;
1305         return -1;
1306 #endif
1307 }
1308
1309 /**************************************************************************
1310  Wrapper for Admin Logs.
1311 ****************************************************************************/
1312
1313  void sys_adminlog(int priority, const char *format_str, ...) 
1314 {
1315         va_list ap;
1316         int ret;
1317         char *msgbuf = NULL;
1318
1319         va_start( ap, format_str );
1320         ret = vasprintf( &msgbuf, format_str, ap );
1321         va_end( ap );
1322
1323         if (ret == -1)
1324                 return;
1325
1326 #if defined(HAVE_SYSLOG)
1327         syslog( priority, "%s", msgbuf );
1328 #else
1329         DEBUG(0,("%s", msgbuf ));
1330 #endif
1331         SAFE_FREE(msgbuf);
1332 }
1333
1334 /******** Solaris EA helper function prototypes ********/
1335 #ifdef HAVE_ATTROPEN
1336 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1337 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1338 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1339 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1340 static int solaris_unlinkat(int attrdirfd, const char *name);
1341 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1342 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1343 #endif
1344
1345 /**************************************************************************
1346  Wrappers for extented attribute calls. Based on the Linux package with
1347  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1348 ****************************************************************************/
1349
1350 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1351 {
1352 #if defined(HAVE_GETXATTR)
1353 #ifndef XATTR_ADD_OPT
1354         return getxattr(path, name, value, size);
1355 #else
1356         int options = 0;
1357         return getxattr(path, name, value, size, 0, options);
1358 #endif
1359 #elif defined(HAVE_GETEA)
1360         return getea(path, name, value, size);
1361 #elif defined(HAVE_EXTATTR_GET_FILE)
1362         char *s;
1363         ssize_t retval;
1364         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1365                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1366         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1367         /*
1368          * The BSD implementation has a nasty habit of silently truncating
1369          * the returned value to the size of the buffer, so we have to check
1370          * that the buffer is large enough to fit the returned value.
1371          */
1372         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1373                 if(retval > size) {
1374                         errno = ERANGE;
1375                         return -1;
1376                 }
1377                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1378                         return retval;
1379         }
1380
1381         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1382         return -1;
1383 #elif defined(HAVE_ATTR_GET)
1384         int retval, flags = 0;
1385         int valuelength = (int)size;
1386         char *attrname = strchr(name,'.') + 1;
1387         
1388         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1389
1390         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1391
1392         return retval ? retval : valuelength;
1393 #elif defined(HAVE_ATTROPEN)
1394         ssize_t ret = -1;
1395         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1396         if (attrfd >= 0) {
1397                 ret = solaris_read_xattr(attrfd, value, size);
1398                 close(attrfd);
1399         }
1400         return ret;
1401 #else
1402         errno = ENOSYS;
1403         return -1;
1404 #endif
1405 }
1406
1407 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1408 {
1409 #if defined(HAVE_LGETXATTR)
1410         return lgetxattr(path, name, value, size);
1411 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1412         int options = XATTR_NOFOLLOW;
1413         return getxattr(path, name, value, size, 0, options);
1414 #elif defined(HAVE_LGETEA)
1415         return lgetea(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         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1424                 if(retval > size) {
1425                         errno = ERANGE;
1426                         return -1;
1427                 }
1428                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1429                         return retval;
1430         }
1431         
1432         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1433         return -1;
1434 #elif defined(HAVE_ATTR_GET)
1435         int retval, flags = ATTR_DONTFOLLOW;
1436         int valuelength = (int)size;
1437         char *attrname = strchr(name,'.') + 1;
1438         
1439         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1440
1441         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1442
1443         return retval ? retval : valuelength;
1444 #elif defined(HAVE_ATTROPEN)
1445         ssize_t ret = -1;
1446         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1447         if (attrfd >= 0) {
1448                 ret = solaris_read_xattr(attrfd, value, size);
1449                 close(attrfd);
1450         }
1451         return ret;
1452 #else
1453         errno = ENOSYS;
1454         return -1;
1455 #endif
1456 }
1457
1458 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1459 {
1460 #if defined(HAVE_FGETXATTR)
1461 #ifndef XATTR_ADD_OPT
1462         return fgetxattr(filedes, name, value, size);
1463 #else
1464         int options = 0;
1465         return fgetxattr(filedes, name, value, size, 0, options);
1466 #endif
1467 #elif defined(HAVE_FGETEA)
1468         return fgetea(filedes, name, value, size);
1469 #elif defined(HAVE_EXTATTR_GET_FD)
1470         char *s;
1471         ssize_t retval;
1472         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1473                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1474         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1475
1476         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1477                 if(retval > size) {
1478                         errno = ERANGE;
1479                         return -1;
1480                 }
1481                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1482                         return retval;
1483         }
1484         
1485         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1486         return -1;
1487 #elif defined(HAVE_ATTR_GETF)
1488         int retval, flags = 0;
1489         int valuelength = (int)size;
1490         char *attrname = strchr(name,'.') + 1;
1491         
1492         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1493
1494         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1495
1496         return retval ? retval : valuelength;
1497 #elif defined(HAVE_ATTROPEN)
1498         ssize_t ret = -1;
1499         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1500         if (attrfd >= 0) {
1501                 ret = solaris_read_xattr(attrfd, value, size);
1502                 close(attrfd);
1503         }
1504         return ret;
1505 #else
1506         errno = ENOSYS;
1507         return -1;
1508 #endif
1509 }
1510
1511 #if defined(HAVE_EXTATTR_LIST_FILE)
1512
1513 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1514
1515 static struct {
1516         int space;
1517         const char *name;
1518         size_t len;
1519
1520 extattr[] = {
1521         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1522         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1523 };
1524
1525 typedef union {
1526         const char *path;
1527         int filedes;
1528 } extattr_arg;
1529
1530 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1531 {
1532         ssize_t list_size, total_size = 0;
1533         int i, t, len;
1534         char *buf;
1535         /* Iterate through extattr(2) namespaces */
1536         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1537                 switch(type) {
1538 #if defined(HAVE_EXTATTR_LIST_FILE)
1539                         case 0:
1540                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1541                                 break;
1542 #endif
1543 #if defined(HAVE_EXTATTR_LIST_LINK)
1544                         case 1:
1545                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1546                                 break;
1547 #endif
1548 #if defined(HAVE_EXTATTR_LIST_FD)
1549                         case 2:
1550                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1551                                 break;
1552 #endif
1553                         default:
1554                                 errno = ENOSYS;
1555                                 return -1;
1556                 }
1557                 /* Some error happend. Errno should be set by the previous call */
1558                 if(list_size < 0)
1559                         return -1;
1560                 /* No attributes */
1561                 if(list_size == 0)
1562                         continue;
1563                 /* XXX: Call with an empty buffer may be used to calculate
1564                    necessary buffer size. Unfortunately, we can't say, how
1565                    many attributes were returned, so here is the potential
1566                    problem with the emulation.
1567                 */
1568                 if(list == NULL) {
1569                         /* Take the worse case of one char attribute names - 
1570                            two bytes per name plus one more for sanity.
1571                         */
1572                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1573                         continue;
1574                 }
1575                 /* Count necessary offset to fit namespace prefixes */
1576                 len = 0;
1577                 for(i = 0; i < list_size; i += list[i] + 1)
1578                         len += extattr[t].len;
1579
1580                 total_size += list_size + len;
1581                 /* Buffer is too small to fit the results */
1582                 if(total_size > size) {
1583                         errno = ERANGE;
1584                         return -1;
1585                 }
1586                 /* Shift results back, so we can prepend prefixes */
1587                 buf = memmove(list + len, list, list_size);
1588
1589                 for(i = 0; i < list_size; i += len + 1) {
1590                         len = buf[i];
1591                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1592                         list += extattr[t].len;
1593                         strncpy(list, buf + i + 1, len);
1594                         list[len] = '\0';
1595                         list += len + 1;
1596                 }
1597                 size -= total_size;
1598         }
1599         return total_size;
1600 }
1601
1602 #endif
1603
1604 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1605 static char attr_buffer[ATTR_MAX_VALUELEN];
1606
1607 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1608 {
1609         int retval = 0, index;
1610         attrlist_cursor_t *cursor = 0;
1611         int total_size = 0;
1612         attrlist_t * al = (attrlist_t *)attr_buffer;
1613         attrlist_ent_t *ae;
1614         size_t ent_size, left = size;
1615         char *bp = list;
1616
1617         while (True) {
1618             if (filedes)
1619                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1620             else
1621                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1622             if (retval) break;
1623             for (index = 0; index < al->al_count; index++) {
1624                 ae = ATTR_ENTRY(attr_buffer, index);
1625                 ent_size = strlen(ae->a_name) + sizeof("user.");
1626                 if (left >= ent_size) {
1627                     strncpy(bp, "user.", sizeof("user."));
1628                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1629                     bp += ent_size;
1630                     left -= ent_size;
1631                 } else if (size) {
1632                     errno = ERANGE;
1633                     retval = -1;
1634                     break;
1635                 }
1636                 total_size += ent_size;
1637             }
1638             if (al->al_more == 0) break;
1639         }
1640         if (retval == 0) {
1641             flags |= ATTR_ROOT;
1642             cursor = 0;
1643             while (True) {
1644                 if (filedes)
1645                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1646                 else
1647                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1648                 if (retval) break;
1649                 for (index = 0; index < al->al_count; index++) {
1650                     ae = ATTR_ENTRY(attr_buffer, index);
1651                     ent_size = strlen(ae->a_name) + sizeof("system.");
1652                     if (left >= ent_size) {
1653                         strncpy(bp, "system.", sizeof("system."));
1654                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1655                         bp += ent_size;
1656                         left -= ent_size;
1657                     } else if (size) {
1658                         errno = ERANGE;
1659                         retval = -1;
1660                         break;
1661                     }
1662                     total_size += ent_size;
1663                 }
1664                 if (al->al_more == 0) break;
1665             }
1666         }
1667         return (ssize_t)(retval ? retval : total_size);
1668 }
1669
1670 #endif
1671
1672 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1673 {
1674 #if defined(HAVE_LISTXATTR)
1675 #ifndef XATTR_ADD_OPT
1676         return listxattr(path, list, size);
1677 #else
1678         int options = 0;
1679         return listxattr(path, list, size, options);
1680 #endif
1681 #elif defined(HAVE_LISTEA)
1682         return listea(path, list, size);
1683 #elif defined(HAVE_EXTATTR_LIST_FILE)
1684         extattr_arg arg;
1685         arg.path = path;
1686         return bsd_attr_list(0, arg, list, size);
1687 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1688         return irix_attr_list(path, 0, list, size, 0);
1689 #elif defined(HAVE_ATTROPEN)
1690         ssize_t ret = -1;
1691         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1692         if (attrdirfd >= 0) {
1693                 ret = solaris_list_xattr(attrdirfd, list, size);
1694                 close(attrdirfd);
1695         }
1696         return ret;
1697 #else
1698         errno = ENOSYS;
1699         return -1;
1700 #endif
1701 }
1702
1703 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1704 {
1705 #if defined(HAVE_LLISTXATTR)
1706         return llistxattr(path, list, size);
1707 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1708         int options = XATTR_NOFOLLOW;
1709         return listxattr(path, list, size, options);
1710 #elif defined(HAVE_LLISTEA)
1711         return llistea(path, list, size);
1712 #elif defined(HAVE_EXTATTR_LIST_LINK)
1713         extattr_arg arg;
1714         arg.path = path;
1715         return bsd_attr_list(1, arg, list, size);
1716 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1717         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1718 #elif defined(HAVE_ATTROPEN)
1719         ssize_t ret = -1;
1720         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1721         if (attrdirfd >= 0) {
1722                 ret = solaris_list_xattr(attrdirfd, list, size);
1723                 close(attrdirfd);
1724         }
1725         return ret;
1726 #else
1727         errno = ENOSYS;
1728         return -1;
1729 #endif
1730 }
1731
1732 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1733 {
1734 #if defined(HAVE_FLISTXATTR)
1735 #ifndef XATTR_ADD_OPT
1736         return flistxattr(filedes, list, size);
1737 #else
1738         int options = 0;
1739         return flistxattr(filedes, list, size, options);
1740 #endif
1741 #elif defined(HAVE_FLISTEA)
1742         return flistea(filedes, list, size);
1743 #elif defined(HAVE_EXTATTR_LIST_FD)
1744         extattr_arg arg;
1745         arg.filedes = filedes;
1746         return bsd_attr_list(2, arg, list, size);
1747 #elif defined(HAVE_ATTR_LISTF)
1748         return irix_attr_list(NULL, filedes, list, size, 0);
1749 #elif defined(HAVE_ATTROPEN)
1750         ssize_t ret = -1;
1751         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1752         if (attrdirfd >= 0) {
1753                 ret = solaris_list_xattr(attrdirfd, list, size);
1754                 close(attrdirfd);
1755         }
1756         return ret;
1757 #else
1758         errno = ENOSYS;
1759         return -1;
1760 #endif
1761 }
1762
1763 int sys_removexattr (const char *path, const char *name)
1764 {
1765 #if defined(HAVE_REMOVEXATTR)
1766 #ifndef XATTR_ADD_OPT
1767         return removexattr(path, name);
1768 #else
1769         int options = 0;
1770         return removexattr(path, name, options);
1771 #endif
1772 #elif defined(HAVE_REMOVEEA)
1773         return removeea(path, name);
1774 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1775         char *s;
1776         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1777                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1778         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1779
1780         return extattr_delete_file(path, attrnamespace, attrname);
1781 #elif defined(HAVE_ATTR_REMOVE)
1782         int flags = 0;
1783         char *attrname = strchr(name,'.') + 1;
1784         
1785         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1786
1787         return attr_remove(path, attrname, flags);
1788 #elif defined(HAVE_ATTROPEN)
1789         int ret = -1;
1790         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1791         if (attrdirfd >= 0) {
1792                 ret = solaris_unlinkat(attrdirfd, name);
1793                 close(attrdirfd);
1794         }
1795         return ret;
1796 #else
1797         errno = ENOSYS;
1798         return -1;
1799 #endif
1800 }
1801
1802 int sys_lremovexattr (const char *path, const char *name)
1803 {
1804 #if defined(HAVE_LREMOVEXATTR)
1805         return lremovexattr(path, name);
1806 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
1807         int options = XATTR_NOFOLLOW;
1808         return removexattr(path, name, options);
1809 #elif defined(HAVE_LREMOVEEA)
1810         return lremoveea(path, name);
1811 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1812         char *s;
1813         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1814                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1815         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1816
1817         return extattr_delete_link(path, attrnamespace, attrname);
1818 #elif defined(HAVE_ATTR_REMOVE)
1819         int flags = ATTR_DONTFOLLOW;
1820         char *attrname = strchr(name,'.') + 1;
1821         
1822         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1823
1824         return attr_remove(path, attrname, flags);
1825 #elif defined(HAVE_ATTROPEN)
1826         int ret = -1;
1827         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1828         if (attrdirfd >= 0) {
1829                 ret = solaris_unlinkat(attrdirfd, name);
1830                 close(attrdirfd);
1831         }
1832         return ret;
1833 #else
1834         errno = ENOSYS;
1835         return -1;
1836 #endif
1837 }
1838
1839 int sys_fremovexattr (int filedes, const char *name)
1840 {
1841 #if defined(HAVE_FREMOVEXATTR)
1842 #ifndef XATTR_ADD_OPT
1843         return fremovexattr(filedes, name);
1844 #else
1845         int options = 0;
1846         return fremovexattr(filedes, name, options);
1847 #endif
1848 #elif defined(HAVE_FREMOVEEA)
1849         return fremoveea(filedes, name);
1850 #elif defined(HAVE_EXTATTR_DELETE_FD)
1851         char *s;
1852         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1853                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1854         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1855
1856         return extattr_delete_fd(filedes, attrnamespace, attrname);
1857 #elif defined(HAVE_ATTR_REMOVEF)
1858         int flags = 0;
1859         char *attrname = strchr(name,'.') + 1;
1860         
1861         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1862
1863         return attr_removef(filedes, attrname, flags);
1864 #elif defined(HAVE_ATTROPEN)
1865         int ret = -1;
1866         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1867         if (attrdirfd >= 0) {
1868                 ret = solaris_unlinkat(attrdirfd, name);
1869                 close(attrdirfd);
1870         }
1871         return ret;
1872 #else
1873         errno = ENOSYS;
1874         return -1;
1875 #endif
1876 }
1877
1878 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1879 {
1880 #if defined(HAVE_SETXATTR)
1881 #ifndef XATTR_ADD_OPT
1882         return setxattr(path, name, value, size, flags);
1883 #else
1884         int options = 0;
1885         return setxattr(path, name, value, size, 0, options);
1886 #endif
1887 #elif defined(HAVE_SETEA)
1888         return setea(path, name, value, size, flags);
1889 #elif defined(HAVE_EXTATTR_SET_FILE)
1890         char *s;
1891         int retval = 0;
1892         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1893                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1894         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1895         if (flags) {
1896                 /* Check attribute existence */
1897                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1898                 if (retval < 0) {
1899                         /* REPLACE attribute, that doesn't exist */
1900                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1901                                 errno = ENOATTR;
1902                                 return -1;
1903                         }
1904                         /* Ignore other errors */
1905                 }
1906                 else {
1907                         /* CREATE attribute, that already exists */
1908                         if (flags & XATTR_CREATE) {
1909                                 errno = EEXIST;
1910                                 return -1;
1911                         }
1912                 }
1913         }
1914         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
1915         return (retval < 0) ? -1 : 0;
1916 #elif defined(HAVE_ATTR_SET)
1917         int myflags = 0;
1918         char *attrname = strchr(name,'.') + 1;
1919         
1920         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1921         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1922         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1923
1924         return attr_set(path, attrname, (const char *)value, size, myflags);
1925 #elif defined(HAVE_ATTROPEN)
1926         int ret = -1;
1927         int myflags = O_RDWR;
1928         int attrfd;
1929         if (flags & XATTR_CREATE) myflags |= O_EXCL;
1930         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
1931         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
1932         if (attrfd >= 0) {
1933                 ret = solaris_write_xattr(attrfd, value, size);
1934                 close(attrfd);
1935         }
1936         return ret;
1937 #else
1938         errno = ENOSYS;
1939         return -1;
1940 #endif
1941 }
1942
1943 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1944 {
1945 #if defined(HAVE_LSETXATTR)
1946         return lsetxattr(path, name, value, size, flags);
1947 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
1948         int options = XATTR_NOFOLLOW;
1949         return setxattr(path, name, value, size, 0, options);
1950 #elif defined(LSETEA)
1951         return lsetea(path, name, value, size, flags);
1952 #elif defined(HAVE_EXTATTR_SET_LINK)
1953         char *s;
1954         int retval = 0;
1955         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1956                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1957         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1958         if (flags) {
1959                 /* Check attribute existence */
1960                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
1961                 if (retval < 0) {
1962                         /* REPLACE attribute, that doesn't exist */
1963                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1964                                 errno = ENOATTR;
1965                                 return -1;
1966                         }
1967                         /* Ignore other errors */
1968                 }
1969                 else {
1970                         /* CREATE attribute, that already exists */
1971                         if (flags & XATTR_CREATE) {
1972                                 errno = EEXIST;
1973                                 return -1;
1974                         }
1975                 }
1976         }
1977
1978         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
1979         return (retval < 0) ? -1 : 0;
1980 #elif defined(HAVE_ATTR_SET)
1981         int myflags = ATTR_DONTFOLLOW;
1982         char *attrname = strchr(name,'.') + 1;
1983         
1984         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1985         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1986         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1987
1988         return attr_set(path, attrname, (const char *)value, size, myflags);
1989 #elif defined(HAVE_ATTROPEN)
1990         int ret = -1;
1991         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
1992         int attrfd;
1993         if (flags & XATTR_CREATE) myflags |= O_EXCL;
1994         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
1995         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
1996         if (attrfd >= 0) {
1997                 ret = solaris_write_xattr(attrfd, value, size);
1998                 close(attrfd);
1999         }
2000         return ret;
2001 #else
2002         errno = ENOSYS;
2003         return -1;
2004 #endif
2005 }
2006
2007 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2008 {
2009 #if defined(HAVE_FSETXATTR)
2010 #ifndef XATTR_ADD_OPT
2011         return fsetxattr(filedes, name, value, size, flags);
2012 #else
2013         int options = 0;
2014         return fsetxattr(filedes, name, value, size, 0, options);
2015 #endif
2016 #elif defined(HAVE_FSETEA)
2017         return fsetea(filedes, name, value, size, flags);
2018 #elif defined(HAVE_EXTATTR_SET_FD)
2019         char *s;
2020         int retval = 0;
2021         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2022                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2023         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2024         if (flags) {
2025                 /* Check attribute existence */
2026                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2027                 if (retval < 0) {
2028                         /* REPLACE attribute, that doesn't exist */
2029                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2030                                 errno = ENOATTR;
2031                                 return -1;
2032                         }
2033                         /* Ignore other errors */
2034                 }
2035                 else {
2036                         /* CREATE attribute, that already exists */
2037                         if (flags & XATTR_CREATE) {
2038                                 errno = EEXIST;
2039                                 return -1;
2040                         }
2041                 }
2042         }
2043         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2044         return (retval < 0) ? -1 : 0;
2045 #elif defined(HAVE_ATTR_SETF)
2046         int myflags = 0;
2047         char *attrname = strchr(name,'.') + 1;
2048         
2049         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2050         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2051         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2052
2053         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2054 #elif defined(HAVE_ATTROPEN)
2055         int ret = -1;
2056         int myflags = O_RDWR | O_XATTR;
2057         int attrfd;
2058         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2059         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2060         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2061         if (attrfd >= 0) {
2062                 ret = solaris_write_xattr(attrfd, value, size);
2063                 close(attrfd);
2064         }
2065         return ret;
2066 #else
2067         errno = ENOSYS;
2068         return -1;
2069 #endif
2070 }
2071
2072 /**************************************************************************
2073  helper functions for Solaris' EA support
2074 ****************************************************************************/
2075 #ifdef HAVE_ATTROPEN
2076 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2077 {
2078         struct stat sbuf;
2079
2080         if (fstat(attrfd, &sbuf) == -1) {
2081                 errno = ENOATTR;
2082                 return -1;
2083         }
2084
2085         /* This is to return the current size of the named extended attribute */
2086         if (size == 0) {
2087                 return sbuf.st_size;
2088         }
2089
2090         /* check size and read xattr */
2091         if (sbuf.st_size > size) {
2092                 errno = ERANGE;
2093                 return -1;
2094         }
2095
2096         return read(attrfd, value, sbuf.st_size);
2097 }
2098
2099 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2100 {
2101         ssize_t len = 0;
2102         int stop = 0;
2103         DIR *dirp;
2104         struct dirent *de;
2105         int newfd = dup(attrdirfd);
2106         /* CAUTION: The originating file descriptor should not be
2107                     used again following the call to fdopendir().
2108                     For that reason we dup() the file descriptor
2109                     here to make things more clear. */
2110         dirp = fdopendir(newfd);
2111
2112         while ((de = readdir(dirp))) {
2113                 size_t listlen = strlen(de->d_name);
2114                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2115                         /* we don't want "." and ".." here: */
2116                         DEBUG(10,("skipped EA %s\n",de->d_name));
2117                         continue;
2118                 }
2119
2120                 if (size == 0) {
2121                         /* return the current size of the list of extended attribute names*/
2122                         len += listlen + 1;
2123                 } else {
2124                         /* check size and copy entrieÑ• + nul into list. */
2125                         if ((len + listlen + 1) > size) {
2126                                 errno = ERANGE;
2127                                 len = -1;
2128                                 break;
2129                         } else {
2130                                 safe_strcpy(list + len, de->d_name, listlen);
2131                                 len += listlen;
2132                                 list[len] = '\0';
2133                                 ++len;
2134                         }
2135                 }
2136         }
2137
2138         if (closedir(dirp) == -1) {
2139                 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2140                 return -1;
2141         }
2142         return len;
2143 }
2144
2145 static int solaris_unlinkat(int attrdirfd, const char *name)
2146 {
2147         if (unlinkat(attrdirfd, name, 0) == -1) {
2148                 if (errno == ENOENT) {
2149                         errno = ENOATTR;
2150                 }
2151                 return -1;
2152         }
2153         return 0;
2154 }
2155
2156 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2157 {
2158         int filedes = attropen(path, attrpath, oflag, mode);
2159         if (filedes == -1) {
2160                 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2161                 if (errno == EINVAL) {
2162                         errno = ENOTSUP;
2163                 } else {
2164                         errno = ENOATTR;
2165                 }
2166         }
2167         return filedes;
2168 }
2169
2170 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2171 {
2172         int filedes = openat(fildes, path, oflag, mode);
2173         if (filedes == -1) {
2174                 DEBUG(10,("openat FAILED: fd: %s, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2175                 if (errno == EINVAL) {
2176                         errno = ENOTSUP;
2177                 } else {
2178                         errno = ENOATTR;
2179                 }
2180         }
2181         return filedes;
2182 }
2183
2184 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2185 {
2186         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2187                 return 0;
2188         } else {
2189                 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2190                 return -1;
2191         }
2192 }
2193 #endif /*HAVE_ATTROPEN*/
2194
2195
2196 /****************************************************************************
2197  Return the major devicenumber for UNIX extensions.
2198 ****************************************************************************/
2199                                                                                                                 
2200 uint32 unix_dev_major(SMB_DEV_T dev)
2201 {
2202 #if defined(HAVE_DEVICE_MAJOR_FN)
2203         return (uint32)major(dev);
2204 #else
2205         return (uint32)(dev >> 8);
2206 #endif
2207 }
2208                                                                                                                 
2209 /****************************************************************************
2210  Return the minor devicenumber for UNIX extensions.
2211 ****************************************************************************/
2212                                                                                                                 
2213 uint32 unix_dev_minor(SMB_DEV_T dev)
2214 {
2215 #if defined(HAVE_DEVICE_MINOR_FN)
2216         return (uint32)minor(dev);
2217 #else
2218         return (uint32)(dev & 0xff);
2219 #endif
2220 }
2221
2222 #if defined(WITH_AIO)
2223
2224 /*******************************************************************
2225  An aio_read wrapper that will deal with 64-bit sizes.
2226 ********************************************************************/
2227                                                                                                                                            
2228 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2229 {
2230 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2231         return aio_read64(aiocb);
2232 #elif defined(HAVE_AIO_READ)
2233         return aio_read(aiocb);
2234 #else
2235         errno = ENOSYS;
2236         return -1;
2237 #endif
2238 }
2239
2240 /*******************************************************************
2241  An aio_write wrapper that will deal with 64-bit sizes.
2242 ********************************************************************/
2243                                                                                                                                            
2244 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2245 {
2246 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2247         return aio_write64(aiocb);
2248 #elif defined(HAVE_AIO_WRITE)
2249         return aio_write(aiocb);
2250 #else
2251         errno = ENOSYS;
2252         return -1;
2253 #endif
2254 }
2255
2256 /*******************************************************************
2257  An aio_return wrapper that will deal with 64-bit sizes.
2258 ********************************************************************/
2259                                                                                                                                            
2260 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2261 {
2262 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2263         return aio_return64(aiocb);
2264 #elif defined(HAVE_AIO_RETURN)
2265         return aio_return(aiocb);
2266 #else
2267         errno = ENOSYS;
2268         return -1;
2269 #endif
2270 }
2271
2272 /*******************************************************************
2273  An aio_cancel wrapper that will deal with 64-bit sizes.
2274 ********************************************************************/
2275
2276 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2277 {
2278 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2279         return aio_cancel64(fd, aiocb);
2280 #elif defined(HAVE_AIO_CANCEL)
2281         return aio_cancel(fd, aiocb);
2282 #else
2283         errno = ENOSYS;
2284         return -1;
2285 #endif
2286 }
2287
2288 /*******************************************************************
2289  An aio_error wrapper that will deal with 64-bit sizes.
2290 ********************************************************************/
2291
2292 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2293 {
2294 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2295         return aio_error64(aiocb);
2296 #elif defined(HAVE_AIO_ERROR)
2297         return aio_error(aiocb);
2298 #else
2299         errno = ENOSYS;
2300         return -1;
2301 #endif
2302 }
2303
2304 /*******************************************************************
2305  An aio_fsync wrapper that will deal with 64-bit sizes.
2306 ********************************************************************/
2307
2308 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2309 {
2310 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2311         return aio_fsync64(op, aiocb);
2312 #elif defined(HAVE_AIO_FSYNC)
2313         return aio_fsync(op, aiocb);
2314 #else
2315         errno = ENOSYS;
2316         return -1;
2317 #endif
2318 }
2319
2320 /*******************************************************************
2321  An aio_fsync wrapper that will deal with 64-bit sizes.
2322 ********************************************************************/
2323
2324 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2325 {
2326 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2327         return aio_suspend64(cblist, n, timeout);
2328 #elif defined(HAVE_AIO_FSYNC)
2329         return aio_suspend(cblist, n, timeout);
2330 #else
2331         errno = ENOSYS;
2332         return -1;
2333 #endif
2334 }
2335 #else /* !WITH_AIO */
2336
2337 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2338 {
2339         errno = ENOSYS;
2340         return -1;
2341 }
2342
2343 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2344 {
2345         errno = ENOSYS;
2346         return -1;
2347 }
2348
2349 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2350 {
2351         errno = ENOSYS;
2352         return -1;
2353 }
2354
2355 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2356 {
2357         errno = ENOSYS;
2358         return -1;
2359 }
2360
2361 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2362 {
2363         errno = ENOSYS;
2364         return -1;
2365 }
2366
2367 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2368 {
2369         errno = ENOSYS;
2370         return -1;
2371 }
2372
2373 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2374 {
2375         errno = ENOSYS;
2376         return -1;
2377 }
2378 #endif /* WITH_AIO */
2379
2380 int sys_getpeereid( int s, uid_t *uid)
2381 {
2382 #if defined(HAVE_PEERCRED)
2383         struct ucred cred;
2384         socklen_t cred_len = sizeof(struct ucred);
2385         int ret;
2386
2387         ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2388         if (ret != 0) {
2389                 return -1;
2390         }
2391
2392         if (cred_len != sizeof(struct ucred)) {
2393                 errno = EINVAL;
2394                 return -1;
2395         }
2396
2397         *uid = cred.uid;
2398         return 0;
2399 #else
2400         errno = ENOSYS;
2401         return -1;
2402 #endif
2403 }
2404
2405 int sys_getnameinfo(const struct sockaddr *psa,
2406                         socklen_t salen,
2407                         char *host,
2408                         size_t hostlen,
2409                         char *service,
2410                         size_t servlen,
2411                         int flags)
2412 {
2413         /*
2414          * For Solaris we must make sure salen is the
2415          * correct length for the incoming sa_family.
2416          */
2417
2418         if (salen == sizeof(struct sockaddr_storage)) {
2419                 salen = sizeof(struct sockaddr_in);
2420 #if defined(HAVE_IPV6)
2421                 if (psa->sa_family == AF_INET6) {
2422                         salen = sizeof(struct sockaddr_in6);
2423                 }
2424 #endif
2425         }
2426         return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2427 }
2428
2429 int sys_connect(int fd, const struct sockaddr * addr)
2430 {
2431         socklen_t salen = -1;
2432
2433         if (addr->sa_family == AF_INET) {
2434             salen = sizeof(struct sockaddr_in);
2435         } else if (addr->sa_family == AF_UNIX) {
2436             salen = sizeof(struct sockaddr_un);
2437         }
2438 #if defined(HAVE_IPV6)
2439         else if (addr->sa_family == AF_INET6) {
2440             salen = sizeof(struct sockaddr_in6);
2441         }
2442 #endif
2443
2444         return connect(fd, addr, salen);
2445 }