s3: optimize strict allocate for XFS on IRIX
[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 /* This define hasn't made it into the glibc capabilities header yet. */
912 #ifndef SECURE_NO_SETUID_FIXUP
913 #define SECURE_NO_SETUID_FIXUP          2
914 #endif
915
916 /**************************************************************************
917  Try and abstract process capabilities (for systems that have them).
918 ****************************************************************************/
919
920 /* Set the POSIX capabilities needed for the given purpose into the effective
921  * capability set of the current process. Make sure they are always removed
922  * from the inheritable set, because there is no circumstance in which our
923  * children should inherit our elevated privileges.
924  */
925 static bool set_process_capability(enum smbd_capability capability,
926                                    bool enable)
927 {
928         cap_value_t cap_vals[2] = {0};
929         int num_cap_vals = 0;
930
931         cap_t cap;
932
933 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
934         /* On Linux, make sure that any capabilities we grab are sticky
935          * across UID changes. We expect that this would allow us to keep both
936          * the effective and permitted capability sets, but as of circa 2.6.16,
937          * only the permitted set is kept. It is a bug (which we work around)
938          * that the effective set is lost, but we still require the effective
939          * set to be kept.
940          */
941         if (!prctl(PR_GET_KEEPCAPS)) {
942                 prctl(PR_SET_KEEPCAPS, 1);
943         }
944 #endif
945
946 #if defined(HAVE_PRCTL) && defined(PR_SET_SECUREBITS) && defined(SECURE_NO_SETUID_FIXUP)
947         /* New way of setting capabilities as "sticky". */
948
949         /*
950          * Use PR_SET_SECUREBITS to prevent setresuid()
951          * atomically dropping effective capabilities on
952          * uid change. Only available in Linux kernels
953          * 2.6.26 and above.
954          *
955          * See here:
956          * http://www.kernel.org/doc/man-pages/online/pages/man7/capabilities.7.html
957          * for details.
958          *
959          * Specifically the CAP_KILL capability we need
960          * to allow Linux threads under different euids
961          * to send signals to each other.
962          */
963
964         if (prctl(PR_SET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP)) {
965                 DEBUG(0,("set_process_capability: "
966                         "prctl PR_SET_SECUREBITS failed with error %s\n",
967                         strerror(errno) ));
968                 return false;
969         }
970 #endif
971
972         cap = cap_get_proc();
973         if (cap == NULL) {
974                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
975                         strerror(errno)));
976                 return False;
977         }
978
979         switch (capability) {
980                 case KERNEL_OPLOCK_CAPABILITY:
981 #ifdef CAP_NETWORK_MGT
982                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
983                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
984 #endif
985                         break;
986                 case DMAPI_ACCESS_CAPABILITY:
987 #ifdef CAP_DEVICE_MGT
988                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
989                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
990 #elif CAP_MKNOD
991                         /* Linux has CAP_MKNOD for DMAPI access. */
992                         cap_vals[num_cap_vals++] = CAP_MKNOD;
993 #endif
994                         break;
995                 case LEASE_CAPABILITY:
996 #ifdef CAP_LEASE
997                         cap_vals[num_cap_vals++] = CAP_LEASE;
998 #endif
999                         break;
1000                 case KILL_CAPABILITY:
1001 #ifdef CAP_KILL
1002                         cap_vals[num_cap_vals++] = CAP_KILL;
1003 #endif
1004                         break;
1005         }
1006
1007         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
1008
1009         if (num_cap_vals == 0) {
1010                 cap_free(cap);
1011                 return True;
1012         }
1013
1014         /*
1015          * Ensure the capability is effective. We assume that as a root
1016          * process it's always permitted.
1017          */
1018
1019         if (cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
1020                         enable ? CAP_SET : CAP_CLEAR) == -1) {
1021                 DEBUG(0, ("set_process_capability: cap_set_flag effective "
1022                         "failed (%d): %s\n",
1023                         (int)capability,
1024                         strerror(errno)));
1025                 cap_free(cap);
1026                 return false;
1027         }
1028
1029         /* We never want to pass capabilities down to our children, so make
1030          * sure they are not inherited.
1031          */
1032         if (cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals,
1033                         cap_vals, CAP_CLEAR) == -1) {
1034                 DEBUG(0, ("set_process_capability: cap_set_flag inheritable "
1035                         "failed (%d): %s\n",
1036                         (int)capability,
1037                         strerror(errno)));
1038                 cap_free(cap);
1039                 return false;
1040         }
1041
1042         if (cap_set_proc(cap) == -1) {
1043                 DEBUG(0, ("set_process_capability: cap_set_flag (%d) failed: %s\n",
1044                         (int)capability,
1045                         strerror(errno)));
1046                 cap_free(cap);
1047                 return False;
1048         }
1049
1050         cap_free(cap);
1051         return True;
1052 }
1053
1054 #endif /* HAVE_POSIX_CAPABILITIES */
1055
1056 /****************************************************************************
1057  Gain the oplock capability from the kernel if possible.
1058 ****************************************************************************/
1059
1060 void set_effective_capability(enum smbd_capability capability)
1061 {
1062 #if defined(HAVE_POSIX_CAPABILITIES)
1063         set_process_capability(capability, True);
1064 #endif /* HAVE_POSIX_CAPABILITIES */
1065 }
1066
1067 void drop_effective_capability(enum smbd_capability capability)
1068 {
1069 #if defined(HAVE_POSIX_CAPABILITIES)
1070         set_process_capability(capability, False);
1071 #endif /* HAVE_POSIX_CAPABILITIES */
1072 }
1073
1074 /**************************************************************************
1075  Wrapper for random().
1076 ****************************************************************************/
1077
1078 long sys_random(void)
1079 {
1080 #if defined(HAVE_RANDOM)
1081         return (long)random();
1082 #elif defined(HAVE_RAND)
1083         return (long)rand();
1084 #else
1085         DEBUG(0,("Error - no random function available !\n"));
1086         exit(1);
1087 #endif
1088 }
1089
1090 /**************************************************************************
1091  Wrapper for srandom().
1092 ****************************************************************************/
1093
1094 void sys_srandom(unsigned int seed)
1095 {
1096 #if defined(HAVE_SRANDOM)
1097         srandom(seed);
1098 #elif defined(HAVE_SRAND)
1099         srand(seed);
1100 #else
1101         DEBUG(0,("Error - no srandom function available !\n"));
1102         exit(1);
1103 #endif
1104 }
1105
1106 /**************************************************************************
1107  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
1108 ****************************************************************************/
1109
1110 int groups_max(void)
1111 {
1112 #if defined(SYSCONF_SC_NGROUPS_MAX)
1113         int ret = sysconf(_SC_NGROUPS_MAX);
1114         return (ret == -1) ? NGROUPS_MAX : ret;
1115 #else
1116         return NGROUPS_MAX;
1117 #endif
1118 }
1119
1120 /**************************************************************************
1121  Wrap setgroups and getgroups for systems that declare getgroups() as
1122  returning an array of gid_t, but actuall return an array of int.
1123 ****************************************************************************/
1124
1125 #if defined(HAVE_BROKEN_GETGROUPS)
1126 static int sys_broken_getgroups(int setlen, gid_t *gidset)
1127 {
1128         GID_T gid;
1129         GID_T *group_list;
1130         int i, ngroups;
1131
1132         if(setlen == 0) {
1133                 return getgroups(setlen, &gid);
1134         }
1135
1136         /*
1137          * Broken case. We need to allocate a
1138          * GID_T array of size setlen.
1139          */
1140
1141         if(setlen < 0) {
1142                 errno = EINVAL; 
1143                 return -1;
1144         } 
1145
1146         if (setlen == 0)
1147                 setlen = groups_max();
1148
1149         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1150                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
1151                 return -1;
1152         }
1153
1154         if((ngroups = getgroups(setlen, group_list)) < 0) {
1155                 int saved_errno = errno;
1156                 SAFE_FREE(group_list);
1157                 errno = saved_errno;
1158                 return -1;
1159         }
1160
1161         for(i = 0; i < ngroups; i++)
1162                 gidset[i] = (gid_t)group_list[i];
1163
1164         SAFE_FREE(group_list);
1165         return ngroups;
1166 }
1167
1168 static int sys_broken_setgroups(int setlen, gid_t *gidset)
1169 {
1170         GID_T *group_list;
1171         int i ; 
1172
1173         if (setlen == 0)
1174                 return 0 ;
1175
1176         if (setlen < 0 || setlen > groups_max()) {
1177                 errno = EINVAL; 
1178                 return -1;   
1179         }
1180
1181         /*
1182          * Broken case. We need to allocate a
1183          * GID_T array of size setlen.
1184          */
1185
1186         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1187                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1188                 return -1;    
1189         }
1190
1191         for(i = 0; i < setlen; i++) 
1192                 group_list[i] = (GID_T) gidset[i]; 
1193
1194         if(setgroups(setlen, group_list) != 0) {
1195                 int saved_errno = errno;
1196                 SAFE_FREE(group_list);
1197                 errno = saved_errno;
1198                 return -1;
1199         }
1200
1201         SAFE_FREE(group_list);
1202         return 0 ;
1203 }
1204
1205 #endif /* HAVE_BROKEN_GETGROUPS */
1206
1207 /* This is a list of systems that require the first GID passed to setgroups(2)
1208  * to be the effective GID. If your system is one of these, add it here.
1209  */
1210 #if defined (FREEBSD) || defined (DARWINOS)
1211 #define USE_BSD_SETGROUPS
1212 #endif
1213
1214 #if defined(USE_BSD_SETGROUPS)
1215 /* Depending on the particular BSD implementation, the first GID that is
1216  * passed to setgroups(2) will either be ignored or will set the credential's
1217  * effective GID. In either case, the right thing to do is to guarantee that
1218  * gidset[0] is the effective GID.
1219  */
1220 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1221 {
1222         gid_t *new_gidset = NULL;
1223         int max;
1224         int ret;
1225
1226         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1227         max = groups_max();
1228
1229         /* No group list, just make sure we are setting the efective GID. */
1230         if (setlen == 0) {
1231                 return setgroups(1, &primary_gid);
1232         }
1233
1234         /* If the primary gid is not the first array element, grow the array
1235          * and insert it at the front.
1236          */
1237         if (gidset[0] != primary_gid) {
1238                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1239                 if (new_gidset == NULL) {
1240                         return -1;
1241                 }
1242
1243                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1244                 new_gidset[0] = primary_gid;
1245                 setlen++;
1246         }
1247
1248         if (setlen > max) {
1249                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1250                         setlen, max));
1251                 setlen = max;
1252         }
1253
1254 #if defined(HAVE_BROKEN_GETGROUPS)
1255         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1256 #else
1257         ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1258 #endif
1259
1260         if (new_gidset) {
1261                 int errsav = errno;
1262                 SAFE_FREE(new_gidset);
1263                 errno = errsav;
1264         }
1265
1266         return ret;
1267 }
1268
1269 #endif /* USE_BSD_SETGROUPS */
1270
1271 /**************************************************************************
1272  Wrapper for getgroups. Deals with broken (int) case.
1273 ****************************************************************************/
1274
1275 int sys_getgroups(int setlen, gid_t *gidset)
1276 {
1277 #if defined(HAVE_BROKEN_GETGROUPS)
1278         return sys_broken_getgroups(setlen, gidset);
1279 #else
1280         return getgroups(setlen, gidset);
1281 #endif
1282 }
1283
1284 /**************************************************************************
1285  Wrapper for setgroups. Deals with broken (int) case and BSD case.
1286 ****************************************************************************/
1287
1288 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1289 {
1290 #if !defined(HAVE_SETGROUPS)
1291         errno = ENOSYS;
1292         return -1;
1293 #endif /* HAVE_SETGROUPS */
1294
1295 #if defined(USE_BSD_SETGROUPS)
1296         return sys_bsd_setgroups(primary_gid, setlen, gidset);
1297 #elif defined(HAVE_BROKEN_GETGROUPS)
1298         return sys_broken_setgroups(setlen, gidset);
1299 #else
1300         return setgroups(setlen, gidset);
1301 #endif
1302 }
1303
1304 /**************************************************************************
1305  Wrappers for setpwent(), getpwent() and endpwent()
1306 ****************************************************************************/
1307
1308 void sys_setpwent(void)
1309 {
1310         setpwent();
1311 }
1312
1313 struct passwd *sys_getpwent(void)
1314 {
1315         return getpwent();
1316 }
1317
1318 void sys_endpwent(void)
1319 {
1320         endpwent();
1321 }
1322
1323 /**************************************************************************
1324  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
1325 ****************************************************************************/
1326
1327
1328 struct passwd *sys_getpwnam(const char *name)
1329 {
1330         return getpwnam(name);
1331 }
1332
1333 struct passwd *sys_getpwuid(uid_t uid)
1334 {
1335         return getpwuid(uid);
1336 }
1337
1338 struct group *sys_getgrnam(const char *name)
1339 {
1340         return getgrnam(name);
1341 }
1342
1343 struct group *sys_getgrgid(gid_t gid)
1344 {
1345         return getgrgid(gid);
1346 }
1347
1348 /**************************************************************************
1349  Extract a command into an arg list.
1350 ****************************************************************************/
1351
1352 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1353 {
1354         char *trunc_cmd;
1355         char *saveptr;
1356         char *ptr;
1357         int argcl;
1358         char **argl = NULL;
1359         int i;
1360
1361         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1362                 DEBUG(0, ("talloc failed\n"));
1363                 goto nomem;
1364         }
1365
1366         if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1367                 TALLOC_FREE(trunc_cmd);
1368                 errno = EINVAL;
1369                 return NULL;
1370         }
1371
1372         /*
1373          * Count the args.
1374          */
1375
1376         for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1377                 argcl++;
1378
1379         TALLOC_FREE(trunc_cmd);
1380
1381         if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1382                 goto nomem;
1383         }
1384
1385         /*
1386          * Now do the extraction.
1387          */
1388
1389         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1390                 goto nomem;
1391         }
1392
1393         ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1394         i = 0;
1395
1396         if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1397                 goto nomem;
1398         }
1399
1400         while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1401
1402                 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1403                         goto nomem;
1404                 }
1405         }
1406
1407         argl[i++] = NULL;
1408         TALLOC_FREE(trunc_cmd);
1409         return argl;
1410
1411  nomem:
1412         DEBUG(0, ("talloc failed\n"));
1413         TALLOC_FREE(trunc_cmd);
1414         TALLOC_FREE(argl);
1415         errno = ENOMEM;
1416         return NULL;
1417 }
1418
1419 /**************************************************************************
1420  Wrapper for popen. Safer as it doesn't search a path.
1421  Modified from the glibc sources.
1422  modified by tridge to return a file descriptor. We must kick our FILE* habit
1423 ****************************************************************************/
1424
1425 typedef struct _popen_list
1426 {
1427         int fd;
1428         pid_t child_pid;
1429         struct _popen_list *next;
1430 } popen_list;
1431
1432 static popen_list *popen_chain;
1433
1434 int sys_popen(const char *command)
1435 {
1436         int parent_end, child_end;
1437         int pipe_fds[2];
1438         popen_list *entry = NULL;
1439         char **argl = NULL;
1440
1441         if (pipe(pipe_fds) < 0)
1442                 return -1;
1443
1444         parent_end = pipe_fds[0];
1445         child_end = pipe_fds[1];
1446
1447         if (!*command) {
1448                 errno = EINVAL;
1449                 goto err_exit;
1450         }
1451
1452         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1453                 goto err_exit;
1454
1455         ZERO_STRUCTP(entry);
1456
1457         /*
1458          * Extract the command and args into a NULL terminated array.
1459          */
1460
1461         if(!(argl = extract_args(NULL, command)))
1462                 goto err_exit;
1463
1464         entry->child_pid = sys_fork();
1465
1466         if (entry->child_pid == -1) {
1467                 goto err_exit;
1468         }
1469
1470         if (entry->child_pid == 0) {
1471
1472                 /*
1473                  * Child !
1474                  */
1475
1476                 int child_std_end = STDOUT_FILENO;
1477                 popen_list *p;
1478
1479                 close(parent_end);
1480                 if (child_end != child_std_end) {
1481                         dup2 (child_end, child_std_end);
1482                         close (child_end);
1483                 }
1484
1485                 /*
1486                  * POSIX.2:  "popen() shall ensure that any streams from previous
1487                  * popen() calls that remain open in the parent process are closed
1488                  * in the new child process."
1489                  */
1490
1491                 for (p = popen_chain; p; p = p->next)
1492                         close(p->fd);
1493
1494                 execv(argl[0], argl);
1495                 _exit (127);
1496         }
1497
1498         /*
1499          * Parent.
1500          */
1501
1502         close (child_end);
1503         TALLOC_FREE(argl);
1504
1505         /* Link into popen_chain. */
1506         entry->next = popen_chain;
1507         popen_chain = entry;
1508         entry->fd = parent_end;
1509
1510         return entry->fd;
1511
1512 err_exit:
1513
1514         SAFE_FREE(entry);
1515         SAFE_FREE(argl);
1516         close(pipe_fds[0]);
1517         close(pipe_fds[1]);
1518         return -1;
1519 }
1520
1521 /**************************************************************************
1522  Wrapper for pclose. Modified from the glibc sources.
1523 ****************************************************************************/
1524
1525 int sys_pclose(int fd)
1526 {
1527         int wstatus;
1528         popen_list **ptr = &popen_chain;
1529         popen_list *entry = NULL;
1530         pid_t wait_pid;
1531         int status = -1;
1532
1533         /* Unlink from popen_chain. */
1534         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1535                 if ((*ptr)->fd == fd) {
1536                         entry = *ptr;
1537                         *ptr = (*ptr)->next;
1538                         status = 0;
1539                         break;
1540                 }
1541         }
1542
1543         if (status < 0 || close(entry->fd) < 0)
1544                 return -1;
1545
1546         /*
1547          * As Samba is catching and eating child process
1548          * exits we don't really care about the child exit
1549          * code, a -1 with errno = ECHILD will do fine for us.
1550          */
1551
1552         do {
1553                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1554         } while (wait_pid == -1 && errno == EINTR);
1555
1556         SAFE_FREE(entry);
1557
1558         if (wait_pid == -1)
1559                 return -1;
1560         return wstatus;
1561 }
1562
1563 /**************************************************************************
1564  Wrapper for Admin Logs.
1565 ****************************************************************************/
1566
1567  void sys_adminlog(int priority, const char *format_str, ...) 
1568 {
1569         va_list ap;
1570         int ret;
1571         char *msgbuf = NULL;
1572
1573         va_start( ap, format_str );
1574         ret = vasprintf( &msgbuf, format_str, ap );
1575         va_end( ap );
1576
1577         if (ret == -1)
1578                 return;
1579
1580 #if defined(HAVE_SYSLOG)
1581         syslog( priority, "%s", msgbuf );
1582 #else
1583         DEBUG(0,("%s", msgbuf ));
1584 #endif
1585         SAFE_FREE(msgbuf);
1586 }
1587
1588 /******** Solaris EA helper function prototypes ********/
1589 #ifdef HAVE_ATTROPEN
1590 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1591 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1592 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1593 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1594 static int solaris_unlinkat(int attrdirfd, const char *name);
1595 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1596 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1597 #endif
1598
1599 /**************************************************************************
1600  Wrappers for extented attribute calls. Based on the Linux package with
1601  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1602 ****************************************************************************/
1603
1604 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1605 {
1606 #if defined(HAVE_GETXATTR)
1607 #ifndef XATTR_ADD_OPT
1608         return getxattr(path, name, value, size);
1609 #else
1610         int options = 0;
1611         return getxattr(path, name, value, size, 0, options);
1612 #endif
1613 #elif defined(HAVE_GETEA)
1614         return getea(path, name, value, size);
1615 #elif defined(HAVE_EXTATTR_GET_FILE)
1616         char *s;
1617         ssize_t retval;
1618         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1619                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1620         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1621         /*
1622          * The BSD implementation has a nasty habit of silently truncating
1623          * the returned value to the size of the buffer, so we have to check
1624          * that the buffer is large enough to fit the returned value.
1625          */
1626         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1627                 if(retval > size) {
1628                         errno = ERANGE;
1629                         return -1;
1630                 }
1631                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1632                         return retval;
1633         }
1634
1635         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1636         return -1;
1637 #elif defined(HAVE_ATTR_GET)
1638         int retval, flags = 0;
1639         int valuelength = (int)size;
1640         char *attrname = strchr(name,'.') + 1;
1641
1642         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1643
1644         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1645
1646         return retval ? retval : valuelength;
1647 #elif defined(HAVE_ATTROPEN)
1648         ssize_t ret = -1;
1649         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1650         if (attrfd >= 0) {
1651                 ret = solaris_read_xattr(attrfd, value, size);
1652                 close(attrfd);
1653         }
1654         return ret;
1655 #else
1656         errno = ENOSYS;
1657         return -1;
1658 #endif
1659 }
1660
1661 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1662 {
1663 #if defined(HAVE_LGETXATTR)
1664         return lgetxattr(path, name, value, size);
1665 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1666         int options = XATTR_NOFOLLOW;
1667         return getxattr(path, name, value, size, 0, options);
1668 #elif defined(HAVE_LGETEA)
1669         return lgetea(path, name, value, size);
1670 #elif defined(HAVE_EXTATTR_GET_LINK)
1671         char *s;
1672         ssize_t retval;
1673         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1674                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1675         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1676
1677         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1678                 if(retval > size) {
1679                         errno = ERANGE;
1680                         return -1;
1681                 }
1682                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1683                         return retval;
1684         }
1685
1686         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1687         return -1;
1688 #elif defined(HAVE_ATTR_GET)
1689         int retval, flags = ATTR_DONTFOLLOW;
1690         int valuelength = (int)size;
1691         char *attrname = strchr(name,'.') + 1;
1692
1693         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1694
1695         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1696
1697         return retval ? retval : valuelength;
1698 #elif defined(HAVE_ATTROPEN)
1699         ssize_t ret = -1;
1700         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1701         if (attrfd >= 0) {
1702                 ret = solaris_read_xattr(attrfd, value, size);
1703                 close(attrfd);
1704         }
1705         return ret;
1706 #else
1707         errno = ENOSYS;
1708         return -1;
1709 #endif
1710 }
1711
1712 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1713 {
1714 #if defined(HAVE_FGETXATTR)
1715 #ifndef XATTR_ADD_OPT
1716         return fgetxattr(filedes, name, value, size);
1717 #else
1718         int options = 0;
1719         return fgetxattr(filedes, name, value, size, 0, options);
1720 #endif
1721 #elif defined(HAVE_FGETEA)
1722         return fgetea(filedes, name, value, size);
1723 #elif defined(HAVE_EXTATTR_GET_FD)
1724         char *s;
1725         ssize_t retval;
1726         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1727                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1728         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1729
1730         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1731                 if(retval > size) {
1732                         errno = ERANGE;
1733                         return -1;
1734                 }
1735                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1736                         return retval;
1737         }
1738
1739         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1740         return -1;
1741 #elif defined(HAVE_ATTR_GETF)
1742         int retval, flags = 0;
1743         int valuelength = (int)size;
1744         char *attrname = strchr(name,'.') + 1;
1745
1746         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1747
1748         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1749
1750         return retval ? retval : valuelength;
1751 #elif defined(HAVE_ATTROPEN)
1752         ssize_t ret = -1;
1753         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1754         if (attrfd >= 0) {
1755                 ret = solaris_read_xattr(attrfd, value, size);
1756                 close(attrfd);
1757         }
1758         return ret;
1759 #else
1760         errno = ENOSYS;
1761         return -1;
1762 #endif
1763 }
1764
1765 #if defined(HAVE_EXTATTR_LIST_FILE)
1766
1767 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1768
1769 static struct {
1770         int space;
1771         const char *name;
1772         size_t len;
1773
1774 extattr[] = {
1775         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1776         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1777 };
1778
1779 typedef union {
1780         const char *path;
1781         int filedes;
1782 } extattr_arg;
1783
1784 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1785 {
1786         ssize_t list_size, total_size = 0;
1787         int i, t, len;
1788         char *buf;
1789         /* Iterate through extattr(2) namespaces */
1790         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1791                 switch(type) {
1792 #if defined(HAVE_EXTATTR_LIST_FILE)
1793                         case 0:
1794                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1795                                 break;
1796 #endif
1797 #if defined(HAVE_EXTATTR_LIST_LINK)
1798                         case 1:
1799                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1800                                 break;
1801 #endif
1802 #if defined(HAVE_EXTATTR_LIST_FD)
1803                         case 2:
1804                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1805                                 break;
1806 #endif
1807                         default:
1808                                 errno = ENOSYS;
1809                                 return -1;
1810                 }
1811                 /* Some error happend. Errno should be set by the previous call */
1812                 if(list_size < 0)
1813                         return -1;
1814                 /* No attributes */
1815                 if(list_size == 0)
1816                         continue;
1817                 /* XXX: Call with an empty buffer may be used to calculate
1818                    necessary buffer size. Unfortunately, we can't say, how
1819                    many attributes were returned, so here is the potential
1820                    problem with the emulation.
1821                 */
1822                 if(list == NULL) {
1823                         /* Take the worse case of one char attribute names - 
1824                            two bytes per name plus one more for sanity.
1825                         */
1826                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1827                         continue;
1828                 }
1829                 /* Count necessary offset to fit namespace prefixes */
1830                 len = 0;
1831                 for(i = 0; i < list_size; i += list[i] + 1)
1832                         len += extattr[t].len;
1833
1834                 total_size += list_size + len;
1835                 /* Buffer is too small to fit the results */
1836                 if(total_size > size) {
1837                         errno = ERANGE;
1838                         return -1;
1839                 }
1840                 /* Shift results back, so we can prepend prefixes */
1841                 buf = memmove(list + len, list, list_size);
1842
1843                 for(i = 0; i < list_size; i += len + 1) {
1844                         len = buf[i];
1845                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1846                         list += extattr[t].len;
1847                         strncpy(list, buf + i + 1, len);
1848                         list[len] = '\0';
1849                         list += len + 1;
1850                 }
1851                 size -= total_size;
1852         }
1853         return total_size;
1854 }
1855
1856 #endif
1857
1858 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1859 static char attr_buffer[ATTR_MAX_VALUELEN];
1860
1861 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1862 {
1863         int retval = 0, index;
1864         attrlist_cursor_t *cursor = 0;
1865         int total_size = 0;
1866         attrlist_t * al = (attrlist_t *)attr_buffer;
1867         attrlist_ent_t *ae;
1868         size_t ent_size, left = size;
1869         char *bp = list;
1870
1871         while (True) {
1872             if (filedes)
1873                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1874             else
1875                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1876             if (retval) break;
1877             for (index = 0; index < al->al_count; index++) {
1878                 ae = ATTR_ENTRY(attr_buffer, index);
1879                 ent_size = strlen(ae->a_name) + sizeof("user.");
1880                 if (left >= ent_size) {
1881                     strncpy(bp, "user.", sizeof("user."));
1882                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1883                     bp += ent_size;
1884                     left -= ent_size;
1885                 } else if (size) {
1886                     errno = ERANGE;
1887                     retval = -1;
1888                     break;
1889                 }
1890                 total_size += ent_size;
1891             }
1892             if (al->al_more == 0) break;
1893         }
1894         if (retval == 0) {
1895             flags |= ATTR_ROOT;
1896             cursor = 0;
1897             while (True) {
1898                 if (filedes)
1899                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1900                 else
1901                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1902                 if (retval) break;
1903                 for (index = 0; index < al->al_count; index++) {
1904                     ae = ATTR_ENTRY(attr_buffer, index);
1905                     ent_size = strlen(ae->a_name) + sizeof("system.");
1906                     if (left >= ent_size) {
1907                         strncpy(bp, "system.", sizeof("system."));
1908                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1909                         bp += ent_size;
1910                         left -= ent_size;
1911                     } else if (size) {
1912                         errno = ERANGE;
1913                         retval = -1;
1914                         break;
1915                     }
1916                     total_size += ent_size;
1917                 }
1918                 if (al->al_more == 0) break;
1919             }
1920         }
1921         return (ssize_t)(retval ? retval : total_size);
1922 }
1923
1924 #endif
1925
1926 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1927 {
1928 #if defined(HAVE_LISTXATTR)
1929 #ifndef XATTR_ADD_OPT
1930         return listxattr(path, list, size);
1931 #else
1932         int options = 0;
1933         return listxattr(path, list, size, options);
1934 #endif
1935 #elif defined(HAVE_LISTEA)
1936         return listea(path, list, size);
1937 #elif defined(HAVE_EXTATTR_LIST_FILE)
1938         extattr_arg arg;
1939         arg.path = path;
1940         return bsd_attr_list(0, arg, list, size);
1941 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1942         return irix_attr_list(path, 0, list, size, 0);
1943 #elif defined(HAVE_ATTROPEN)
1944         ssize_t ret = -1;
1945         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1946         if (attrdirfd >= 0) {
1947                 ret = solaris_list_xattr(attrdirfd, list, size);
1948                 close(attrdirfd);
1949         }
1950         return ret;
1951 #else
1952         errno = ENOSYS;
1953         return -1;
1954 #endif
1955 }
1956
1957 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1958 {
1959 #if defined(HAVE_LLISTXATTR)
1960         return llistxattr(path, list, size);
1961 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1962         int options = XATTR_NOFOLLOW;
1963         return listxattr(path, list, size, options);
1964 #elif defined(HAVE_LLISTEA)
1965         return llistea(path, list, size);
1966 #elif defined(HAVE_EXTATTR_LIST_LINK)
1967         extattr_arg arg;
1968         arg.path = path;
1969         return bsd_attr_list(1, arg, list, size);
1970 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1971         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1972 #elif defined(HAVE_ATTROPEN)
1973         ssize_t ret = -1;
1974         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1975         if (attrdirfd >= 0) {
1976                 ret = solaris_list_xattr(attrdirfd, list, size);
1977                 close(attrdirfd);
1978         }
1979         return ret;
1980 #else
1981         errno = ENOSYS;
1982         return -1;
1983 #endif
1984 }
1985
1986 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1987 {
1988 #if defined(HAVE_FLISTXATTR)
1989 #ifndef XATTR_ADD_OPT
1990         return flistxattr(filedes, list, size);
1991 #else
1992         int options = 0;
1993         return flistxattr(filedes, list, size, options);
1994 #endif
1995 #elif defined(HAVE_FLISTEA)
1996         return flistea(filedes, list, size);
1997 #elif defined(HAVE_EXTATTR_LIST_FD)
1998         extattr_arg arg;
1999         arg.filedes = filedes;
2000         return bsd_attr_list(2, arg, list, size);
2001 #elif defined(HAVE_ATTR_LISTF)
2002         return irix_attr_list(NULL, filedes, list, size, 0);
2003 #elif defined(HAVE_ATTROPEN)
2004         ssize_t ret = -1;
2005         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
2006         if (attrdirfd >= 0) {
2007                 ret = solaris_list_xattr(attrdirfd, list, size);
2008                 close(attrdirfd);
2009         }
2010         return ret;
2011 #else
2012         errno = ENOSYS;
2013         return -1;
2014 #endif
2015 }
2016
2017 int sys_removexattr (const char *path, const char *name)
2018 {
2019 #if defined(HAVE_REMOVEXATTR)
2020 #ifndef XATTR_ADD_OPT
2021         return removexattr(path, name);
2022 #else
2023         int options = 0;
2024         return removexattr(path, name, options);
2025 #endif
2026 #elif defined(HAVE_REMOVEEA)
2027         return removeea(path, name);
2028 #elif defined(HAVE_EXTATTR_DELETE_FILE)
2029         char *s;
2030         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2031                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2032         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2033
2034         return extattr_delete_file(path, attrnamespace, attrname);
2035 #elif defined(HAVE_ATTR_REMOVE)
2036         int flags = 0;
2037         char *attrname = strchr(name,'.') + 1;
2038
2039         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2040
2041         return attr_remove(path, attrname, flags);
2042 #elif defined(HAVE_ATTROPEN)
2043         int ret = -1;
2044         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
2045         if (attrdirfd >= 0) {
2046                 ret = solaris_unlinkat(attrdirfd, name);
2047                 close(attrdirfd);
2048         }
2049         return ret;
2050 #else
2051         errno = ENOSYS;
2052         return -1;
2053 #endif
2054 }
2055
2056 int sys_lremovexattr (const char *path, const char *name)
2057 {
2058 #if defined(HAVE_LREMOVEXATTR)
2059         return lremovexattr(path, name);
2060 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
2061         int options = XATTR_NOFOLLOW;
2062         return removexattr(path, name, options);
2063 #elif defined(HAVE_LREMOVEEA)
2064         return lremoveea(path, name);
2065 #elif defined(HAVE_EXTATTR_DELETE_LINK)
2066         char *s;
2067         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2068                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2069         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2070
2071         return extattr_delete_link(path, attrnamespace, attrname);
2072 #elif defined(HAVE_ATTR_REMOVE)
2073         int flags = ATTR_DONTFOLLOW;
2074         char *attrname = strchr(name,'.') + 1;
2075
2076         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2077
2078         return attr_remove(path, attrname, flags);
2079 #elif defined(HAVE_ATTROPEN)
2080         int ret = -1;
2081         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
2082         if (attrdirfd >= 0) {
2083                 ret = solaris_unlinkat(attrdirfd, name);
2084                 close(attrdirfd);
2085         }
2086         return ret;
2087 #else
2088         errno = ENOSYS;
2089         return -1;
2090 #endif
2091 }
2092
2093 int sys_fremovexattr (int filedes, const char *name)
2094 {
2095 #if defined(HAVE_FREMOVEXATTR)
2096 #ifndef XATTR_ADD_OPT
2097         return fremovexattr(filedes, name);
2098 #else
2099         int options = 0;
2100         return fremovexattr(filedes, name, options);
2101 #endif
2102 #elif defined(HAVE_FREMOVEEA)
2103         return fremoveea(filedes, name);
2104 #elif defined(HAVE_EXTATTR_DELETE_FD)
2105         char *s;
2106         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2107                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2108         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2109
2110         return extattr_delete_fd(filedes, attrnamespace, attrname);
2111 #elif defined(HAVE_ATTR_REMOVEF)
2112         int flags = 0;
2113         char *attrname = strchr(name,'.') + 1;
2114
2115         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2116
2117         return attr_removef(filedes, attrname, flags);
2118 #elif defined(HAVE_ATTROPEN)
2119         int ret = -1;
2120         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
2121         if (attrdirfd >= 0) {
2122                 ret = solaris_unlinkat(attrdirfd, name);
2123                 close(attrdirfd);
2124         }
2125         return ret;
2126 #else
2127         errno = ENOSYS;
2128         return -1;
2129 #endif
2130 }
2131
2132 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2133 {
2134 #if defined(HAVE_SETXATTR)
2135 #ifndef XATTR_ADD_OPT
2136         return setxattr(path, name, value, size, flags);
2137 #else
2138         int options = 0;
2139         return setxattr(path, name, value, size, 0, options);
2140 #endif
2141 #elif defined(HAVE_SETEA)
2142         return setea(path, name, value, size, flags);
2143 #elif defined(HAVE_EXTATTR_SET_FILE)
2144         char *s;
2145         int retval = 0;
2146         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2147                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2148         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2149         if (flags) {
2150                 /* Check attribute existence */
2151                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
2152                 if (retval < 0) {
2153                         /* REPLACE attribute, that doesn't exist */
2154                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2155                                 errno = ENOATTR;
2156                                 return -1;
2157                         }
2158                         /* Ignore other errors */
2159                 }
2160                 else {
2161                         /* CREATE attribute, that already exists */
2162                         if (flags & XATTR_CREATE) {
2163                                 errno = EEXIST;
2164                                 return -1;
2165                         }
2166                 }
2167         }
2168         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
2169         return (retval < 0) ? -1 : 0;
2170 #elif defined(HAVE_ATTR_SET)
2171         int myflags = 0;
2172         char *attrname = strchr(name,'.') + 1;
2173
2174         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2175         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2176         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2177
2178         return attr_set(path, attrname, (const char *)value, size, myflags);
2179 #elif defined(HAVE_ATTROPEN)
2180         int ret = -1;
2181         int myflags = O_RDWR;
2182         int attrfd;
2183         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2184         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2185         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2186         if (attrfd >= 0) {
2187                 ret = solaris_write_xattr(attrfd, value, size);
2188                 close(attrfd);
2189         }
2190         return ret;
2191 #else
2192         errno = ENOSYS;
2193         return -1;
2194 #endif
2195 }
2196
2197 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2198 {
2199 #if defined(HAVE_LSETXATTR)
2200         return lsetxattr(path, name, value, size, flags);
2201 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
2202         int options = XATTR_NOFOLLOW;
2203         return setxattr(path, name, value, size, 0, options);
2204 #elif defined(LSETEA)
2205         return lsetea(path, name, value, size, flags);
2206 #elif defined(HAVE_EXTATTR_SET_LINK)
2207         char *s;
2208         int retval = 0;
2209         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2210                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2211         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2212         if (flags) {
2213                 /* Check attribute existence */
2214                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
2215                 if (retval < 0) {
2216                         /* REPLACE attribute, that doesn't exist */
2217                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2218                                 errno = ENOATTR;
2219                                 return -1;
2220                         }
2221                         /* Ignore other errors */
2222                 }
2223                 else {
2224                         /* CREATE attribute, that already exists */
2225                         if (flags & XATTR_CREATE) {
2226                                 errno = EEXIST;
2227                                 return -1;
2228                         }
2229                 }
2230         }
2231
2232         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2233         return (retval < 0) ? -1 : 0;
2234 #elif defined(HAVE_ATTR_SET)
2235         int myflags = ATTR_DONTFOLLOW;
2236         char *attrname = strchr(name,'.') + 1;
2237
2238         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2239         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2240         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2241
2242         return attr_set(path, attrname, (const char *)value, size, myflags);
2243 #elif defined(HAVE_ATTROPEN)
2244         int ret = -1;
2245         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2246         int attrfd;
2247         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2248         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2249         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2250         if (attrfd >= 0) {
2251                 ret = solaris_write_xattr(attrfd, value, size);
2252                 close(attrfd);
2253         }
2254         return ret;
2255 #else
2256         errno = ENOSYS;
2257         return -1;
2258 #endif
2259 }
2260
2261 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2262 {
2263 #if defined(HAVE_FSETXATTR)
2264 #ifndef XATTR_ADD_OPT
2265         return fsetxattr(filedes, name, value, size, flags);
2266 #else
2267         int options = 0;
2268         return fsetxattr(filedes, name, value, size, 0, options);
2269 #endif
2270 #elif defined(HAVE_FSETEA)
2271         return fsetea(filedes, name, value, size, flags);
2272 #elif defined(HAVE_EXTATTR_SET_FD)
2273         char *s;
2274         int retval = 0;
2275         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2276                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2277         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2278         if (flags) {
2279                 /* Check attribute existence */
2280                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2281                 if (retval < 0) {
2282                         /* REPLACE attribute, that doesn't exist */
2283                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2284                                 errno = ENOATTR;
2285                                 return -1;
2286                         }
2287                         /* Ignore other errors */
2288                 }
2289                 else {
2290                         /* CREATE attribute, that already exists */
2291                         if (flags & XATTR_CREATE) {
2292                                 errno = EEXIST;
2293                                 return -1;
2294                         }
2295                 }
2296         }
2297         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2298         return (retval < 0) ? -1 : 0;
2299 #elif defined(HAVE_ATTR_SETF)
2300         int myflags = 0;
2301         char *attrname = strchr(name,'.') + 1;
2302
2303         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2304         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2305         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2306
2307         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2308 #elif defined(HAVE_ATTROPEN)
2309         int ret = -1;
2310         int myflags = O_RDWR | O_XATTR;
2311         int attrfd;
2312         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2313         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2314         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2315         if (attrfd >= 0) {
2316                 ret = solaris_write_xattr(attrfd, value, size);
2317                 close(attrfd);
2318         }
2319         return ret;
2320 #else
2321         errno = ENOSYS;
2322         return -1;
2323 #endif
2324 }
2325
2326 /**************************************************************************
2327  helper functions for Solaris' EA support
2328 ****************************************************************************/
2329 #ifdef HAVE_ATTROPEN
2330 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2331 {
2332         struct stat sbuf;
2333
2334         if (fstat(attrfd, &sbuf) == -1) {
2335                 errno = ENOATTR;
2336                 return -1;
2337         }
2338
2339         /* This is to return the current size of the named extended attribute */
2340         if (size == 0) {
2341                 return sbuf.st_size;
2342         }
2343
2344         /* check size and read xattr */
2345         if (sbuf.st_size > size) {
2346                 errno = ERANGE;
2347                 return -1;
2348         }
2349
2350         return read(attrfd, value, sbuf.st_size);
2351 }
2352
2353 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2354 {
2355         ssize_t len = 0;
2356         DIR *dirp;
2357         struct dirent *de;
2358         int newfd = dup(attrdirfd);
2359         /* CAUTION: The originating file descriptor should not be
2360                     used again following the call to fdopendir().
2361                     For that reason we dup() the file descriptor
2362                     here to make things more clear. */
2363         dirp = fdopendir(newfd);
2364
2365         while ((de = readdir(dirp))) {
2366                 size_t listlen = strlen(de->d_name);
2367                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2368                         /* we don't want "." and ".." here: */
2369                         DEBUG(10,("skipped EA %s\n",de->d_name));
2370                         continue;
2371                 }
2372
2373                 if (size == 0) {
2374                         /* return the current size of the list of extended attribute names*/
2375                         len += listlen + 1;
2376                 } else {
2377                         /* check size and copy entrieÑ• + nul into list. */
2378                         if ((len + listlen + 1) > size) {
2379                                 errno = ERANGE;
2380                                 len = -1;
2381                                 break;
2382                         } else {
2383                                 safe_strcpy(list + len, de->d_name, listlen);
2384                                 len += listlen;
2385                                 list[len] = '\0';
2386                                 ++len;
2387                         }
2388                 }
2389         }
2390
2391         if (closedir(dirp) == -1) {
2392                 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2393                 return -1;
2394         }
2395         return len;
2396 }
2397
2398 static int solaris_unlinkat(int attrdirfd, const char *name)
2399 {
2400         if (unlinkat(attrdirfd, name, 0) == -1) {
2401                 if (errno == ENOENT) {
2402                         errno = ENOATTR;
2403                 }
2404                 return -1;
2405         }
2406         return 0;
2407 }
2408
2409 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2410 {
2411         int filedes = attropen(path, attrpath, oflag, mode);
2412         if (filedes == -1) {
2413                 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2414                 if (errno == EINVAL) {
2415                         errno = ENOTSUP;
2416                 } else {
2417                         errno = ENOATTR;
2418                 }
2419         }
2420         return filedes;
2421 }
2422
2423 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2424 {
2425         int filedes = openat(fildes, path, oflag, mode);
2426         if (filedes == -1) {
2427                 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2428                 if (errno == EINVAL) {
2429                         errno = ENOTSUP;
2430                 } else {
2431                         errno = ENOATTR;
2432                 }
2433         }
2434         return filedes;
2435 }
2436
2437 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2438 {
2439         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2440                 return 0;
2441         } else {
2442                 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2443                 return -1;
2444         }
2445 }
2446 #endif /*HAVE_ATTROPEN*/
2447
2448
2449 /****************************************************************************
2450  Return the major devicenumber for UNIX extensions.
2451 ****************************************************************************/
2452
2453 uint32 unix_dev_major(SMB_DEV_T dev)
2454 {
2455 #if defined(HAVE_DEVICE_MAJOR_FN)
2456         return (uint32)major(dev);
2457 #else
2458         return (uint32)(dev >> 8);
2459 #endif
2460 }
2461
2462 /****************************************************************************
2463  Return the minor devicenumber for UNIX extensions.
2464 ****************************************************************************/
2465
2466 uint32 unix_dev_minor(SMB_DEV_T dev)
2467 {
2468 #if defined(HAVE_DEVICE_MINOR_FN)
2469         return (uint32)minor(dev);
2470 #else
2471         return (uint32)(dev & 0xff);
2472 #endif
2473 }
2474
2475 #if defined(WITH_AIO)
2476
2477 /*******************************************************************
2478  An aio_read wrapper that will deal with 64-bit sizes.
2479 ********************************************************************/
2480
2481 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2482 {
2483 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2484         return aio_read64(aiocb);
2485 #elif defined(HAVE_AIO_READ)
2486         return aio_read(aiocb);
2487 #else
2488         errno = ENOSYS;
2489         return -1;
2490 #endif
2491 }
2492
2493 /*******************************************************************
2494  An aio_write wrapper that will deal with 64-bit sizes.
2495 ********************************************************************/
2496
2497 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2498 {
2499 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2500         return aio_write64(aiocb);
2501 #elif defined(HAVE_AIO_WRITE)
2502         return aio_write(aiocb);
2503 #else
2504         errno = ENOSYS;
2505         return -1;
2506 #endif
2507 }
2508
2509 /*******************************************************************
2510  An aio_return wrapper that will deal with 64-bit sizes.
2511 ********************************************************************/
2512
2513 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2514 {
2515 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2516         return aio_return64(aiocb);
2517 #elif defined(HAVE_AIO_RETURN)
2518         return aio_return(aiocb);
2519 #else
2520         errno = ENOSYS;
2521         return -1;
2522 #endif
2523 }
2524
2525 /*******************************************************************
2526  An aio_cancel wrapper that will deal with 64-bit sizes.
2527 ********************************************************************/
2528
2529 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2530 {
2531 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2532         return aio_cancel64(fd, aiocb);
2533 #elif defined(HAVE_AIO_CANCEL)
2534         return aio_cancel(fd, aiocb);
2535 #else
2536         errno = ENOSYS;
2537         return -1;
2538 #endif
2539 }
2540
2541 /*******************************************************************
2542  An aio_error wrapper that will deal with 64-bit sizes.
2543 ********************************************************************/
2544
2545 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2546 {
2547 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2548         return aio_error64(aiocb);
2549 #elif defined(HAVE_AIO_ERROR)
2550         return aio_error(aiocb);
2551 #else
2552         errno = ENOSYS;
2553         return -1;
2554 #endif
2555 }
2556
2557 /*******************************************************************
2558  An aio_fsync wrapper that will deal with 64-bit sizes.
2559 ********************************************************************/
2560
2561 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2562 {
2563 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2564         return aio_fsync64(op, aiocb);
2565 #elif defined(HAVE_AIO_FSYNC)
2566         return aio_fsync(op, aiocb);
2567 #else
2568         errno = ENOSYS;
2569         return -1;
2570 #endif
2571 }
2572
2573 /*******************************************************************
2574  An aio_fsync wrapper that will deal with 64-bit sizes.
2575 ********************************************************************/
2576
2577 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2578 {
2579 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2580         return aio_suspend64(cblist, n, timeout);
2581 #elif defined(HAVE_AIO_FSYNC)
2582         return aio_suspend(cblist, n, timeout);
2583 #else
2584         errno = ENOSYS;
2585         return -1;
2586 #endif
2587 }
2588 #else /* !WITH_AIO */
2589
2590 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2591 {
2592         errno = ENOSYS;
2593         return -1;
2594 }
2595
2596 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2597 {
2598         errno = ENOSYS;
2599         return -1;
2600 }
2601
2602 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2603 {
2604         errno = ENOSYS;
2605         return -1;
2606 }
2607
2608 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2609 {
2610         errno = ENOSYS;
2611         return -1;
2612 }
2613
2614 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2615 {
2616         errno = ENOSYS;
2617         return -1;
2618 }
2619
2620 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2621 {
2622         errno = ENOSYS;
2623         return -1;
2624 }
2625
2626 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2627 {
2628         errno = ENOSYS;
2629         return -1;
2630 }
2631 #endif /* WITH_AIO */
2632
2633 int sys_getpeereid( int s, uid_t *uid)
2634 {
2635 #if defined(HAVE_PEERCRED)
2636         struct ucred cred;
2637         socklen_t cred_len = sizeof(struct ucred);
2638         int ret;
2639
2640         ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2641         if (ret != 0) {
2642                 return -1;
2643         }
2644
2645         if (cred_len != sizeof(struct ucred)) {
2646                 errno = EINVAL;
2647                 return -1;
2648         }
2649
2650         *uid = cred.uid;
2651         return 0;
2652 #else
2653         errno = ENOSYS;
2654         return -1;
2655 #endif
2656 }
2657
2658 int sys_getnameinfo(const struct sockaddr *psa,
2659                         socklen_t salen,
2660                         char *host,
2661                         size_t hostlen,
2662                         char *service,
2663                         size_t servlen,
2664                         int flags)
2665 {
2666         /*
2667          * For Solaris we must make sure salen is the
2668          * correct length for the incoming sa_family.
2669          */
2670
2671         if (salen == sizeof(struct sockaddr_storage)) {
2672                 salen = sizeof(struct sockaddr_in);
2673 #if defined(HAVE_IPV6)
2674                 if (psa->sa_family == AF_INET6) {
2675                         salen = sizeof(struct sockaddr_in6);
2676                 }
2677 #endif
2678         }
2679         return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2680 }
2681
2682 int sys_connect(int fd, const struct sockaddr * addr)
2683 {
2684         socklen_t salen = -1;
2685
2686         if (addr->sa_family == AF_INET) {
2687             salen = sizeof(struct sockaddr_in);
2688         } else if (addr->sa_family == AF_UNIX) {
2689             salen = sizeof(struct sockaddr_un);
2690         }
2691 #if defined(HAVE_IPV6)
2692         else if (addr->sa_family == AF_INET6) {
2693             salen = sizeof(struct sockaddr_in6);
2694         }
2695 #endif
2696
2697         return connect(fd, addr, salen);
2698 }