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"
28 #include "lib/util/setid.h"
29 #include "lib/util/time.h"
31 #ifdef HAVE_SYS_SYSCTL_H
32 #include <sys/sysctl.h>
35 #ifdef HAVE_SYS_PRCTL_H
36 #include <sys/prctl.h>
40 The idea is that this file will eventually have wrappers around all
41 important system calls in samba. The aims are:
43 - to enable easier porting by putting OS dependent stuff in here
45 - to allow for hooks into other "pseudo-filesystems"
47 - to allow easier integration of things like the japanese extensions
49 - to support the philosophy of Samba to expose the features of
50 the OS within the SMB model. In general whatever file/printer/variable
51 expansions/etc make sense to the OS should be acceptable to Samba.
54 /*******************************************************************
55 A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
56 ********************************************************************/
58 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
63 ret = send(s, msg, len, flags);
64 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
69 /*******************************************************************
70 A recvfrom wrapper that will deal with EINTR.
71 NB. As used with non-blocking sockets, return on EAGAIN/EWOULDBLOCK
72 ********************************************************************/
74 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
79 ret = recvfrom(s, buf, len, flags, from, fromlen);
80 } while (ret == -1 && (errno == EINTR));
84 /*******************************************************************
85 A fcntl wrapper that will deal with EINTR.
86 ********************************************************************/
88 int sys_fcntl_ptr(int fd, int cmd, void *arg)
93 ret = fcntl(fd, cmd, arg);
94 } while (ret == -1 && errno == EINTR);
98 /*******************************************************************
99 A fcntl wrapper that will deal with EINTR.
100 ********************************************************************/
102 int sys_fcntl_long(int fd, int cmd, long arg)
107 ret = fcntl(fd, cmd, arg);
108 } while (ret == -1 && errno == EINTR);
112 /*******************************************************************
113 A fcntl wrapper that will deal with EINTR.
114 ********************************************************************/
116 int sys_fcntl_int(int fd, int cmd, int arg)
121 ret = fcntl(fd, cmd, arg);
122 } while (ret == -1 && errno == EINTR);
126 /****************************************************************************
127 Return the best approximation to a 'create time' under UNIX from a stat
129 ****************************************************************************/
131 static struct timespec calc_create_time_stat(const struct stat *st)
133 struct timespec ret, ret1;
134 struct timespec c_time = get_ctimespec(st);
135 struct timespec m_time = get_mtimespec(st);
136 struct timespec a_time = get_atimespec(st);
138 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
139 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
141 if(!null_timespec(ret1)) {
146 * One of ctime, mtime or atime was zero (probably atime).
147 * Just return MIN(ctime, mtime).
152 /****************************************************************************
153 Return the best approximation to a 'create time' under UNIX from a stat_ex
155 ****************************************************************************/
157 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
159 struct timespec ret, ret1;
160 struct timespec c_time = st->st_ex_ctime;
161 struct timespec m_time = st->st_ex_mtime;
162 struct timespec a_time = st->st_ex_atime;
164 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
165 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
167 if(!null_timespec(ret1)) {
172 * One of ctime, mtime or atime was zero (probably atime).
173 * Just return MIN(ctime, mtime).
178 /****************************************************************************
179 Return the 'create time' from a stat struct if it exists (birthtime) or else
180 use the best approximation.
181 ****************************************************************************/
183 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
184 bool fake_dir_create_times)
186 if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
187 dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */
188 dst->st_ex_btime.tv_nsec = 0;
192 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
194 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
195 dst->st_ex_btime = pst->st_birthtimespec;
196 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
197 dst->st_ex_btime.tv_sec = pst->st_birthtime;
198 dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
199 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
200 dst->st_ex_btime.tv_sec = pst->st_birthtime;
201 dst->st_ex_btime.tv_nsec = 0;
203 dst->st_ex_btime = calc_create_time_stat(pst);
204 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
207 /* Deal with systems that don't initialize birthtime correctly.
208 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
210 if (null_timespec(dst->st_ex_btime)) {
211 dst->st_ex_btime = calc_create_time_stat(pst);
212 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
216 /****************************************************************************
217 If we update a timestamp in a stat_ex struct we may have to recalculate
218 the birthtime. For now only implement this for write time, but we may
219 also need to do it for atime and ctime. JRA.
220 ****************************************************************************/
222 void update_stat_ex_mtime(struct stat_ex *dst,
223 struct timespec write_ts)
225 dst->st_ex_mtime = write_ts;
227 /* We may have to recalculate btime. */
228 if (dst->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME) {
229 dst->st_ex_btime = calc_create_time_stat_ex(dst);
233 void update_stat_ex_create_time(struct stat_ex *dst,
234 struct timespec create_time)
236 dst->st_ex_btime = create_time;
237 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
240 void update_stat_ex_from_saved_stat(struct stat_ex *dst,
241 const struct stat_ex *src)
243 if (!VALID_STAT(*src)) {
247 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) {
248 update_stat_ex_create_time(dst, src->st_ex_btime);
252 void init_stat_ex_from_stat (struct stat_ex *dst,
253 const struct stat *src,
254 bool fake_dir_create_times)
256 dst->st_ex_dev = src->st_dev;
257 dst->st_ex_ino = src->st_ino;
258 dst->st_ex_mode = src->st_mode;
259 dst->st_ex_nlink = src->st_nlink;
260 dst->st_ex_uid = src->st_uid;
261 dst->st_ex_gid = src->st_gid;
262 dst->st_ex_rdev = src->st_rdev;
263 dst->st_ex_size = src->st_size;
264 dst->st_ex_atime = get_atimespec(src);
265 dst->st_ex_mtime = get_mtimespec(src);
266 dst->st_ex_ctime = get_ctimespec(src);
267 dst->st_ex_iflags = 0;
268 make_create_timespec(src, dst, fake_dir_create_times);
269 #ifdef HAVE_STAT_ST_BLKSIZE
270 dst->st_ex_blksize = src->st_blksize;
272 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
275 #ifdef HAVE_STAT_ST_BLOCKS
276 dst->st_ex_blocks = src->st_blocks;
278 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
281 #ifdef HAVE_STAT_ST_FLAGS
282 dst->st_ex_flags = src->st_flags;
284 dst->st_ex_flags = 0;
288 /*******************************************************************
290 ********************************************************************/
292 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
293 bool fake_dir_create_times)
297 ret = stat(fname, &statbuf);
299 /* we always want directories to appear zero size */
300 if (S_ISDIR(statbuf.st_mode)) {
303 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
308 /*******************************************************************
310 ********************************************************************/
312 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
316 ret = fstat(fd, &statbuf);
318 /* we always want directories to appear zero size */
319 if (S_ISDIR(statbuf.st_mode)) {
322 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
327 /*******************************************************************
329 ********************************************************************/
331 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
332 bool fake_dir_create_times)
336 ret = lstat(fname, &statbuf);
338 /* we always want directories to appear zero size */
339 if (S_ISDIR(statbuf.st_mode)) {
342 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
347 /*******************************************************************
348 An fstatat() wrapper.
349 ********************************************************************/
351 int sys_fstatat(int fd,
352 const char *pathname,
353 SMB_STRUCT_STAT *sbuf,
355 bool fake_dir_create_times)
360 ret = fstatat(fd, pathname, &statbuf, flags);
365 /* we always want directories to appear zero size */
366 if (S_ISDIR(statbuf.st_mode)) {
369 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
373 /*******************************************************************
374 An posix_fallocate() wrapper.
375 ********************************************************************/
376 int sys_posix_fallocate(int fd, off_t offset, off_t len)
378 #if defined(HAVE_POSIX_FALLOCATE)
379 return posix_fallocate(fd, offset, len);
380 #elif defined(F_RESVSP64)
381 /* this handles XFS on IRIX */
383 off_t new_len = offset + len;
387 /* unlikely to get a too large file on a 64bit system but ... */
391 fl.l_whence = SEEK_SET;
395 ret=fcntl(fd, F_RESVSP64, &fl);
400 /* Make sure the file gets enlarged after we allocated space: */
402 if (new_len > sbuf.st_size)
403 ftruncate64(fd, new_len);
410 /*******************************************************************
411 An fallocate() function that matches the semantics of the Linux one.
412 ********************************************************************/
414 #ifdef HAVE_LINUX_FALLOC_H
415 #include <linux/falloc.h>
418 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
420 #if defined(HAVE_LINUX_FALLOCATE)
423 if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
424 lmode |= FALLOC_FL_KEEP_SIZE;
425 mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
428 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
429 if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
430 lmode |= FALLOC_FL_PUNCH_HOLE;
431 mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
433 #endif /* HAVE_FALLOC_FL_PUNCH_HOLE */
436 DEBUG(2, ("unmapped fallocate flags: %lx\n",
437 (unsigned long)mode));
441 return fallocate(fd, lmode, offset, len);
442 #else /* HAVE_LINUX_FALLOCATE */
443 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
446 #endif /* HAVE_LINUX_FALLOCATE */
449 /*******************************************************************
450 An fdopendir wrapper.
451 ********************************************************************/
453 DIR *sys_fdopendir(int fd)
455 #if defined(HAVE_FDOPENDIR)
456 return fdopendir(fd);
463 /*******************************************************************
465 ********************************************************************/
467 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
469 #if defined(HAVE_MKNOD)
470 return mknod(path, mode, dev);
472 /* No mknod system call. */
478 /*******************************************************************
480 ********************************************************************/
482 int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
484 #if defined(HAVE_MKNODAT)
485 return mknodat(dirfd, path, mode, dev);
487 /* No mknod system call. */
493 /*******************************************************************
494 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
495 on error (malloc fail usually).
496 ********************************************************************/
498 char *sys_getwd(void)
500 #ifdef GETCWD_TAKES_NULL
501 return getcwd(NULL, 0);
502 #elif defined(HAVE_GETCWD)
503 char *wd = NULL, *s = NULL;
504 size_t allocated = PATH_MAX;
507 s = SMB_REALLOC_ARRAY(s, char, allocated);
511 wd = getcwd(s, allocated);
515 if (errno != ERANGE) {
516 int saved_errno = errno;
522 if (allocated < PATH_MAX) {
530 char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
536 int saved_errno = errno;
544 #if defined(HAVE_POSIX_CAPABILITIES)
546 /**************************************************************************
547 Try and abstract process capabilities (for systems that have them).
548 ****************************************************************************/
550 /* Set the POSIX capabilities needed for the given purpose into the effective
551 * capability set of the current process. Make sure they are always removed
552 * from the inheritable set, because there is no circumstance in which our
553 * children should inherit our elevated privileges.
555 static bool set_process_capability(enum smbd_capability capability,
558 /* "5" is the number of "num_cap_vals++" below */
559 cap_value_t cap_vals[5] = {0};
560 size_t num_cap_vals = 0;
564 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
565 /* On Linux, make sure that any capabilities we grab are sticky
566 * across UID changes. We expect that this would allow us to keep both
567 * the effective and permitted capability sets, but as of circa 2.6.16,
568 * only the permitted set is kept. It is a bug (which we work around)
569 * that the effective set is lost, but we still require the effective
572 if (!prctl(PR_GET_KEEPCAPS)) {
573 prctl(PR_SET_KEEPCAPS, 1);
577 cap = cap_get_proc();
579 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
584 switch (capability) {
586 * WARNING: If you add any #ifdef for a fresh
587 * capability, bump up the array size in the
588 * declaration of cap_vals[] above just to be
589 * trivially safe to never overwrite cap_vals[].
591 case KERNEL_OPLOCK_CAPABILITY:
592 #ifdef CAP_NETWORK_MGT
593 /* IRIX has CAP_NETWORK_MGT for oplocks. */
594 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
597 case DMAPI_ACCESS_CAPABILITY:
598 #ifdef CAP_DEVICE_MGT
599 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
600 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
602 /* Linux has CAP_MKNOD for DMAPI access. */
603 cap_vals[num_cap_vals++] = CAP_MKNOD;
606 case LEASE_CAPABILITY:
608 cap_vals[num_cap_vals++] = CAP_LEASE;
611 case DAC_OVERRIDE_CAPABILITY:
612 #ifdef CAP_DAC_OVERRIDE
613 cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
617 if (num_cap_vals == 0) {
622 cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
623 enable ? CAP_SET : CAP_CLEAR);
625 /* We never want to pass capabilities down to our children, so make
626 * sure they are not inherited.
628 cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
630 if (cap_set_proc(cap) == -1) {
631 DBG_ERR("adding capability %d: cap_set_proc failed: %s\n",
632 capability, strerror(errno));
636 DBG_INFO("added capability %d\n", capability);
642 #endif /* HAVE_POSIX_CAPABILITIES */
644 /****************************************************************************
645 Gain the oplock capability from the kernel if possible.
646 ****************************************************************************/
648 #if defined(HAVE_POSIX_CAPABILITIES) && defined(CAP_DAC_OVERRIDE)
649 static bool have_cap_dac_override = true;
651 static bool have_cap_dac_override = false;
654 void set_effective_capability(enum smbd_capability capability)
658 if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
659 #if defined(HAVE_POSIX_CAPABILITIES)
660 ret = set_process_capability(capability, True);
661 #endif /* HAVE_POSIX_CAPABILITIES */
665 * Fallback to become_root() if CAP_DAC_OVERRIDE is not
668 if (capability == DAC_OVERRIDE_CAPABILITY) {
670 have_cap_dac_override = false;
672 if (!have_cap_dac_override) {
678 void drop_effective_capability(enum smbd_capability capability)
680 if (capability != DAC_OVERRIDE_CAPABILITY || have_cap_dac_override) {
681 #if defined(HAVE_POSIX_CAPABILITIES)
682 set_process_capability(capability, False);
683 #endif /* HAVE_POSIX_CAPABILITIES */
689 /**************************************************************************
690 Wrapper for random().
691 ****************************************************************************/
693 long sys_random(void)
695 #if defined(HAVE_RANDOM)
696 return (long)random();
697 #elif defined(HAVE_RAND)
700 DEBUG(0,("Error - no random function available !\n"));
705 /**************************************************************************
706 Wrapper for srandom().
707 ****************************************************************************/
709 void sys_srandom(unsigned int seed)
711 #if defined(HAVE_SRANDOM)
713 #elif defined(HAVE_SRAND)
716 DEBUG(0,("Error - no srandom function available !\n"));
722 #define NGROUPS_MAX 32 /* Guess... */
725 /**************************************************************************
726 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
727 ****************************************************************************/
729 int setgroups_max(void)
731 #if defined(SYSCONF_SC_NGROUPS_MAX)
732 int ret = sysconf(_SC_NGROUPS_MAX);
733 return (ret == -1) ? NGROUPS_MAX : ret;
739 int getgroups_max(void)
741 #if defined(DARWINOS)
743 * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
744 * nesting. However, The initgroups() manpage states the following:
745 * "Note that OS X supports group membership in an unlimited number
746 * of groups. The OS X kernel uses the group list stored in the process
747 * credentials only as an initial cache. Additional group memberships
748 * are determined by communication between the operating system and the
749 * opendirectoryd daemon."
753 return setgroups_max();
757 /**************************************************************************
758 Wrap setgroups and getgroups for systems that declare getgroups() as
759 returning an array of gid_t, but actually return an array of int.
760 ****************************************************************************/
762 #if defined(HAVE_BROKEN_GETGROUPS)
764 #ifdef HAVE_BROKEN_GETGROUPS
770 static int sys_broken_getgroups(int setlen, gid_t *gidset)
776 return getgroups(0, NULL);
780 * Broken case. We need to allocate a
781 * GID_T array of size setlen.
789 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
790 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
794 if((ngroups = getgroups(setlen, group_list)) < 0) {
795 int saved_errno = errno;
796 SAFE_FREE(group_list);
802 * We're safe here as if ngroups > setlen then
803 * getgroups *must* return EINVAL.
804 * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
807 for(i = 0; i < ngroups; i++)
808 gidset[i] = (gid_t)group_list[i];
810 SAFE_FREE(group_list);
814 static int sys_broken_setgroups(int setlen, gid_t *gidset)
822 if (setlen < 0 || setlen > setgroups_max()) {
828 * Broken case. We need to allocate a
829 * GID_T array of size setlen.
832 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
833 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
837 for(i = 0; i < setlen; i++)
838 group_list[i] = (GID_T) gidset[i];
840 if(samba_setgroups(setlen, group_list) != 0) {
841 int saved_errno = errno;
842 SAFE_FREE(group_list);
847 SAFE_FREE(group_list);
851 #endif /* HAVE_BROKEN_GETGROUPS */
853 /* This is a list of systems that require the first GID passed to setgroups(2)
854 * to be the effective GID. If your system is one of these, add it here.
856 #if defined (FREEBSD) || defined (DARWINOS)
857 #define USE_BSD_SETGROUPS
860 #if defined(USE_BSD_SETGROUPS)
861 /* Depending on the particular BSD implementation, the first GID that is
862 * passed to setgroups(2) will either be ignored or will set the credential's
863 * effective GID. In either case, the right thing to do is to guarantee that
864 * gidset[0] is the effective GID.
866 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
868 gid_t *new_gidset = NULL;
872 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
873 max = setgroups_max();
875 /* No group list, just make sure we are setting the effective GID. */
877 return samba_setgroups(1, &primary_gid);
880 /* If the primary gid is not the first array element, grow the array
881 * and insert it at the front.
883 if (gidset[0] != primary_gid) {
884 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
885 if (new_gidset == NULL) {
889 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
890 new_gidset[0] = primary_gid;
895 DEBUG(3, ("forced to truncate group list from %d to %d\n",
900 #if defined(HAVE_BROKEN_GETGROUPS)
901 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
903 ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
908 SAFE_FREE(new_gidset);
915 #endif /* USE_BSD_SETGROUPS */
917 /**************************************************************************
918 Wrapper for getgroups. Deals with broken (int) case.
919 ****************************************************************************/
921 int sys_getgroups(int setlen, gid_t *gidset)
923 #if defined(HAVE_BROKEN_GETGROUPS)
924 return sys_broken_getgroups(setlen, gidset);
926 return getgroups(setlen, gidset);
930 /**************************************************************************
931 Wrapper for setgroups. Deals with broken (int) case and BSD case.
932 ****************************************************************************/
934 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
936 #if !defined(HAVE_SETGROUPS)
939 #endif /* HAVE_SETGROUPS */
941 #if defined(USE_BSD_SETGROUPS)
942 return sys_bsd_setgroups(primary_gid, setlen, gidset);
943 #elif defined(HAVE_BROKEN_GETGROUPS)
944 return sys_broken_setgroups(setlen, gidset);
946 return samba_setgroups(setlen, gidset);
950 /****************************************************************************
951 Return the major devicenumber for UNIX extensions.
952 ****************************************************************************/
954 uint32_t unix_dev_major(SMB_DEV_T dev)
956 #if defined(HAVE_DEVICE_MAJOR_FN)
957 return (uint32_t)major(dev);
959 return (uint32_t)(dev >> 8);
963 /****************************************************************************
964 Return the minor devicenumber for UNIX extensions.
965 ****************************************************************************/
967 uint32_t unix_dev_minor(SMB_DEV_T dev)
969 #if defined(HAVE_DEVICE_MINOR_FN)
970 return (uint32_t)minor(dev);
972 return (uint32_t)(dev & 0xff);
976 /**************************************************************************
977 Wrapper for realpath.
978 ****************************************************************************/
980 char *sys_realpath(const char *path)
984 #ifdef REALPATH_TAKES_NULL
985 result = realpath(path, NULL);
987 result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
989 char *resolved_path = realpath(path, result);
990 if (!resolved_path) {
993 /* SMB_ASSERT(result == resolved_path) ? */
994 result = resolved_path;
1002 /*******************************************************************
1003 Return the number of CPUs.
1004 ********************************************************************/
1006 int sys_get_number_of_cores(void)
1010 #if defined(HAVE_SYSCONF)
1011 #if defined(_SC_NPROCESSORS_ONLN)
1012 ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
1014 #if defined(_SC_NPROCESSORS_CONF)
1016 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
1019 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
1021 unsigned int len = sizeof(ret);
1024 #if defined(HW_AVAILCPU)
1025 name[1] = HW_AVAILCPU;
1027 if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
1031 #if defined(HW_NCPU)
1035 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1048 bool sys_have_proc_fds(void)
1050 static bool checked = false;
1051 static bool have_proc_fds = false;
1056 return have_proc_fds;
1059 ret = stat("/proc/self/fd/0", &sb);
1060 have_proc_fds = (ret == 0);
1063 return have_proc_fds;
1066 char *sys_proc_fd_path(int fd, struct sys_proc_fd_path_buf *buf)
1069 snprintf(buf->buf, sizeof(buf->buf), "/proc/self/fd/%d", fd);
1071 SMB_ASSERT(sys_have_proc_fds() && (written >= 0));