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