2 Unix SMB/CIFS implementation.
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
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.
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.
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/>.
24 #include "system/syslog.h"
25 #include "system/capability.h"
26 #include "system/passwd.h"
27 #include "system/filesys.h"
29 #ifdef HAVE_SYS_SYSCTL_H
30 #include <sys/sysctl.h>
33 #ifdef HAVE_SYS_PRCTL_H
34 #include <sys/prctl.h>
38 The idea is that this file will eventually have wrappers around all
39 important system calls in samba. The aims are:
41 - to enable easier porting by putting OS dependent stuff in here
43 - to allow for hooks into other "pseudo-filesystems"
45 - to allow easier integration of things like the japanese extensions
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.
54 /*******************************************************************
55 A read wrapper that will deal with EINTR.
56 ********************************************************************/
58 ssize_t sys_read(int fd, void *buf, size_t count)
63 ret = read(fd, buf, count);
64 #if defined(EWOULDBLOCK)
65 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
67 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
72 /*******************************************************************
73 A write wrapper that will deal with EINTR.
74 ********************************************************************/
76 ssize_t sys_write(int fd, const void *buf, size_t count)
81 ret = write(fd, buf, count);
82 #if defined(EWOULDBLOCK)
83 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
85 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
90 /*******************************************************************
91 A writev wrapper that will deal with EINTR.
92 ********************************************************************/
94 ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
99 /* Try to confuse write_data_iov a bit */
100 if ((random() % 5) == 0) {
101 return sys_write(fd, iov[0].iov_base, iov[0].iov_len);
103 if (iov[0].iov_len > 1) {
104 return sys_write(fd, iov[0].iov_base,
105 (random() % (iov[0].iov_len-1)) + 1);
110 ret = writev(fd, iov, iovcnt);
111 #if defined(EWOULDBLOCK)
112 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
114 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
119 /*******************************************************************
120 A pread wrapper that will deal with EINTR
121 ********************************************************************/
123 #if defined(HAVE_PREAD)
124 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
129 ret = pread(fd, buf, count, off);
130 } while (ret == -1 && errno == EINTR);
135 /*******************************************************************
136 A write wrapper that will deal with EINTR
137 ********************************************************************/
139 #if defined(HAVE_PWRITE)
140 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
145 ret = pwrite(fd, buf, count, off);
146 } while (ret == -1 && errno == EINTR);
151 /*******************************************************************
152 A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
153 ********************************************************************/
155 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
160 ret = send(s, msg, len, flags);
161 #if defined(EWOULDBLOCK)
162 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
164 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
169 /*******************************************************************
170 A recvfrom wrapper that will deal with EINTR.
171 ********************************************************************/
173 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
178 ret = recvfrom(s, buf, len, flags, from, fromlen);
179 #if defined(EWOULDBLOCK)
180 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
182 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
187 /*******************************************************************
188 A fcntl wrapper that will deal with EINTR.
189 ********************************************************************/
191 int sys_fcntl_ptr(int fd, int cmd, void *arg)
196 ret = fcntl(fd, cmd, arg);
197 } while (ret == -1 && errno == EINTR);
201 /****************************************************************************
202 Get/Set all the possible time fields from a stat struct as a timespec.
203 ****************************************************************************/
205 static struct timespec get_atimespec(const struct stat *pst)
207 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
210 /* Old system - no ns timestamp. */
211 ret.tv_sec = pst->st_atime;
215 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
217 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
219 ret.tv_sec = pst->st_atime;
220 ret.tv_nsec = pst->st_atimensec;
222 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
224 ret.tv_sec = pst->st_atime;
225 ret.tv_nsec = pst->st_atime_n;
227 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
229 ret.tv_sec = pst->st_atime;
230 ret.tv_nsec = pst->st_uatime * 1000;
232 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
233 return pst->st_atimespec;
235 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
240 static struct timespec get_mtimespec(const struct stat *pst)
242 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
245 /* Old system - no ns timestamp. */
246 ret.tv_sec = pst->st_mtime;
250 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
252 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
254 ret.tv_sec = pst->st_mtime;
255 ret.tv_nsec = pst->st_mtimensec;
257 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
259 ret.tv_sec = pst->st_mtime;
260 ret.tv_nsec = pst->st_mtime_n;
262 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
264 ret.tv_sec = pst->st_mtime;
265 ret.tv_nsec = pst->st_umtime * 1000;
267 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
268 return pst->st_mtimespec;
270 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
275 static struct timespec get_ctimespec(const struct stat *pst)
277 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
280 /* Old system - no ns timestamp. */
281 ret.tv_sec = pst->st_ctime;
285 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
287 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
289 ret.tv_sec = pst->st_ctime;
290 ret.tv_nsec = pst->st_ctimensec;
292 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
294 ret.tv_sec = pst->st_ctime;
295 ret.tv_nsec = pst->st_ctime_n;
297 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
299 ret.tv_sec = pst->st_ctime;
300 ret.tv_nsec = pst->st_uctime * 1000;
302 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
303 return pst->st_ctimespec;
305 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
310 /****************************************************************************
311 Return the best approximation to a 'create time' under UNIX from a stat
313 ****************************************************************************/
315 static struct timespec calc_create_time_stat(const struct stat *st)
317 struct timespec ret, ret1;
318 struct timespec c_time = get_ctimespec(st);
319 struct timespec m_time = get_mtimespec(st);
320 struct timespec a_time = get_atimespec(st);
322 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
323 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
325 if(!null_timespec(ret1)) {
330 * One of ctime, mtime or atime was zero (probably atime).
331 * Just return MIN(ctime, mtime).
336 /****************************************************************************
337 Return the best approximation to a 'create time' under UNIX from a stat_ex
339 ****************************************************************************/
341 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
343 struct timespec ret, ret1;
344 struct timespec c_time = st->st_ex_ctime;
345 struct timespec m_time = st->st_ex_mtime;
346 struct timespec a_time = st->st_ex_atime;
348 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
349 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
351 if(!null_timespec(ret1)) {
356 * One of ctime, mtime or atime was zero (probably atime).
357 * Just return MIN(ctime, mtime).
362 /****************************************************************************
363 Return the 'create time' from a stat struct if it exists (birthtime) or else
364 use the best approximation.
365 ****************************************************************************/
367 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
368 bool fake_dir_create_times)
370 if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
371 dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */
372 dst->st_ex_btime.tv_nsec = 0;
375 dst->st_ex_calculated_birthtime = false;
377 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
378 dst->st_ex_btime = pst->st_birthtimespec;
379 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
380 dst->st_ex_btime.tv_sec = pst->st_birthtime;
381 dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
382 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
383 dst->st_ex_btime.tv_sec = pst->st_birthtime;
384 dst->st_ex_btime.tv_nsec = 0;
386 dst->st_ex_btime = calc_create_time_stat(pst);
387 dst->st_ex_calculated_birthtime = true;
390 /* Deal with systems that don't initialize birthtime correctly.
391 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
393 if (null_timespec(dst->st_ex_btime)) {
394 dst->st_ex_btime = calc_create_time_stat(pst);
395 dst->st_ex_calculated_birthtime = true;
399 /****************************************************************************
400 If we update a timestamp in a stat_ex struct we may have to recalculate
401 the birthtime. For now only implement this for write time, but we may
402 also need to do it for atime and ctime. JRA.
403 ****************************************************************************/
405 void update_stat_ex_mtime(struct stat_ex *dst,
406 struct timespec write_ts)
408 dst->st_ex_mtime = write_ts;
410 /* We may have to recalculate btime. */
411 if (dst->st_ex_calculated_birthtime) {
412 dst->st_ex_btime = calc_create_time_stat_ex(dst);
416 void update_stat_ex_create_time(struct stat_ex *dst,
417 struct timespec create_time)
419 dst->st_ex_btime = create_time;
420 dst->st_ex_calculated_birthtime = false;
423 void init_stat_ex_from_stat (struct stat_ex *dst,
424 const struct stat *src,
425 bool fake_dir_create_times)
427 dst->st_ex_dev = src->st_dev;
428 dst->st_ex_ino = src->st_ino;
429 dst->st_ex_mode = src->st_mode;
430 dst->st_ex_nlink = src->st_nlink;
431 dst->st_ex_uid = src->st_uid;
432 dst->st_ex_gid = src->st_gid;
433 dst->st_ex_rdev = src->st_rdev;
434 dst->st_ex_size = src->st_size;
435 dst->st_ex_atime = get_atimespec(src);
436 dst->st_ex_mtime = get_mtimespec(src);
437 dst->st_ex_ctime = get_ctimespec(src);
438 make_create_timespec(src, dst, fake_dir_create_times);
439 #ifdef HAVE_STAT_ST_BLKSIZE
440 dst->st_ex_blksize = src->st_blksize;
442 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
445 #ifdef HAVE_STAT_ST_BLOCKS
446 dst->st_ex_blocks = src->st_blocks;
448 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
451 #ifdef HAVE_STAT_ST_FLAGS
452 dst->st_ex_flags = src->st_flags;
454 dst->st_ex_flags = 0;
458 /*******************************************************************
460 ********************************************************************/
462 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
463 bool fake_dir_create_times)
467 ret = stat(fname, &statbuf);
469 /* we always want directories to appear zero size */
470 if (S_ISDIR(statbuf.st_mode)) {
473 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
478 /*******************************************************************
480 ********************************************************************/
482 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
486 ret = fstat(fd, &statbuf);
488 /* we always want directories to appear zero size */
489 if (S_ISDIR(statbuf.st_mode)) {
492 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
497 /*******************************************************************
499 ********************************************************************/
501 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
502 bool fake_dir_create_times)
506 ret = lstat(fname, &statbuf);
508 /* we always want directories to appear zero size */
509 if (S_ISDIR(statbuf.st_mode)) {
512 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
517 /*******************************************************************
518 An posix_fallocate() wrapper.
519 ********************************************************************/
520 int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
522 #if defined(HAVE_POSIX_FALLOCATE) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
523 return posix_fallocate(fd, offset, len);
524 #elif defined(F_RESVSP64)
525 /* this handles XFS on IRIX */
527 SMB_OFF_T new_len = offset + len;
531 /* unlikely to get a too large file on a 64bit system but ... */
535 fl.l_whence = SEEK_SET;
539 ret=fcntl(fd, F_RESVSP64, &fl);
544 /* Make sure the file gets enlarged after we allocated space: */
546 if (new_len > sbuf.st_size)
547 ftruncate64(fd, new_len);
554 /*******************************************************************
555 An fallocate() function that matches the semantics of the Linux one.
556 ********************************************************************/
558 #ifdef HAVE_LINUX_FALLOC_H
559 #include <linux/falloc.h>
562 int sys_fallocate(int fd, enum vfs_fallocate_mode mode, SMB_OFF_T offset, SMB_OFF_T len)
564 #if defined(HAVE_LINUX_FALLOCATE64) || defined(HAVE_LINUX_FALLOCATE)
567 case VFS_FALLOCATE_EXTEND_SIZE:
570 case VFS_FALLOCATE_KEEP_SIZE:
571 lmode = FALLOC_FL_KEEP_SIZE;
577 #if defined(HAVE_LINUX_FALLOCATE)
578 return fallocate(fd, lmode, offset, len);
581 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
587 /*******************************************************************
589 ********************************************************************/
591 SMB_OFF_T sys_ftell(FILE *fp)
593 return (SMB_OFF_T)ftell(fp);
596 /*******************************************************************
598 ********************************************************************/
600 int sys_creat(const char *path, mode_t mode)
602 #if defined(HAVE_CREAT)
603 return creat(path, mode);
606 * If creat isn't defined then ensure we call open with the expected flags.
609 return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
613 /*******************************************************************
615 ********************************************************************/
617 int sys_open(const char *path, int oflag, mode_t mode)
619 return open(path, oflag, mode);
622 /*******************************************************************
624 ********************************************************************/
626 FILE *sys_fopen(const char *path, const char *type)
628 return fopen(path, type);
632 #if HAVE_KERNEL_SHARE_MODES
634 #define LOCK_MAND 32 /* This is a mandatory flock */
635 #define LOCK_READ 64 /* ... Which allows concurrent read operations */
636 #define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
637 #define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
641 /*******************************************************************
642 A flock() wrapper that will perform the kernel flock.
643 ********************************************************************/
645 void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
647 #if HAVE_KERNEL_SHARE_MODES
649 if (share_mode == FILE_SHARE_WRITE) {
650 kernel_mode = LOCK_MAND|LOCK_WRITE;
651 } else if (share_mode == FILE_SHARE_READ) {
652 kernel_mode = LOCK_MAND|LOCK_READ;
653 } else if (share_mode == FILE_SHARE_NONE) {
654 kernel_mode = LOCK_MAND;
657 flock(fd, kernel_mode);
665 /*******************************************************************
667 ********************************************************************/
669 SMB_STRUCT_DIR *sys_opendir(const char *name)
671 return opendir(name);
674 /*******************************************************************
675 An fdopendir wrapper.
676 Ugly hack - we need dirfd for this to work correctly in the
678 ********************************************************************/
680 SMB_STRUCT_DIR *sys_fdopendir(int fd)
682 #if defined(HAVE_FDOPENDIR) && defined(HAVE_DIRFD)
683 return fdopendir(fd);
690 /*******************************************************************
692 ********************************************************************/
694 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
696 return readdir(dirp);
699 /*******************************************************************
701 ********************************************************************/
703 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
705 seekdir(dirp, offset);
708 /*******************************************************************
710 ********************************************************************/
712 long sys_telldir(SMB_STRUCT_DIR *dirp)
714 return (long)telldir(dirp);
717 /*******************************************************************
719 ********************************************************************/
721 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
726 /*******************************************************************
728 ********************************************************************/
730 int sys_closedir(SMB_STRUCT_DIR *dirp)
732 return closedir(dirp);
735 /*******************************************************************
737 ********************************************************************/
739 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
741 #if defined(HAVE_MKNOD)
742 return mknod(path, mode, dev);
744 /* No mknod system call. */
750 /*******************************************************************
751 The wait() calls vary between systems
752 ********************************************************************/
754 int sys_waitpid(pid_t pid,int *status,int options)
757 return waitpid(pid,status,options);
758 #else /* HAVE_WAITPID */
759 return wait4(pid, status, options, NULL);
760 #endif /* HAVE_WAITPID */
763 /*******************************************************************
764 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
765 on error (malloc fail usually).
766 ********************************************************************/
768 char *sys_getwd(void)
770 #ifdef GETCWD_TAKES_NULL
771 return getcwd(NULL, 0);
773 char *wd = NULL, *s = NULL;
774 size_t allocated = PATH_MAX;
777 s = SMB_REALLOC_ARRAY(s, char, allocated);
781 wd = getcwd(s, allocated);
785 if (errno != ERANGE) {
790 if (allocated < PATH_MAX) {
797 char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
805 #if defined(HAVE_POSIX_CAPABILITIES)
807 /**************************************************************************
808 Try and abstract process capabilities (for systems that have them).
809 ****************************************************************************/
811 /* Set the POSIX capabilities needed for the given purpose into the effective
812 * capability set of the current process. Make sure they are always removed
813 * from the inheritable set, because there is no circumstance in which our
814 * children should inherit our elevated privileges.
816 static bool set_process_capability(enum smbd_capability capability,
819 cap_value_t cap_vals[2] = {0};
820 int num_cap_vals = 0;
824 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
825 /* On Linux, make sure that any capabilities we grab are sticky
826 * across UID changes. We expect that this would allow us to keep both
827 * the effective and permitted capability sets, but as of circa 2.6.16,
828 * only the permitted set is kept. It is a bug (which we work around)
829 * that the effective set is lost, but we still require the effective
832 if (!prctl(PR_GET_KEEPCAPS)) {
833 prctl(PR_SET_KEEPCAPS, 1);
837 cap = cap_get_proc();
839 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
844 switch (capability) {
845 case KERNEL_OPLOCK_CAPABILITY:
846 #ifdef CAP_NETWORK_MGT
847 /* IRIX has CAP_NETWORK_MGT for oplocks. */
848 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
851 case DMAPI_ACCESS_CAPABILITY:
852 #ifdef CAP_DEVICE_MGT
853 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
854 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
856 /* Linux has CAP_MKNOD for DMAPI access. */
857 cap_vals[num_cap_vals++] = CAP_MKNOD;
860 case LEASE_CAPABILITY:
862 cap_vals[num_cap_vals++] = CAP_LEASE;
867 SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
869 if (num_cap_vals == 0) {
874 cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
875 enable ? CAP_SET : CAP_CLEAR);
877 /* We never want to pass capabilities down to our children, so make
878 * sure they are not inherited.
880 cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
882 if (cap_set_proc(cap) == -1) {
883 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
893 #endif /* HAVE_POSIX_CAPABILITIES */
895 /****************************************************************************
896 Gain the oplock capability from the kernel if possible.
897 ****************************************************************************/
899 void set_effective_capability(enum smbd_capability capability)
901 #if defined(HAVE_POSIX_CAPABILITIES)
902 set_process_capability(capability, True);
903 #endif /* HAVE_POSIX_CAPABILITIES */
906 void drop_effective_capability(enum smbd_capability capability)
908 #if defined(HAVE_POSIX_CAPABILITIES)
909 set_process_capability(capability, False);
910 #endif /* HAVE_POSIX_CAPABILITIES */
913 /**************************************************************************
914 Wrapper for random().
915 ****************************************************************************/
917 long sys_random(void)
919 #if defined(HAVE_RANDOM)
920 return (long)random();
921 #elif defined(HAVE_RAND)
924 DEBUG(0,("Error - no random function available !\n"));
929 /**************************************************************************
930 Wrapper for srandom().
931 ****************************************************************************/
933 void sys_srandom(unsigned int seed)
935 #if defined(HAVE_SRANDOM)
937 #elif defined(HAVE_SRAND)
940 DEBUG(0,("Error - no srandom function available !\n"));
946 #define NGROUPS_MAX 32 /* Guess... */
949 /**************************************************************************
950 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
951 ****************************************************************************/
955 #if defined(SYSCONF_SC_NGROUPS_MAX)
956 int ret = sysconf(_SC_NGROUPS_MAX);
957 return (ret == -1) ? NGROUPS_MAX : ret;
963 /**************************************************************************
964 Wrap setgroups and getgroups for systems that declare getgroups() as
965 returning an array of gid_t, but actuall return an array of int.
966 ****************************************************************************/
968 #if defined(HAVE_BROKEN_GETGROUPS)
970 #ifdef HAVE_BROKEN_GETGROUPS
976 static int sys_broken_getgroups(int setlen, gid_t *gidset)
983 return getgroups(setlen, &gid);
987 * Broken case. We need to allocate a
988 * GID_T array of size setlen.
997 setlen = groups_max();
999 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1000 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
1004 if((ngroups = getgroups(setlen, group_list)) < 0) {
1005 int saved_errno = errno;
1006 SAFE_FREE(group_list);
1007 errno = saved_errno;
1011 for(i = 0; i < ngroups; i++)
1012 gidset[i] = (gid_t)group_list[i];
1014 SAFE_FREE(group_list);
1018 static int sys_broken_setgroups(int setlen, gid_t *gidset)
1026 if (setlen < 0 || setlen > groups_max()) {
1032 * Broken case. We need to allocate a
1033 * GID_T array of size setlen.
1036 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1037 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1041 for(i = 0; i < setlen; i++)
1042 group_list[i] = (GID_T) gidset[i];
1044 if(setgroups(setlen, group_list) != 0) {
1045 int saved_errno = errno;
1046 SAFE_FREE(group_list);
1047 errno = saved_errno;
1051 SAFE_FREE(group_list);
1055 #endif /* HAVE_BROKEN_GETGROUPS */
1057 /* This is a list of systems that require the first GID passed to setgroups(2)
1058 * to be the effective GID. If your system is one of these, add it here.
1060 #if defined (FREEBSD) || defined (DARWINOS)
1061 #define USE_BSD_SETGROUPS
1064 #if defined(USE_BSD_SETGROUPS)
1065 /* Depending on the particular BSD implementation, the first GID that is
1066 * passed to setgroups(2) will either be ignored or will set the credential's
1067 * effective GID. In either case, the right thing to do is to guarantee that
1068 * gidset[0] is the effective GID.
1070 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1072 gid_t *new_gidset = NULL;
1076 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1079 /* No group list, just make sure we are setting the efective GID. */
1081 return setgroups(1, &primary_gid);
1084 /* If the primary gid is not the first array element, grow the array
1085 * and insert it at the front.
1087 if (gidset[0] != primary_gid) {
1088 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1089 if (new_gidset == NULL) {
1093 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1094 new_gidset[0] = primary_gid;
1099 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1104 #if defined(HAVE_BROKEN_GETGROUPS)
1105 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1107 ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1112 SAFE_FREE(new_gidset);
1119 #endif /* USE_BSD_SETGROUPS */
1121 /**************************************************************************
1122 Wrapper for getgroups. Deals with broken (int) case.
1123 ****************************************************************************/
1125 int sys_getgroups(int setlen, gid_t *gidset)
1127 #if defined(HAVE_BROKEN_GETGROUPS)
1128 return sys_broken_getgroups(setlen, gidset);
1130 return getgroups(setlen, gidset);
1134 /**************************************************************************
1135 Wrapper for setgroups. Deals with broken (int) case and BSD case.
1136 ****************************************************************************/
1138 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1140 #if !defined(HAVE_SETGROUPS)
1143 #endif /* HAVE_SETGROUPS */
1145 #if defined(USE_BSD_SETGROUPS)
1146 return sys_bsd_setgroups(primary_gid, setlen, gidset);
1147 #elif defined(HAVE_BROKEN_GETGROUPS)
1148 return sys_broken_setgroups(setlen, gidset);
1150 return setgroups(setlen, gidset);
1154 /**************************************************************************
1155 Extract a command into an arg list.
1156 ****************************************************************************/
1158 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1167 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1168 DEBUG(0, ("talloc failed\n"));
1172 if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1173 TALLOC_FREE(trunc_cmd);
1182 for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1185 TALLOC_FREE(trunc_cmd);
1187 if (!(argl = talloc_array(mem_ctx, char *, argcl + 1))) {
1192 * Now do the extraction.
1195 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1199 ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1202 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1206 while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1208 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1214 TALLOC_FREE(trunc_cmd);
1218 DEBUG(0, ("talloc failed\n"));
1219 TALLOC_FREE(trunc_cmd);
1225 /**************************************************************************
1226 Wrapper for popen. Safer as it doesn't search a path.
1227 Modified from the glibc sources.
1228 modified by tridge to return a file descriptor. We must kick our FILE* habit
1229 ****************************************************************************/
1231 typedef struct _popen_list
1235 struct _popen_list *next;
1238 static popen_list *popen_chain;
1240 int sys_popen(const char *command)
1242 int parent_end, child_end;
1244 popen_list *entry = NULL;
1247 if (pipe(pipe_fds) < 0)
1250 parent_end = pipe_fds[0];
1251 child_end = pipe_fds[1];
1258 if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1261 ZERO_STRUCTP(entry);
1264 * Extract the command and args into a NULL terminated array.
1267 if(!(argl = extract_args(NULL, command)))
1270 entry->child_pid = fork();
1272 if (entry->child_pid == -1) {
1276 if (entry->child_pid == 0) {
1282 int child_std_end = STDOUT_FILENO;
1286 if (child_end != child_std_end) {
1287 dup2 (child_end, child_std_end);
1292 * POSIX.2: "popen() shall ensure that any streams from previous
1293 * popen() calls that remain open in the parent process are closed
1294 * in the new child process."
1297 for (p = popen_chain; p; p = p->next)
1300 execv(argl[0], argl);
1311 /* Link into popen_chain. */
1312 entry->next = popen_chain;
1313 popen_chain = entry;
1314 entry->fd = parent_end;
1327 /**************************************************************************
1328 Wrapper for pclose. Modified from the glibc sources.
1329 ****************************************************************************/
1331 int sys_pclose(int fd)
1334 popen_list **ptr = &popen_chain;
1335 popen_list *entry = NULL;
1339 /* Unlink from popen_chain. */
1340 for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1341 if ((*ptr)->fd == fd) {
1343 *ptr = (*ptr)->next;
1349 if (status < 0 || close(entry->fd) < 0)
1353 * As Samba is catching and eating child process
1354 * exits we don't really care about the child exit
1355 * code, a -1 with errno = ECHILD will do fine for us.
1359 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1360 } while (wait_pid == -1 && errno == EINTR);
1369 /**************************************************************************
1370 Wrapper for Admin Logs.
1371 ****************************************************************************/
1373 void sys_adminlog(int priority, const char *format_str, ...)
1377 char *msgbuf = NULL;
1379 va_start( ap, format_str );
1380 ret = vasprintf( &msgbuf, format_str, ap );
1386 #if defined(HAVE_SYSLOG)
1387 syslog( priority, "%s", msgbuf );
1389 DEBUG(0,("%s", msgbuf ));
1394 /******** Solaris EA helper function prototypes ********/
1395 #ifdef HAVE_ATTROPEN
1396 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1397 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1398 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1399 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1400 static int solaris_unlinkat(int attrdirfd, const char *name);
1401 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1402 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1405 /**************************************************************************
1406 Wrappers for extented attribute calls. Based on the Linux package with
1407 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1408 ****************************************************************************/
1410 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1412 #if defined(HAVE_GETXATTR)
1413 #ifndef XATTR_ADD_OPT
1414 return getxattr(path, name, value, size);
1417 return getxattr(path, name, value, size, 0, options);
1419 #elif defined(HAVE_GETEA)
1420 return getea(path, name, value, size);
1421 #elif defined(HAVE_EXTATTR_GET_FILE)
1424 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1425 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1426 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1428 * The BSD implementation has a nasty habit of silently truncating
1429 * the returned value to the size of the buffer, so we have to check
1430 * that the buffer is large enough to fit the returned value.
1432 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1437 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1441 DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1443 #elif defined(HAVE_ATTR_GET)
1444 int retval, flags = 0;
1445 int valuelength = (int)size;
1446 char *attrname = strchr(name,'.') + 1;
1448 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1450 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1452 return retval ? retval : valuelength;
1453 #elif defined(HAVE_ATTROPEN)
1455 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1457 ret = solaris_read_xattr(attrfd, value, size);
1467 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1469 #if defined(HAVE_LGETXATTR)
1470 return lgetxattr(path, name, value, size);
1471 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1472 int options = XATTR_NOFOLLOW;
1473 return getxattr(path, name, value, size, 0, options);
1474 #elif defined(HAVE_LGETEA)
1475 return lgetea(path, name, value, size);
1476 #elif defined(HAVE_EXTATTR_GET_LINK)
1479 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1480 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1481 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1483 if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1488 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1492 DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1494 #elif defined(HAVE_ATTR_GET)
1495 int retval, flags = ATTR_DONTFOLLOW;
1496 int valuelength = (int)size;
1497 char *attrname = strchr(name,'.') + 1;
1499 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1501 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1503 return retval ? retval : valuelength;
1504 #elif defined(HAVE_ATTROPEN)
1506 int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1508 ret = solaris_read_xattr(attrfd, value, size);
1518 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1520 #if defined(HAVE_FGETXATTR)
1521 #ifndef XATTR_ADD_OPT
1522 return fgetxattr(filedes, name, value, size);
1525 return fgetxattr(filedes, name, value, size, 0, options);
1527 #elif defined(HAVE_FGETEA)
1528 return fgetea(filedes, name, value, size);
1529 #elif defined(HAVE_EXTATTR_GET_FD)
1532 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1533 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1534 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1536 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1541 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1545 DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1547 #elif defined(HAVE_ATTR_GETF)
1548 int retval, flags = 0;
1549 int valuelength = (int)size;
1550 char *attrname = strchr(name,'.') + 1;
1552 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1554 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1556 return retval ? retval : valuelength;
1557 #elif defined(HAVE_ATTROPEN)
1559 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1561 ret = solaris_read_xattr(attrfd, value, size);
1571 #if defined(HAVE_EXTATTR_LIST_FILE)
1573 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
1581 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1582 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1590 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1592 ssize_t list_size, total_size = 0;
1595 /* Iterate through extattr(2) namespaces */
1596 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
1598 #if defined(HAVE_EXTATTR_LIST_FILE)
1600 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1603 #if defined(HAVE_EXTATTR_LIST_LINK)
1605 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1608 #if defined(HAVE_EXTATTR_LIST_FD)
1610 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1617 /* Some error happend. Errno should be set by the previous call */
1623 /* XXX: Call with an empty buffer may be used to calculate
1624 necessary buffer size. Unfortunately, we can't say, how
1625 many attributes were returned, so here is the potential
1626 problem with the emulation.
1629 /* Take the worse case of one char attribute names -
1630 two bytes per name plus one more for sanity.
1632 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1635 /* Count necessary offset to fit namespace prefixes */
1637 for(i = 0; i < list_size; i += list[i] + 1)
1638 len += extattr[t].len;
1640 total_size += list_size + len;
1641 /* Buffer is too small to fit the results */
1642 if(total_size > size) {
1646 /* Shift results back, so we can prepend prefixes */
1647 buf = (char *)memmove(list + len, list, list_size);
1649 for(i = 0; i < list_size; i += len + 1) {
1651 strncpy(list, extattr[t].name, extattr[t].len + 1);
1652 list += extattr[t].len;
1653 strncpy(list, buf + i + 1, len);
1664 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1665 static char attr_buffer[ATTR_MAX_VALUELEN];
1667 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1669 int retval = 0, index;
1670 attrlist_cursor_t *cursor = 0;
1672 attrlist_t * al = (attrlist_t *)attr_buffer;
1674 size_t ent_size, left = size;
1679 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1681 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1683 for (index = 0; index < al->al_count; index++) {
1684 ae = ATTR_ENTRY(attr_buffer, index);
1685 ent_size = strlen(ae->a_name) + sizeof("user.");
1686 if (left >= ent_size) {
1687 strncpy(bp, "user.", sizeof("user."));
1688 strncat(bp, ae->a_name, ent_size - sizeof("user."));
1696 total_size += ent_size;
1698 if (al->al_more == 0) break;
1705 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1707 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1709 for (index = 0; index < al->al_count; index++) {
1710 ae = ATTR_ENTRY(attr_buffer, index);
1711 ent_size = strlen(ae->a_name) + sizeof("system.");
1712 if (left >= ent_size) {
1713 strncpy(bp, "system.", sizeof("system."));
1714 strncat(bp, ae->a_name, ent_size - sizeof("system."));
1722 total_size += ent_size;
1724 if (al->al_more == 0) break;
1727 return (ssize_t)(retval ? retval : total_size);
1732 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1734 #if defined(HAVE_LISTXATTR)
1735 #ifndef XATTR_ADD_OPT
1736 return listxattr(path, list, size);
1739 return listxattr(path, list, size, options);
1741 #elif defined(HAVE_LISTEA)
1742 return listea(path, list, size);
1743 #elif defined(HAVE_EXTATTR_LIST_FILE)
1746 return bsd_attr_list(0, arg, list, size);
1747 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1748 return irix_attr_list(path, 0, list, size, 0);
1749 #elif defined(HAVE_ATTROPEN)
1751 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1752 if (attrdirfd >= 0) {
1753 ret = solaris_list_xattr(attrdirfd, list, size);
1763 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1765 #if defined(HAVE_LLISTXATTR)
1766 return llistxattr(path, list, size);
1767 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1768 int options = XATTR_NOFOLLOW;
1769 return listxattr(path, list, size, options);
1770 #elif defined(HAVE_LLISTEA)
1771 return llistea(path, list, size);
1772 #elif defined(HAVE_EXTATTR_LIST_LINK)
1775 return bsd_attr_list(1, arg, list, size);
1776 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1777 return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1778 #elif defined(HAVE_ATTROPEN)
1780 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1781 if (attrdirfd >= 0) {
1782 ret = solaris_list_xattr(attrdirfd, list, size);
1792 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1794 #if defined(HAVE_FLISTXATTR)
1795 #ifndef XATTR_ADD_OPT
1796 return flistxattr(filedes, list, size);
1799 return flistxattr(filedes, list, size, options);
1801 #elif defined(HAVE_FLISTEA)
1802 return flistea(filedes, list, size);
1803 #elif defined(HAVE_EXTATTR_LIST_FD)
1805 arg.filedes = filedes;
1806 return bsd_attr_list(2, arg, list, size);
1807 #elif defined(HAVE_ATTR_LISTF)
1808 return irix_attr_list(NULL, filedes, list, size, 0);
1809 #elif defined(HAVE_ATTROPEN)
1811 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1812 if (attrdirfd >= 0) {
1813 ret = solaris_list_xattr(attrdirfd, list, size);
1823 int sys_removexattr (const char *path, const char *name)
1825 #if defined(HAVE_REMOVEXATTR)
1826 #ifndef XATTR_ADD_OPT
1827 return removexattr(path, name);
1830 return removexattr(path, name, options);
1832 #elif defined(HAVE_REMOVEEA)
1833 return removeea(path, name);
1834 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1836 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1837 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1838 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1840 return extattr_delete_file(path, attrnamespace, attrname);
1841 #elif defined(HAVE_ATTR_REMOVE)
1843 char *attrname = strchr(name,'.') + 1;
1845 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1847 return attr_remove(path, attrname, flags);
1848 #elif defined(HAVE_ATTROPEN)
1850 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1851 if (attrdirfd >= 0) {
1852 ret = solaris_unlinkat(attrdirfd, name);
1862 int sys_lremovexattr (const char *path, const char *name)
1864 #if defined(HAVE_LREMOVEXATTR)
1865 return lremovexattr(path, name);
1866 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
1867 int options = XATTR_NOFOLLOW;
1868 return removexattr(path, name, options);
1869 #elif defined(HAVE_LREMOVEEA)
1870 return lremoveea(path, name);
1871 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1873 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1874 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1875 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1877 return extattr_delete_link(path, attrnamespace, attrname);
1878 #elif defined(HAVE_ATTR_REMOVE)
1879 int flags = ATTR_DONTFOLLOW;
1880 char *attrname = strchr(name,'.') + 1;
1882 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1884 return attr_remove(path, attrname, flags);
1885 #elif defined(HAVE_ATTROPEN)
1887 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1888 if (attrdirfd >= 0) {
1889 ret = solaris_unlinkat(attrdirfd, name);
1899 int sys_fremovexattr (int filedes, const char *name)
1901 #if defined(HAVE_FREMOVEXATTR)
1902 #ifndef XATTR_ADD_OPT
1903 return fremovexattr(filedes, name);
1906 return fremovexattr(filedes, name, options);
1908 #elif defined(HAVE_FREMOVEEA)
1909 return fremoveea(filedes, name);
1910 #elif defined(HAVE_EXTATTR_DELETE_FD)
1912 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1913 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1914 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1916 return extattr_delete_fd(filedes, attrnamespace, attrname);
1917 #elif defined(HAVE_ATTR_REMOVEF)
1919 char *attrname = strchr(name,'.') + 1;
1921 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1923 return attr_removef(filedes, attrname, flags);
1924 #elif defined(HAVE_ATTROPEN)
1926 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1927 if (attrdirfd >= 0) {
1928 ret = solaris_unlinkat(attrdirfd, name);
1938 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1940 #if defined(HAVE_SETXATTR)
1941 #ifndef XATTR_ADD_OPT
1942 return setxattr(path, name, value, size, flags);
1945 return setxattr(path, name, value, size, 0, options);
1947 #elif defined(HAVE_SETEA)
1948 return setea(path, name, value, size, flags);
1949 #elif defined(HAVE_EXTATTR_SET_FILE)
1952 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1953 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1954 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1956 /* Check attribute existence */
1957 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1959 /* REPLACE attribute, that doesn't exist */
1960 if (flags & XATTR_REPLACE && errno == ENOATTR) {
1964 /* Ignore other errors */
1967 /* CREATE attribute, that already exists */
1968 if (flags & XATTR_CREATE) {
1974 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
1975 return (retval < 0) ? -1 : 0;
1976 #elif defined(HAVE_ATTR_SET)
1978 char *attrname = strchr(name,'.') + 1;
1980 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1981 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1982 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1984 return attr_set(path, attrname, (const char *)value, size, myflags);
1985 #elif defined(HAVE_ATTROPEN)
1987 int myflags = O_RDWR;
1989 if (flags & XATTR_CREATE) myflags |= O_EXCL;
1990 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
1991 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
1993 ret = solaris_write_xattr(attrfd, value, size);
2003 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2005 #if defined(HAVE_LSETXATTR)
2006 return lsetxattr(path, name, value, size, flags);
2007 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
2008 int options = XATTR_NOFOLLOW;
2009 return setxattr(path, name, value, size, 0, options);
2010 #elif defined(LSETEA)
2011 return lsetea(path, name, value, size, flags);
2012 #elif defined(HAVE_EXTATTR_SET_LINK)
2015 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2016 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2017 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2019 /* Check attribute existence */
2020 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
2022 /* REPLACE attribute, that doesn't exist */
2023 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2027 /* Ignore other errors */
2030 /* CREATE attribute, that already exists */
2031 if (flags & XATTR_CREATE) {
2038 retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2039 return (retval < 0) ? -1 : 0;
2040 #elif defined(HAVE_ATTR_SET)
2041 int myflags = ATTR_DONTFOLLOW;
2042 char *attrname = strchr(name,'.') + 1;
2044 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2045 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2046 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2048 return attr_set(path, attrname, (const char *)value, size, myflags);
2049 #elif defined(HAVE_ATTROPEN)
2051 int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2053 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2054 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2055 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2057 ret = solaris_write_xattr(attrfd, value, size);
2067 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2069 #if defined(HAVE_FSETXATTR)
2070 #ifndef XATTR_ADD_OPT
2071 return fsetxattr(filedes, name, value, size, flags);
2074 return fsetxattr(filedes, name, value, size, 0, options);
2076 #elif defined(HAVE_FSETEA)
2077 return fsetea(filedes, name, value, size, flags);
2078 #elif defined(HAVE_EXTATTR_SET_FD)
2081 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2082 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2083 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2085 /* Check attribute existence */
2086 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2088 /* REPLACE attribute, that doesn't exist */
2089 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2093 /* Ignore other errors */
2096 /* CREATE attribute, that already exists */
2097 if (flags & XATTR_CREATE) {
2103 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2104 return (retval < 0) ? -1 : 0;
2105 #elif defined(HAVE_ATTR_SETF)
2107 char *attrname = strchr(name,'.') + 1;
2109 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2110 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2111 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2113 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2114 #elif defined(HAVE_ATTROPEN)
2116 int myflags = O_RDWR | O_XATTR;
2118 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2119 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2120 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2122 ret = solaris_write_xattr(attrfd, value, size);
2132 /**************************************************************************
2133 helper functions for Solaris' EA support
2134 ****************************************************************************/
2135 #ifdef HAVE_ATTROPEN
2136 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2140 if (fstat(attrfd, &sbuf) == -1) {
2145 /* This is to return the current size of the named extended attribute */
2147 return sbuf.st_size;
2150 /* check size and read xattr */
2151 if (sbuf.st_size > size) {
2156 return read(attrfd, value, sbuf.st_size);
2159 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2164 int newfd = dup(attrdirfd);
2165 /* CAUTION: The originating file descriptor should not be
2166 used again following the call to fdopendir().
2167 For that reason we dup() the file descriptor
2168 here to make things more clear. */
2169 dirp = fdopendir(newfd);
2171 while ((de = readdir(dirp))) {
2172 size_t listlen = strlen(de->d_name) + 1;
2173 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2174 /* we don't want "." and ".." here: */
2175 DEBUG(10,("skipped EA %s\n",de->d_name));
2180 /* return the current size of the list of extended attribute names*/
2183 /* check size and copy entrieѕ + nul into list. */
2184 if ((len + listlen) > size) {
2189 strlcpy(list + len, de->d_name, listlen);
2195 if (closedir(dirp) == -1) {
2196 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2202 static int solaris_unlinkat(int attrdirfd, const char *name)
2204 if (unlinkat(attrdirfd, name, 0) == -1) {
2205 if (errno == ENOENT) {
2213 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2215 int filedes = attropen(path, attrpath, oflag, mode);
2216 if (filedes == -1) {
2217 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2218 if (errno == EINVAL) {
2227 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2229 int filedes = openat(fildes, path, oflag, mode);
2230 if (filedes == -1) {
2231 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2232 if (errno == EINVAL) {
2241 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2243 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2246 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2250 #endif /*HAVE_ATTROPEN*/
2253 /****************************************************************************
2254 Return the major devicenumber for UNIX extensions.
2255 ****************************************************************************/
2257 uint32 unix_dev_major(SMB_DEV_T dev)
2259 #if defined(HAVE_DEVICE_MAJOR_FN)
2260 return (uint32)major(dev);
2262 return (uint32)(dev >> 8);
2266 /****************************************************************************
2267 Return the minor devicenumber for UNIX extensions.
2268 ****************************************************************************/
2270 uint32 unix_dev_minor(SMB_DEV_T dev)
2272 #if defined(HAVE_DEVICE_MINOR_FN)
2273 return (uint32)minor(dev);
2275 return (uint32)(dev & 0xff);
2280 /*******************************************************************
2281 Return the number of CPUs.
2282 ********************************************************************/
2284 int sys_get_number_of_cores(void)
2288 #if defined(HAVE_SYSCONF)
2289 #if defined(_SC_NPROCESSORS_ONLN)
2290 ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
2292 #if defined(_SC_NPROCESSORS_CONF)
2294 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
2297 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
2299 unsigned int len = sizeof(ret);
2302 #if defined(HW_AVAILCPU)
2303 name[1] = HW_AVAILCPU;
2305 if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
2309 #if defined(HW_NCPU)
2313 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
2326 #if defined(WITH_AIO)
2328 /*******************************************************************
2329 An aio_read wrapper.
2330 ********************************************************************/
2332 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2334 #if defined(HAVE_AIO_READ)
2335 return aio_read(aiocb);
2342 /*******************************************************************
2343 An aio_write wrapper.
2344 ********************************************************************/
2346 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2348 #if defined(HAVE_AIO_WRITE)
2349 return aio_write(aiocb);
2356 /*******************************************************************
2357 An aio_return wrapper.
2358 ********************************************************************/
2360 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2362 #if defined(HAVE_AIO_RETURN)
2363 return aio_return(aiocb);
2370 /*******************************************************************
2371 An aio_cancel wrapper.
2372 ********************************************************************/
2374 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2376 #if defined(HAVE_AIO_CANCEL)
2377 return aio_cancel(fd, aiocb);
2384 /*******************************************************************
2385 An aio_error wrapper.
2386 ********************************************************************/
2388 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2390 #if defined(HAVE_AIO_ERROR)
2391 return aio_error(aiocb);
2398 /*******************************************************************
2399 An aio_fsync wrapper.
2400 ********************************************************************/
2402 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2404 #if defined(HAVE_AIO_FSYNC)
2405 return aio_fsync(op, aiocb);
2412 /*******************************************************************
2413 An aio_fsync wrapper.
2414 ********************************************************************/
2416 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2418 #if defined(HAVE_AIO_FSYNC)
2419 return aio_suspend(cblist, n, timeout);
2425 #else /* !WITH_AIO */
2427 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2433 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2439 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2445 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2451 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2457 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2463 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2468 #endif /* WITH_AIO */