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