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