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