s3:lib: Fix code spelling
[Samba.git] / source3 / lib / system.c
blob7c9a6b5fa083ce68c506e5e74c1effdf416faaac
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
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/>.
23 #include "includes.h"
24 #include "system/syslog.h"
25 #include "system/capability.h"
26 #include "system/passwd.h"
27 #include "system/filesys.h"
28 #include "lib/util/setid.h"
29 #include "lib/util/time.h"
31 #ifdef HAVE_SYS_SYSCTL_H
32 #include <sys/sysctl.h>
33 #endif
35 #ifdef HAVE_SYS_PRCTL_H
36 #include <sys/prctl.h>
37 #endif
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)
60 ssize_t ret;
62 do {
63 ret = send(s, msg, len, flags);
64 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
66 return ret;
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)
76 ssize_t ret;
78 do {
79 ret = recvfrom(s, buf, len, flags, from, fromlen);
80 } while (ret == -1 && (errno == EINTR));
81 return ret;
84 /*******************************************************************
85 A fcntl wrapper that will deal with EINTR.
86 ********************************************************************/
88 int sys_fcntl_ptr(int fd, int cmd, void *arg)
90 int ret;
92 do {
93 ret = fcntl(fd, cmd, arg);
94 } while (ret == -1 && errno == EINTR);
95 return ret;
98 /*******************************************************************
99 A fcntl wrapper that will deal with EINTR.
100 ********************************************************************/
102 int sys_fcntl_long(int fd, int cmd, long arg)
104 int ret;
106 do {
107 ret = fcntl(fd, cmd, arg);
108 } while (ret == -1 && errno == EINTR);
109 return ret;
112 /*******************************************************************
113 A fcntl wrapper that will deal with EINTR.
114 ********************************************************************/
116 int sys_fcntl_int(int fd, int cmd, int arg)
118 int ret;
120 do {
121 ret = fcntl(fd, cmd, arg);
122 } while (ret == -1 && errno == EINTR);
123 return ret;
126 /****************************************************************************
127 Return the best approximation to a 'create time' under UNIX from a stat
128 structure.
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)) {
142 return ret1;
146 * One of ctime, mtime or atime was zero (probably atime).
147 * Just return MIN(ctime, mtime).
149 return ret;
152 /****************************************************************************
153 Return the best approximation to a 'create time' under UNIX from a stat_ex
154 structure.
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)) {
168 return ret1;
172 * One of ctime, mtime or atime was zero (probably atime).
173 * Just return MIN(ctime, mtime).
175 return ret;
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;
191 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
193 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
194 dst->st_ex_btime = pst->st_birthtimespec;
195 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
196 dst->st_ex_btime.tv_sec = pst->st_birthtime;
197 dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
198 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
199 dst->st_ex_btime.tv_sec = pst->st_birthtime;
200 dst->st_ex_btime.tv_nsec = 0;
201 #else
202 dst->st_ex_btime = calc_create_time_stat(pst);
203 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
204 #endif
206 /* Deal with systems that don't initialize birthtime correctly.
207 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
209 if (null_timespec(dst->st_ex_btime)) {
210 dst->st_ex_btime = calc_create_time_stat(pst);
211 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_BTIME;
215 /****************************************************************************
216 If we update a timestamp in a stat_ex struct we may have to recalculate
217 the birthtime. For now only implement this for write time, but we may
218 also need to do it for atime and ctime. JRA.
219 ****************************************************************************/
221 void update_stat_ex_mtime(struct stat_ex *dst,
222 struct timespec write_ts)
224 dst->st_ex_mtime = write_ts;
226 /* We may have to recalculate btime. */
227 if (dst->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME) {
228 dst->st_ex_btime = calc_create_time_stat_ex(dst);
232 void update_stat_ex_create_time(struct stat_ex *dst,
233 struct timespec create_time)
235 dst->st_ex_btime = create_time;
236 dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
239 void update_stat_ex_from_saved_stat(struct stat_ex *dst,
240 const struct stat_ex *src)
242 if (!VALID_STAT(*src)) {
243 return;
246 if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) {
247 update_stat_ex_create_time(dst, src->st_ex_btime);
251 void init_stat_ex_from_stat (struct stat_ex *dst,
252 const struct stat *src,
253 bool fake_dir_create_times)
255 dst->st_ex_dev = src->st_dev;
256 dst->st_ex_ino = src->st_ino;
257 dst->st_ex_mode = src->st_mode;
258 dst->st_ex_nlink = src->st_nlink;
259 dst->st_ex_uid = src->st_uid;
260 dst->st_ex_gid = src->st_gid;
261 dst->st_ex_rdev = src->st_rdev;
262 dst->st_ex_size = src->st_size;
263 dst->st_ex_atime = get_atimespec(src);
264 dst->st_ex_mtime = get_mtimespec(src);
265 dst->st_ex_ctime = get_ctimespec(src);
266 dst->st_ex_iflags = 0;
267 make_create_timespec(src, dst, fake_dir_create_times);
268 #ifdef HAVE_STAT_ST_BLKSIZE
269 dst->st_ex_blksize = src->st_blksize;
270 #else
271 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
272 #endif
274 #ifdef HAVE_STAT_ST_BLOCKS
275 dst->st_ex_blocks = src->st_blocks;
276 #else
277 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
278 #endif
280 #ifdef HAVE_STAT_ST_FLAGS
281 dst->st_ex_flags = src->st_flags;
282 #else
283 dst->st_ex_flags = 0;
284 #endif
287 /*******************************************************************
288 A stat() wrapper.
289 ********************************************************************/
291 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
292 bool fake_dir_create_times)
294 int ret;
295 struct stat statbuf;
296 ret = stat(fname, &statbuf);
297 if (ret == 0) {
298 /* we always want directories to appear zero size */
299 if (S_ISDIR(statbuf.st_mode)) {
300 statbuf.st_size = 0;
302 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
304 return ret;
307 /*******************************************************************
308 An fstat() wrapper.
309 ********************************************************************/
311 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
313 int ret;
314 struct stat statbuf;
315 ret = fstat(fd, &statbuf);
316 if (ret == 0) {
317 /* we always want directories to appear zero size */
318 if (S_ISDIR(statbuf.st_mode)) {
319 statbuf.st_size = 0;
321 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
323 return ret;
326 /*******************************************************************
327 An lstat() wrapper.
328 ********************************************************************/
330 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
331 bool fake_dir_create_times)
333 int ret;
334 struct stat statbuf;
335 ret = lstat(fname, &statbuf);
336 if (ret == 0) {
337 /* we always want directories to appear zero size */
338 if (S_ISDIR(statbuf.st_mode)) {
339 statbuf.st_size = 0;
341 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
343 return ret;
346 /*******************************************************************
347 An fstatat() wrapper.
348 ********************************************************************/
350 int sys_fstatat(int fd,
351 const char *pathname,
352 SMB_STRUCT_STAT *sbuf,
353 int flags,
354 bool fake_dir_create_times)
356 int ret;
357 struct stat statbuf;
359 ret = fstatat(fd, pathname, &statbuf, flags);
360 if (ret != 0) {
361 return -1;
364 /* we always want directories to appear zero size */
365 if (S_ISDIR(statbuf.st_mode)) {
366 statbuf.st_size = 0;
368 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
369 return 0;
372 /*******************************************************************
373 An posix_fallocate() wrapper.
374 ********************************************************************/
375 int sys_posix_fallocate(int fd, off_t offset, off_t len)
377 #if defined(HAVE_POSIX_FALLOCATE)
378 return posix_fallocate(fd, offset, len);
379 #elif defined(F_RESVSP64)
380 /* this handles XFS on IRIX */
381 struct flock64 fl;
382 off_t new_len = offset + len;
383 int ret;
384 struct stat64 sbuf;
386 /* unlikely to get a too large file on a 64bit system but ... */
387 if (new_len < 0)
388 return EFBIG;
390 fl.l_whence = SEEK_SET;
391 fl.l_start = offset;
392 fl.l_len = len;
394 ret=fcntl(fd, F_RESVSP64, &fl);
396 if (ret != 0)
397 return errno;
399 /* Make sure the file gets enlarged after we allocated space: */
400 fstat64(fd, &sbuf);
401 if (new_len > sbuf.st_size)
402 ftruncate64(fd, new_len);
403 return 0;
404 #else
405 return ENOSYS;
406 #endif
409 /*******************************************************************
410 An fallocate() function that matches the semantics of the Linux one.
411 ********************************************************************/
413 #ifdef HAVE_LINUX_FALLOC_H
414 #include <linux/falloc.h>
415 #endif
417 int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len)
419 #if defined(HAVE_LINUX_FALLOCATE)
420 int lmode = 0;
422 if (mode & VFS_FALLOCATE_FL_KEEP_SIZE) {
423 lmode |= FALLOC_FL_KEEP_SIZE;
424 mode &= ~VFS_FALLOCATE_FL_KEEP_SIZE;
427 #if defined(HAVE_FALLOC_FL_PUNCH_HOLE)
428 if (mode & VFS_FALLOCATE_FL_PUNCH_HOLE) {
429 lmode |= FALLOC_FL_PUNCH_HOLE;
430 mode &= ~VFS_FALLOCATE_FL_PUNCH_HOLE;
432 #endif /* HAVE_FALLOC_FL_PUNCH_HOLE */
434 if (mode != 0) {
435 DEBUG(2, ("unmapped fallocate flags: %lx\n",
436 (unsigned long)mode));
437 errno = EINVAL;
438 return -1;
440 return fallocate(fd, lmode, offset, len);
441 #else /* HAVE_LINUX_FALLOCATE */
442 /* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
443 errno = ENOSYS;
444 return -1;
445 #endif /* HAVE_LINUX_FALLOCATE */
448 /*******************************************************************
449 An fdopendir wrapper.
450 ********************************************************************/
452 DIR *sys_fdopendir(int fd)
454 #if defined(HAVE_FDOPENDIR)
455 return fdopendir(fd);
456 #else
457 errno = ENOSYS;
458 return NULL;
459 #endif
462 /*******************************************************************
463 An mknod() wrapper.
464 ********************************************************************/
466 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
468 #if defined(HAVE_MKNOD)
469 return mknod(path, mode, dev);
470 #else
471 /* No mknod system call. */
472 errno = ENOSYS;
473 return -1;
474 #endif
477 /*******************************************************************
478 A mknodat() wrapper.
479 ********************************************************************/
481 int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev)
483 #if defined(HAVE_MKNODAT)
484 return mknodat(dirfd, path, mode, dev);
485 #else
486 /* No mknod system call. */
487 errno = ENOSYS;
488 return -1;
489 #endif
492 /*******************************************************************
493 System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
494 on error (malloc fail usually).
495 ********************************************************************/
497 char *sys_getwd(void)
499 #ifdef GETCWD_TAKES_NULL
500 return getcwd(NULL, 0);
501 #elif defined(HAVE_GETCWD)
502 char *wd = NULL, *s = NULL;
503 size_t allocated = PATH_MAX;
505 while (1) {
506 s = SMB_REALLOC_ARRAY(s, char, allocated);
507 if (s == NULL) {
508 return NULL;
510 wd = getcwd(s, allocated);
511 if (wd) {
512 break;
514 if (errno != ERANGE) {
515 int saved_errno = errno;
516 SAFE_FREE(s);
517 errno = saved_errno;
518 break;
520 allocated *= 2;
521 if (allocated < PATH_MAX) {
522 SAFE_FREE(s);
523 break;
526 return wd;
527 #else
528 char *wd = NULL;
529 char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
530 if (s == NULL) {
531 return NULL;
533 wd = getwd(s);
534 if (wd == NULL) {
535 int saved_errno = errno;
536 SAFE_FREE(s);
537 errno = saved_errno;
539 return wd;
540 #endif
543 #if defined(HAVE_POSIX_CAPABILITIES)
545 /**************************************************************************
546 Try and abstract process capabilities (for systems that have them).
547 ****************************************************************************/
549 /* Set the POSIX capabilities needed for the given purpose into the effective
550 * capability set of the current process. Make sure they are always removed
551 * from the inheritable set, because there is no circumstance in which our
552 * children should inherit our elevated privileges.
554 static bool set_process_capability(enum smbd_capability capability,
555 bool enable)
557 /* "5" is the number of "num_cap_vals++" below */
558 cap_value_t cap_vals[5] = {0};
559 size_t num_cap_vals = 0;
561 cap_t cap;
563 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
564 /* On Linux, make sure that any capabilities we grab are sticky
565 * across UID changes. We expect that this would allow us to keep both
566 * the effective and permitted capability sets, but as of circa 2.6.16,
567 * only the permitted set is kept. It is a bug (which we work around)
568 * that the effective set is lost, but we still require the effective
569 * set to be kept.
571 if (!prctl(PR_GET_KEEPCAPS)) {
572 prctl(PR_SET_KEEPCAPS, 1);
574 #endif
576 cap = cap_get_proc();
577 if (cap == NULL) {
578 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
579 strerror(errno)));
580 return False;
583 switch (capability) {
585 * WARNING: If you add any #ifdef for a fresh
586 * capability, bump up the array size in the
587 * declaration of cap_vals[] above just to be
588 * trivially safe to never overwrite cap_vals[].
590 case KERNEL_OPLOCK_CAPABILITY:
591 #ifdef CAP_NETWORK_MGT
592 /* IRIX has CAP_NETWORK_MGT for oplocks. */
593 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
594 #endif
595 break;
596 case DMAPI_ACCESS_CAPABILITY:
597 #ifdef CAP_DEVICE_MGT
598 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
599 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
600 #elif CAP_MKNOD
601 /* Linux has CAP_MKNOD for DMAPI access. */
602 cap_vals[num_cap_vals++] = CAP_MKNOD;
603 #endif
604 break;
605 case LEASE_CAPABILITY:
606 #ifdef CAP_LEASE
607 cap_vals[num_cap_vals++] = CAP_LEASE;
608 #endif
609 break;
610 case DAC_OVERRIDE_CAPABILITY:
611 #ifdef CAP_DAC_OVERRIDE
612 cap_vals[num_cap_vals++] = CAP_DAC_OVERRIDE;
613 #endif
616 if (num_cap_vals == 0) {
617 cap_free(cap);
618 return True;
621 cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
622 enable ? CAP_SET : CAP_CLEAR);
624 /* We never want to pass capabilities down to our children, so make
625 * sure they are not inherited.
627 cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
629 if (cap_set_proc(cap) == -1) {
630 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
631 strerror(errno)));
632 cap_free(cap);
633 return False;
636 cap_free(cap);
637 return True;
640 #endif /* HAVE_POSIX_CAPABILITIES */
642 /****************************************************************************
643 Gain the oplock capability from the kernel if possible.
644 ****************************************************************************/
646 void set_effective_capability(enum smbd_capability capability)
648 #if defined(HAVE_POSIX_CAPABILITIES)
649 set_process_capability(capability, True);
650 #endif /* HAVE_POSIX_CAPABILITIES */
653 void drop_effective_capability(enum smbd_capability capability)
655 #if defined(HAVE_POSIX_CAPABILITIES)
656 set_process_capability(capability, False);
657 #endif /* HAVE_POSIX_CAPABILITIES */
660 /**************************************************************************
661 Wrapper for random().
662 ****************************************************************************/
664 long sys_random(void)
666 #if defined(HAVE_RANDOM)
667 return (long)random();
668 #elif defined(HAVE_RAND)
669 return (long)rand();
670 #else
671 DEBUG(0,("Error - no random function available !\n"));
672 exit(1);
673 #endif
676 /**************************************************************************
677 Wrapper for srandom().
678 ****************************************************************************/
680 void sys_srandom(unsigned int seed)
682 #if defined(HAVE_SRANDOM)
683 srandom(seed);
684 #elif defined(HAVE_SRAND)
685 srand(seed);
686 #else
687 DEBUG(0,("Error - no srandom function available !\n"));
688 exit(1);
689 #endif
692 #ifndef NGROUPS_MAX
693 #define NGROUPS_MAX 32 /* Guess... */
694 #endif
696 /**************************************************************************
697 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
698 ****************************************************************************/
700 int setgroups_max(void)
702 #if defined(SYSCONF_SC_NGROUPS_MAX)
703 int ret = sysconf(_SC_NGROUPS_MAX);
704 return (ret == -1) ? NGROUPS_MAX : ret;
705 #else
706 return NGROUPS_MAX;
707 #endif
710 int getgroups_max(void)
712 #if defined(DARWINOS)
714 * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group
715 * nesting. However, The initgroups() manpage states the following:
716 * "Note that OS X supports group membership in an unlimited number
717 * of groups. The OS X kernel uses the group list stored in the process
718 * credentials only as an initial cache. Additional group memberships
719 * are determined by communication between the operating system and the
720 * opendirectoryd daemon."
722 return INT_MAX;
723 #else
724 return setgroups_max();
725 #endif
728 /**************************************************************************
729 Wrap setgroups and getgroups for systems that declare getgroups() as
730 returning an array of gid_t, but actually return an array of int.
731 ****************************************************************************/
733 #if defined(HAVE_BROKEN_GETGROUPS)
735 #ifdef HAVE_BROKEN_GETGROUPS
736 #define GID_T int
737 #else
738 #define GID_T gid_t
739 #endif
741 static int sys_broken_getgroups(int setlen, gid_t *gidset)
743 GID_T *group_list;
744 int i, ngroups;
746 if(setlen == 0) {
747 return getgroups(0, NULL);
751 * Broken case. We need to allocate a
752 * GID_T array of size setlen.
755 if(setlen < 0) {
756 errno = EINVAL;
757 return -1;
760 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
761 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
762 return -1;
765 if((ngroups = getgroups(setlen, group_list)) < 0) {
766 int saved_errno = errno;
767 SAFE_FREE(group_list);
768 errno = saved_errno;
769 return -1;
773 * We're safe here as if ngroups > setlen then
774 * getgroups *must* return EINVAL.
775 * pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html
778 for(i = 0; i < ngroups; i++)
779 gidset[i] = (gid_t)group_list[i];
781 SAFE_FREE(group_list);
782 return ngroups;
785 static int sys_broken_setgroups(int setlen, gid_t *gidset)
787 GID_T *group_list;
788 int i ;
790 if (setlen == 0)
791 return 0 ;
793 if (setlen < 0 || setlen > setgroups_max()) {
794 errno = EINVAL;
795 return -1;
799 * Broken case. We need to allocate a
800 * GID_T array of size setlen.
803 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
804 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
805 return -1;
808 for(i = 0; i < setlen; i++)
809 group_list[i] = (GID_T) gidset[i];
811 if(samba_setgroups(setlen, group_list) != 0) {
812 int saved_errno = errno;
813 SAFE_FREE(group_list);
814 errno = saved_errno;
815 return -1;
818 SAFE_FREE(group_list);
819 return 0 ;
822 #endif /* HAVE_BROKEN_GETGROUPS */
824 /* This is a list of systems that require the first GID passed to setgroups(2)
825 * to be the effective GID. If your system is one of these, add it here.
827 #if defined (FREEBSD) || defined (DARWINOS)
828 #define USE_BSD_SETGROUPS
829 #endif
831 #if defined(USE_BSD_SETGROUPS)
832 /* Depending on the particular BSD implementation, the first GID that is
833 * passed to setgroups(2) will either be ignored or will set the credential's
834 * effective GID. In either case, the right thing to do is to guarantee that
835 * gidset[0] is the effective GID.
837 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
839 gid_t *new_gidset = NULL;
840 int max;
841 int ret;
843 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
844 max = setgroups_max();
846 /* No group list, just make sure we are setting the effective GID. */
847 if (setlen == 0) {
848 return samba_setgroups(1, &primary_gid);
851 /* If the primary gid is not the first array element, grow the array
852 * and insert it at the front.
854 if (gidset[0] != primary_gid) {
855 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
856 if (new_gidset == NULL) {
857 return -1;
860 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
861 new_gidset[0] = primary_gid;
862 setlen++;
865 if (setlen > max) {
866 DEBUG(3, ("forced to truncate group list from %d to %d\n",
867 setlen, max));
868 setlen = max;
871 #if defined(HAVE_BROKEN_GETGROUPS)
872 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
873 #else
874 ret = samba_setgroups(setlen, new_gidset ? new_gidset : gidset);
875 #endif
877 if (new_gidset) {
878 int errsav = errno;
879 SAFE_FREE(new_gidset);
880 errno = errsav;
883 return ret;
886 #endif /* USE_BSD_SETGROUPS */
888 /**************************************************************************
889 Wrapper for getgroups. Deals with broken (int) case.
890 ****************************************************************************/
892 int sys_getgroups(int setlen, gid_t *gidset)
894 #if defined(HAVE_BROKEN_GETGROUPS)
895 return sys_broken_getgroups(setlen, gidset);
896 #else
897 return getgroups(setlen, gidset);
898 #endif
901 /**************************************************************************
902 Wrapper for setgroups. Deals with broken (int) case and BSD case.
903 ****************************************************************************/
905 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
907 #if !defined(HAVE_SETGROUPS)
908 errno = ENOSYS;
909 return -1;
910 #endif /* HAVE_SETGROUPS */
912 #if defined(USE_BSD_SETGROUPS)
913 return sys_bsd_setgroups(primary_gid, setlen, gidset);
914 #elif defined(HAVE_BROKEN_GETGROUPS)
915 return sys_broken_setgroups(setlen, gidset);
916 #else
917 return samba_setgroups(setlen, gidset);
918 #endif
921 /****************************************************************************
922 Return the major devicenumber for UNIX extensions.
923 ****************************************************************************/
925 uint32_t unix_dev_major(SMB_DEV_T dev)
927 #if defined(HAVE_DEVICE_MAJOR_FN)
928 return (uint32_t)major(dev);
929 #else
930 return (uint32_t)(dev >> 8);
931 #endif
934 /****************************************************************************
935 Return the minor devicenumber for UNIX extensions.
936 ****************************************************************************/
938 uint32_t unix_dev_minor(SMB_DEV_T dev)
940 #if defined(HAVE_DEVICE_MINOR_FN)
941 return (uint32_t)minor(dev);
942 #else
943 return (uint32_t)(dev & 0xff);
944 #endif
947 /**************************************************************************
948 Wrapper for realpath.
949 ****************************************************************************/
951 char *sys_realpath(const char *path)
953 char *result;
955 #ifdef REALPATH_TAKES_NULL
956 result = realpath(path, NULL);
957 #else
958 result = SMB_MALLOC_ARRAY(char, PATH_MAX + 1);
959 if (result) {
960 char *resolved_path = realpath(path, result);
961 if (!resolved_path) {
962 SAFE_FREE(result);
963 } else {
964 /* SMB_ASSERT(result == resolved_path) ? */
965 result = resolved_path;
968 #endif
969 return result;
972 #if 0
973 /*******************************************************************
974 Return the number of CPUs.
975 ********************************************************************/
977 int sys_get_number_of_cores(void)
979 int ret = -1;
981 #if defined(HAVE_SYSCONF)
982 #if defined(_SC_NPROCESSORS_ONLN)
983 ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
984 #endif
985 #if defined(_SC_NPROCESSORS_CONF)
986 if (ret < 1) {
987 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
989 #endif
990 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
991 int name[2];
992 unsigned int len = sizeof(ret);
994 name[0] = CTL_HW;
995 #if defined(HW_AVAILCPU)
996 name[1] = HW_AVAILCPU;
998 if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
999 ret = -1;
1001 #endif
1002 #if defined(HW_NCPU)
1003 if(ret < 1) {
1004 name[0] = CTL_HW;
1005 name[1] = HW_NCPU;
1006 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
1007 ret = -1;
1010 #endif
1011 #endif
1012 if (ret < 1) {
1013 ret = 1;
1015 return ret;
1017 #endif
1019 static struct proc_fd_pattern {
1020 const char *pattern;
1021 const char *test_path;
1022 } proc_fd_patterns[] = {
1023 /* Linux */
1024 { "/proc/self/fd/%d", "/proc/self/fd/0" },
1025 { NULL, NULL },
1028 static const char *proc_fd_pattern;
1030 bool sys_have_proc_fds(void)
1032 static bool checked;
1033 static bool have_proc_fds;
1034 struct proc_fd_pattern *p = NULL;
1035 struct stat sb;
1036 int ret;
1038 if (checked) {
1039 return have_proc_fds;
1042 for (p = &proc_fd_patterns[0]; p->test_path != NULL; p++) {
1043 ret = stat(p->test_path, &sb);
1044 if (ret != 0) {
1045 continue;
1047 have_proc_fds = true;
1048 proc_fd_pattern = p->pattern;
1049 break;
1052 checked = true;
1053 return have_proc_fds;
1056 const char *sys_proc_fd_path(int fd, char *buf, size_t bufsize)
1058 int written;
1060 if (!sys_have_proc_fds()) {
1061 return NULL;
1064 #if defined(__clang__)
1065 #pragma clang diagnostic push
1066 #pragma clang diagnostic ignored "-Wformat-nonliteral"
1067 #endif
1068 written = snprintf(buf,
1069 bufsize,
1070 proc_fd_pattern,
1071 fd);
1072 #if defined(__clang__)
1073 #pragma clang diagnostic pop
1074 #endif
1075 if (written >= bufsize) {
1076 return NULL;
1079 return buf;