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