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