source: trunk/server/source3/lib/system.c

Last change on this file was 912, checked in by Silvan Scherrer, 9 years ago

samba server: update build cmd to reflect the need of libcx, remove an unneeded memset

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