Fix from James Flemer <jflemer@uvm.edu> to make HAVE_ATTR_LIST linked to
[ira/wip.git] / source3 / lib / system.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 1998-2002
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /*
25    The idea is that this file will eventually have wrappers around all
26    important system calls in samba. The aims are:
27
28    - to enable easier porting by putting OS dependent stuff in here
29
30    - to allow for hooks into other "pseudo-filesystems"
31
32    - to allow easier integration of things like the japanese extensions
33
34    - to support the philosophy of Samba to expose the features of
35      the OS within the SMB model. In general whatever file/printer/variable
36      expansions/etc make sense to the OS should be acceptable to Samba.
37 */
38
39
40
41 /*******************************************************************
42  A wrapper for usleep in case we don't have one.
43 ********************************************************************/
44
45 int sys_usleep(long usecs)
46 {
47 #ifndef HAVE_USLEEP
48         struct timeval tval;
49 #endif
50
51         /*
52          * We need this braindamage as the glibc usleep
53          * is not SPEC1170 complient... grumble... JRA.
54          */
55
56         if(usecs < 0 || usecs > 1000000) {
57                 errno = EINVAL;
58                 return -1;
59         }
60
61 #if HAVE_USLEEP
62         usleep(usecs);
63         return 0;
64 #else /* HAVE_USLEEP */
65         /*
66          * Fake it with select...
67          */
68         tval.tv_sec = 0;
69         tval.tv_usec = usecs/1000;
70         select(0,NULL,NULL,NULL,&tval);
71         return 0;
72 #endif /* HAVE_USLEEP */
73 }
74
75 /*******************************************************************
76 A read wrapper that will deal with EINTR.
77 ********************************************************************/
78
79 ssize_t sys_read(int fd, void *buf, size_t count)
80 {
81         ssize_t ret;
82
83         do {
84                 ret = read(fd, buf, count);
85         } while (ret == -1 && errno == EINTR);
86         return ret;
87 }
88
89 /*******************************************************************
90 A write wrapper that will deal with EINTR.
91 ********************************************************************/
92
93 ssize_t sys_write(int fd, const void *buf, size_t count)
94 {
95         ssize_t ret;
96
97         do {
98                 ret = write(fd, buf, count);
99         } while (ret == -1 && errno == EINTR);
100         return ret;
101 }
102
103 /*******************************************************************
104 A send wrapper that will deal with EINTR.
105 ********************************************************************/
106
107 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
108 {
109         ssize_t ret;
110
111         do {
112                 ret = send(s, msg, len, flags);
113         } while (ret == -1 && errno == EINTR);
114         return ret;
115 }
116
117 /*******************************************************************
118 A sendto wrapper that will deal with EINTR.
119 ********************************************************************/
120
121 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
122 {
123         ssize_t ret;
124
125         do {
126                 ret = sendto(s, msg, len, flags, to, tolen);
127         } while (ret == -1 && errno == EINTR);
128         return ret;
129 }
130
131 /*******************************************************************
132 A recvfrom wrapper that will deal with EINTR.
133 ********************************************************************/
134
135 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
136 {
137         ssize_t ret;
138
139         do {
140                 ret = recvfrom(s, buf, len, flags, from, fromlen);
141         } while (ret == -1 && errno == EINTR);
142         return ret;
143 }
144
145 /*******************************************************************
146 A fcntl wrapper that will deal with EINTR.
147 ********************************************************************/
148
149 int sys_fcntl_ptr(int fd, int cmd, void *arg)
150 {
151         int ret;
152
153         do {
154                 ret = fcntl(fd, cmd, arg);
155         } while (ret == -1 && errno == EINTR);
156         return ret;
157 }
158
159 /*******************************************************************
160 A fcntl wrapper that will deal with EINTR.
161 ********************************************************************/
162
163 int sys_fcntl_long(int fd, int cmd, long arg)
164 {
165         int ret;
166
167         do {
168                 ret = fcntl(fd, cmd, arg);
169         } while (ret == -1 && errno == EINTR);
170         return ret;
171 }
172
173 /*******************************************************************
174 A stat() wrapper that will deal with 64 bit filesizes.
175 ********************************************************************/
176
177 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
178 {
179         int ret;
180 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
181         ret = stat64(fname, sbuf);
182 #else
183         ret = stat(fname, sbuf);
184 #endif
185         /* we always want directories to appear zero size */
186         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
187         return ret;
188 }
189
190 /*******************************************************************
191  An fstat() wrapper that will deal with 64 bit filesizes.
192 ********************************************************************/
193
194 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
195 {
196         int ret;
197 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
198         ret = fstat64(fd, sbuf);
199 #else
200         ret = fstat(fd, sbuf);
201 #endif
202         /* we always want directories to appear zero size */
203         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
204         return ret;
205 }
206
207 /*******************************************************************
208  An lstat() wrapper that will deal with 64 bit filesizes.
209 ********************************************************************/
210
211 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
212 {
213         int ret;
214 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
215         ret = lstat64(fname, sbuf);
216 #else
217         ret = lstat(fname, sbuf);
218 #endif
219         /* we always want directories to appear zero size */
220         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
221         return ret;
222 }
223
224 /*******************************************************************
225  An ftruncate() wrapper that will deal with 64 bit filesizes.
226 ********************************************************************/
227
228 int sys_ftruncate(int fd, SMB_OFF_T offset)
229 {
230 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
231         return ftruncate64(fd, offset);
232 #else
233         return ftruncate(fd, offset);
234 #endif
235 }
236
237 /*******************************************************************
238  An lseek() wrapper that will deal with 64 bit filesizes.
239 ********************************************************************/
240
241 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
242 {
243 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
244         return lseek64(fd, offset, whence);
245 #else
246         return lseek(fd, offset, whence);
247 #endif
248 }
249
250 /*******************************************************************
251  An fseek() wrapper that will deal with 64 bit filesizes.
252 ********************************************************************/
253
254 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
255 {
256 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
257         return fseek64(fp, offset, whence);
258 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
259         return fseeko64(fp, offset, whence);
260 #else
261         return fseek(fp, offset, whence);
262 #endif
263 }
264
265 /*******************************************************************
266  An ftell() wrapper that will deal with 64 bit filesizes.
267 ********************************************************************/
268
269 SMB_OFF_T sys_ftell(FILE *fp)
270 {
271 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
272         return (SMB_OFF_T)ftell64(fp);
273 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
274         return (SMB_OFF_T)ftello64(fp);
275 #else
276         return (SMB_OFF_T)ftell(fp);
277 #endif
278 }
279
280 /*******************************************************************
281  A creat() wrapper that will deal with 64 bit filesizes.
282 ********************************************************************/
283
284 int sys_creat(const char *path, mode_t mode)
285 {
286 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
287         return creat64(path, mode);
288 #else
289         /*
290          * If creat64 isn't defined then ensure we call a potential open64.
291          * JRA.
292          */
293         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
294 #endif
295 }
296
297 /*******************************************************************
298  An open() wrapper that will deal with 64 bit filesizes.
299 ********************************************************************/
300
301 int sys_open(const char *path, int oflag, mode_t mode)
302 {
303 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
304         return open64(path, oflag, mode);
305 #else
306         return open(path, oflag, mode);
307 #endif
308 }
309
310 /*******************************************************************
311  An fopen() wrapper that will deal with 64 bit filesizes.
312 ********************************************************************/
313
314 FILE *sys_fopen(const char *path, const char *type)
315 {
316 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
317         return fopen64(path, type);
318 #else
319         return fopen(path, type);
320 #endif
321 }
322
323 /*******************************************************************
324  A readdir wrapper that will deal with 64 bit filesizes.
325 ********************************************************************/
326
327 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
328 {
329 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
330         return readdir64(dirp);
331 #else
332         return readdir(dirp);
333 #endif
334 }
335
336 /*******************************************************************
337  An mknod() wrapper that will deal with 64 bit filesizes.
338 ********************************************************************/
339
340 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
341 {
342 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
343 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
344         return mknod64(path, mode, dev);
345 #else
346         return mknod(path, mode, dev);
347 #endif
348 #else
349         /* No mknod system call. */
350         errno = ENOSYS;
351         return -1;
352 #endif
353 }
354
355 /*******************************************************************
356  Wrapper for realpath.
357 ********************************************************************/
358
359 char *sys_realpath(const char *path, char *resolved_path)
360 {
361 #if defined(HAVE_REALPATH)
362         return realpath(path, resolved_path);
363 #else
364         /* As realpath is not a system call we can't return ENOSYS. */
365         errno = EINVAL;
366         return NULL;
367 #endif
368 }
369
370 /*******************************************************************
371 The wait() calls vary between systems
372 ********************************************************************/
373
374 int sys_waitpid(pid_t pid,int *status,int options)
375 {
376 #ifdef HAVE_WAITPID
377         return waitpid(pid,status,options);
378 #else /* HAVE_WAITPID */
379         return wait4(pid, status, options, NULL);
380 #endif /* HAVE_WAITPID */
381 }
382
383 /*******************************************************************
384  System wrapper for getwd
385 ********************************************************************/
386
387 char *sys_getwd(char *s)
388 {
389         char *wd;
390 #ifdef HAVE_GETCWD
391         wd = (char *)getcwd(s, sizeof (pstring));
392 #else
393         wd = (char *)getwd(s);
394 #endif
395         return wd;
396 }
397
398 /*******************************************************************
399 system wrapper for symlink
400 ********************************************************************/
401
402 int sys_symlink(const char *oldpath, const char *newpath)
403 {
404 #ifndef HAVE_SYMLINK
405         errno = ENOSYS;
406         return -1;
407 #else
408         return symlink(oldpath, newpath);
409 #endif
410 }
411
412 /*******************************************************************
413 system wrapper for readlink
414 ********************************************************************/
415
416 int sys_readlink(const char *path, char *buf, size_t bufsiz)
417 {
418 #ifndef HAVE_READLINK
419         errno = ENOSYS;
420         return -1;
421 #else
422         return readlink(path, buf, bufsiz);
423 #endif
424 }
425
426 /*******************************************************************
427 system wrapper for link
428 ********************************************************************/
429
430 int sys_link(const char *oldpath, const char *newpath)
431 {
432 #ifndef HAVE_LINK
433         errno = ENOSYS;
434         return -1;
435 #else
436         return link(oldpath, newpath);
437 #endif
438 }
439
440 /*******************************************************************
441 chown isn't used much but OS/2 doesn't have it
442 ********************************************************************/
443
444 int sys_chown(const char *fname,uid_t uid,gid_t gid)
445 {
446 #ifndef HAVE_CHOWN
447         static int done;
448         if (!done) {
449                 DEBUG(1,("WARNING: no chown!\n"));
450                 done=1;
451         }
452 #else
453         return(chown(fname,uid,gid));
454 #endif
455 }
456
457 /*******************************************************************
458 os/2 also doesn't have chroot
459 ********************************************************************/
460 int sys_chroot(const char *dname)
461 {
462 #ifndef HAVE_CHROOT
463         static int done;
464         if (!done) {
465                 DEBUG(1,("WARNING: no chroot!\n"));
466                 done=1;
467         }
468         errno = ENOSYS;
469         return -1;
470 #else
471         return(chroot(dname));
472 #endif
473 }
474
475 /**************************************************************************
476 A wrapper for gethostbyname() that tries avoids looking up hostnames 
477 in the root domain, which can cause dial-on-demand links to come up for no
478 apparent reason.
479 ****************************************************************************/
480
481 struct hostent *sys_gethostbyname(const char *name)
482 {
483 #ifdef REDUCE_ROOT_DNS_LOOKUPS
484         char query[256], hostname[256];
485         char *domain;
486
487         /* Does this name have any dots in it? If so, make no change */
488
489         if (strchr_m(name, '.'))
490                 return(gethostbyname(name));
491
492         /* Get my hostname, which should have domain name 
493                 attached. If not, just do the gethostname on the
494                 original string. 
495         */
496
497         gethostname(hostname, sizeof(hostname) - 1);
498         hostname[sizeof(hostname) - 1] = 0;
499         if ((domain = strchr_m(hostname, '.')) == NULL)
500                 return(gethostbyname(name));
501
502         /* Attach domain name to query and do modified query.
503                 If names too large, just do gethostname on the
504                 original string.
505         */
506
507         if((strlen(name) + strlen(domain)) >= sizeof(query))
508                 return(gethostbyname(name));
509
510         slprintf(query, sizeof(query)-1, "%s%s", name, domain);
511         return(gethostbyname(query));
512 #else /* REDUCE_ROOT_DNS_LOOKUPS */
513         return(gethostbyname(name));
514 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
515 }
516
517
518 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
519 /**************************************************************************
520  Try and abstract process capabilities (for systems that have them).
521 ****************************************************************************/
522 static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
523 {
524         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
525                 cap_t cap = cap_get_proc();
526
527                 if (cap == NULL) {
528                         DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
529                                 strerror(errno)));
530                         return False;
531                 }
532
533                 if(enable)
534                         cap->cap_effective |= CAP_NETWORK_MGT;
535                 else
536                         cap->cap_effective &= ~CAP_NETWORK_MGT;
537
538                 if (cap_set_proc(cap) == -1) {
539                         DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
540                                 strerror(errno)));
541                         cap_free(cap);
542                         return False;
543                 }
544
545                 cap_free(cap);
546
547                 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
548         }
549         return True;
550 }
551
552 /**************************************************************************
553  Try and abstract inherited process capabilities (for systems that have them).
554 ****************************************************************************/
555
556 static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
557 {
558         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
559                 cap_t cap = cap_get_proc();
560
561                 if (cap == NULL) {
562                         DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
563                                 strerror(errno)));
564                         return False;
565                 }
566
567                 if(enable)
568                         cap->cap_inheritable |= CAP_NETWORK_MGT;
569                 else
570                         cap->cap_inheritable &= ~CAP_NETWORK_MGT;
571
572                 if (cap_set_proc(cap) == -1) {
573                         DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
574                                 strerror(errno)));
575                         cap_free(cap);
576                         return False;
577                 }
578
579                 cap_free(cap);
580
581                 DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
582         }
583         return True;
584 }
585 #endif
586
587 /****************************************************************************
588  Gain the oplock capability from the kernel if possible.
589 ****************************************************************************/
590
591 void oplock_set_capability(BOOL this_process, BOOL inherit)
592 {
593 #if HAVE_KERNEL_OPLOCKS_IRIX
594         set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
595         set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
596 #endif
597 }
598
599 /**************************************************************************
600  Wrapper for random().
601 ****************************************************************************/
602
603 long sys_random(void)
604 {
605 #if defined(HAVE_RANDOM)
606         return (long)random();
607 #elif defined(HAVE_RAND)
608         return (long)rand();
609 #else
610         DEBUG(0,("Error - no random function available !\n"));
611         exit(1);
612 #endif
613 }
614
615 /**************************************************************************
616  Wrapper for srandom().
617 ****************************************************************************/
618
619 void sys_srandom(unsigned int seed)
620 {
621 #if defined(HAVE_SRANDOM)
622         srandom(seed);
623 #elif defined(HAVE_SRAND)
624         srand(seed);
625 #else
626         DEBUG(0,("Error - no srandom function available !\n"));
627         exit(1);
628 #endif
629 }
630
631 /**************************************************************************
632  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
633 ****************************************************************************/
634
635 int groups_max(void)
636 {
637 #if defined(SYSCONF_SC_NGROUPS_MAX)
638         int ret = sysconf(_SC_NGROUPS_MAX);
639         return (ret == -1) ? NGROUPS_MAX : ret;
640 #else
641         return NGROUPS_MAX;
642 #endif
643 }
644
645 /**************************************************************************
646  Wrapper for getgroups. Deals with broken (int) case.
647 ****************************************************************************/
648
649 int sys_getgroups(int setlen, gid_t *gidset)
650 {
651 #if !defined(HAVE_BROKEN_GETGROUPS)
652         return getgroups(setlen, gidset);
653 #else
654
655         GID_T gid;
656         GID_T *group_list;
657         int i, ngroups;
658
659         if(setlen == 0) {
660                 return getgroups(setlen, &gid);
661         }
662
663         /*
664          * Broken case. We need to allocate a
665          * GID_T array of size setlen.
666          */
667
668         if(setlen < 0) {
669                 errno = EINVAL; 
670                 return -1;
671         } 
672
673         if (setlen == 0)
674                 setlen = groups_max();
675
676         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
677                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
678                 return -1;
679         }
680
681         if((ngroups = getgroups(setlen, group_list)) < 0) {
682                 int saved_errno = errno;
683                 SAFE_FREE(group_list);
684                 errno = saved_errno;
685                 return -1;
686         }
687
688         for(i = 0; i < ngroups; i++)
689                 gidset[i] = (gid_t)group_list[i];
690
691         SAFE_FREE(group_list);
692         return ngroups;
693 #endif /* HAVE_BROKEN_GETGROUPS */
694 }
695
696
697 /**************************************************************************
698  Wrapper for setgroups. Deals with broken (int) case. Automatically used
699  if we have broken getgroups.
700 ****************************************************************************/
701
702 int sys_setgroups(int setlen, gid_t *gidset)
703 {
704 #if !defined(HAVE_SETGROUPS)
705         errno = ENOSYS;
706         return -1;
707 #endif /* HAVE_SETGROUPS */
708
709 #if !defined(HAVE_BROKEN_GETGROUPS)
710         return setgroups(setlen, gidset);
711 #else
712
713         GID_T *group_list;
714         int i ; 
715
716         if (setlen == 0)
717                 return 0 ;
718
719         if (setlen < 0 || setlen > groups_max()) {
720                 errno = EINVAL; 
721                 return -1;   
722         }
723
724         /*
725          * Broken case. We need to allocate a
726          * GID_T array of size setlen.
727          */
728
729         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
730                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
731                 return -1;    
732         }
733  
734         for(i = 0; i < setlen; i++) 
735                 group_list[i] = (GID_T) gidset[i]; 
736
737         if(setgroups(setlen, group_list) != 0) {
738                 int saved_errno = errno;
739                 SAFE_FREE(group_list);
740                 errno = saved_errno;
741                 return -1;
742         }
743  
744         SAFE_FREE(group_list);
745         return 0 ;
746 #endif /* HAVE_BROKEN_GETGROUPS */
747 }
748
749 /**************************************************************************
750  Wrappers for setpwent(), getpwent() and endpwent()
751 ****************************************************************************/
752
753 void sys_setpwent(void)
754 {
755         setpwent();
756 }
757
758 struct passwd *sys_getpwent(void)
759 {
760         return getpwent();
761 }
762
763 void sys_endpwent(void)
764 {
765         endpwent();
766 }
767
768 /**************************************************************************
769  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
770 ****************************************************************************/
771
772 struct passwd *sys_getpwnam(const char *name)
773 {
774         return getpwnam(name);
775 }
776
777 struct passwd *sys_getpwuid(uid_t uid)
778 {
779         return getpwuid(uid);
780 }
781
782 struct group *sys_getgrnam(const char *name)
783 {
784         return getgrnam(name);
785 }
786
787 struct group *sys_getgrgid(gid_t gid)
788 {
789         return getgrgid(gid);
790 }
791
792 #if 0 /* NOT CURRENTLY USED - JRA */
793 /**************************************************************************
794  The following are the UNICODE versions of *all* system interface functions
795  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
796  which currently are left as ascii as they are not used other than in name
797  resolution.
798 ****************************************************************************/
799
800 /**************************************************************************
801  Wide stat. Just narrow and call sys_xxx.
802 ****************************************************************************/
803
804 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
805 {
806         pstring fname;
807         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
808 }
809
810 /**************************************************************************
811  Wide lstat. Just narrow and call sys_xxx.
812 ****************************************************************************/
813
814 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
815 {
816         pstring fname;
817         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
818 }
819
820 /**************************************************************************
821  Wide creat. Just narrow and call sys_xxx.
822 ****************************************************************************/
823
824 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
825 {
826         pstring fname;
827         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
828 }
829
830 /**************************************************************************
831  Wide open. Just narrow and call sys_xxx.
832 ****************************************************************************/
833
834 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
835 {
836         pstring fname;
837         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
838 }
839
840 /**************************************************************************
841  Wide fopen. Just narrow and call sys_xxx.
842 ****************************************************************************/
843
844 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
845 {
846         pstring fname;
847         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
848 }
849
850 /**************************************************************************
851  Wide opendir. Just narrow and call sys_xxx.
852 ****************************************************************************/
853
854 DIR *wsys_opendir(const smb_ucs2_t *wfname)
855 {
856         pstring fname;
857         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
858 }
859
860 /**************************************************************************
861  Wide readdir. Return a structure pointer containing a wide filename.
862 ****************************************************************************/
863
864 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
865 {
866         static SMB_STRUCT_WDIRENT retval;
867         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
868
869         if(!dirval)
870                 return NULL;
871
872         /*
873          * The only POSIX defined member of this struct is d_name.
874          */
875
876         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
877
878         return &retval;
879 }
880
881 /**************************************************************************
882  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
883 ****************************************************************************/
884
885 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
886 {
887         pstring fname;
888         char *p = sys_getwd(fname);
889
890         if(!p)
891                 return NULL;
892
893         return unix_to_unicode(s, p, sizeof(wpstring));
894 }
895
896 /**************************************************************************
897  Wide chown. Just narrow and call sys_xxx.
898 ****************************************************************************/
899
900 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
901 {
902         pstring fname;
903         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
904 }
905
906 /**************************************************************************
907  Wide chroot. Just narrow and call sys_xxx.
908 ****************************************************************************/
909
910 int wsys_chroot(const smb_ucs2_t *wfname)
911 {
912         pstring fname;
913         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
914 }
915
916 /**************************************************************************
917  Wide getpwnam. Return a structure pointer containing wide names.
918 ****************************************************************************/
919
920 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
921 {
922         static SMB_STRUCT_WPASSWD retval;
923         fstring name;
924         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
925
926         if(!pwret)
927                 return NULL;
928
929         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
930         retval.pw_passwd = pwret->pw_passwd;
931         retval.pw_uid = pwret->pw_uid;
932         retval.pw_gid = pwret->pw_gid;
933         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
934         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
935         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
936
937         return &retval;
938 }
939
940 /**************************************************************************
941  Wide getpwuid. Return a structure pointer containing wide names.
942 ****************************************************************************/
943
944 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
945 {
946         static SMB_STRUCT_WPASSWD retval;
947         struct passwd *pwret = sys_getpwuid(uid);
948
949         if(!pwret)
950                 return NULL;
951
952         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
953         retval.pw_passwd = pwret->pw_passwd;
954         retval.pw_uid = pwret->pw_uid;
955         retval.pw_gid = pwret->pw_gid;
956         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
957         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
958         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
959
960         return &retval;
961 }
962 #endif /* NOT CURRENTLY USED - JRA */
963
964 /**************************************************************************
965  Extract a command into an arg list. Uses a static pstring for storage.
966  Caller frees returned arg list (which contains pointers into the static pstring).
967 ****************************************************************************/
968
969 static char **extract_args(const char *command)
970 {
971         static pstring trunc_cmd;
972         char *ptr;
973         int argcl;
974         char **argl = NULL;
975         int i;
976
977         pstrcpy(trunc_cmd, command);
978
979         if(!(ptr = strtok(trunc_cmd, " \t"))) {
980                 errno = EINVAL;
981                 return NULL;
982         }
983
984         /*
985          * Count the args.
986          */
987
988         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
989                 argcl++;
990
991         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
992                 return NULL;
993
994         /*
995          * Now do the extraction.
996          */
997
998         pstrcpy(trunc_cmd, command);
999
1000         ptr = strtok(trunc_cmd, " \t");
1001         i = 0;
1002         argl[i++] = ptr;
1003
1004         while((ptr = strtok(NULL, " \t")) != NULL)
1005                 argl[i++] = ptr;
1006
1007         argl[i++] = NULL;
1008         return argl;
1009 }
1010
1011 /**************************************************************************
1012  Wrapper for fork. Ensures that mypid is reset. Used so we can write
1013  a sys_getpid() that only does a system call *once*.
1014 ****************************************************************************/
1015
1016 static pid_t mypid = (pid_t)-1;
1017
1018 pid_t sys_fork(void)
1019 {
1020         pid_t forkret = fork();
1021
1022         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
1023                 mypid = (pid_t) -1;
1024
1025         return forkret;
1026 }
1027
1028 /**************************************************************************
1029  Wrapper for getpid. Ensures we only do a system call *once*.
1030 ****************************************************************************/
1031
1032 pid_t sys_getpid(void)
1033 {
1034         if (mypid == (pid_t)-1)
1035                 mypid = getpid();
1036
1037         return mypid;
1038 }
1039
1040 /**************************************************************************
1041  Wrapper for popen. Safer as it doesn't search a path.
1042  Modified from the glibc sources.
1043  modified by tridge to return a file descriptor. We must kick our FILE* habit
1044 ****************************************************************************/
1045
1046 typedef struct _popen_list
1047 {
1048         int fd;
1049         pid_t child_pid;
1050         struct _popen_list *next;
1051 } popen_list;
1052
1053 static popen_list *popen_chain;
1054
1055 int sys_popen(const char *command)
1056 {
1057         int parent_end, child_end;
1058         int pipe_fds[2];
1059         popen_list *entry = NULL;
1060         char **argl = NULL;
1061
1062         if (pipe(pipe_fds) < 0)
1063                 return -1;
1064
1065         parent_end = pipe_fds[0];
1066         child_end = pipe_fds[1];
1067
1068         if (!*command) {
1069                 errno = EINVAL;
1070                 goto err_exit;
1071         }
1072
1073         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
1074                 goto err_exit;
1075
1076         ZERO_STRUCTP(entry);
1077
1078         /*
1079          * Extract the command and args into a NULL terminated array.
1080          */
1081
1082         if(!(argl = extract_args(command)))
1083                 goto err_exit;
1084
1085         entry->child_pid = sys_fork();
1086
1087         if (entry->child_pid == -1) {
1088                 goto err_exit;
1089         }
1090
1091         if (entry->child_pid == 0) {
1092
1093                 /*
1094                  * Child !
1095                  */
1096
1097                 int child_std_end = STDOUT_FILENO;
1098                 popen_list *p;
1099
1100                 close(parent_end);
1101                 if (child_end != child_std_end) {
1102                         dup2 (child_end, child_std_end);
1103                         close (child_end);
1104                 }
1105
1106                 /*
1107                  * POSIX.2:  "popen() shall ensure that any streams from previous
1108                  * popen() calls that remain open in the parent process are closed
1109                  * in the new child process."
1110                  */
1111
1112                 for (p = popen_chain; p; p = p->next)
1113                         close(p->fd);
1114
1115                 execv(argl[0], argl);
1116                 _exit (127);
1117         }
1118
1119         /*
1120          * Parent.
1121          */
1122
1123         close (child_end);
1124         SAFE_FREE(argl);
1125
1126         /* Link into popen_chain. */
1127         entry->next = popen_chain;
1128         popen_chain = entry;
1129         entry->fd = parent_end;
1130
1131         return entry->fd;
1132
1133 err_exit:
1134
1135         SAFE_FREE(entry);
1136         SAFE_FREE(argl);
1137         close(pipe_fds[0]);
1138         close(pipe_fds[1]);
1139         return -1;
1140 }
1141
1142 /**************************************************************************
1143  Wrapper for pclose. Modified from the glibc sources.
1144 ****************************************************************************/
1145
1146 int sys_pclose(int fd)
1147 {
1148         int wstatus;
1149         popen_list **ptr = &popen_chain;
1150         popen_list *entry = NULL;
1151         pid_t wait_pid;
1152         int status = -1;
1153
1154         /* Unlink from popen_chain. */
1155         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1156                 if ((*ptr)->fd == fd) {
1157                         entry = *ptr;
1158                         *ptr = (*ptr)->next;
1159                         status = 0;
1160                         break;
1161                 }
1162         }
1163
1164         if (status < 0 || close(entry->fd) < 0)
1165                 return -1;
1166
1167         /*
1168          * As Samba is catching and eating child process
1169          * exits we don't really care about the child exit
1170          * code, a -1 with errno = ECHILD will do fine for us.
1171          */
1172
1173         do {
1174                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1175         } while (wait_pid == -1 && errno == EINTR);
1176
1177         SAFE_FREE(entry);
1178
1179         if (wait_pid == -1)
1180                 return -1;
1181         return wstatus;
1182 }
1183
1184 /**************************************************************************
1185  Wrappers for dlopen, dlsym, dlclose.
1186 ****************************************************************************/
1187
1188 void *sys_dlopen(const char *name, int flags)
1189 {
1190 #if defined(HAVE_DLOPEN)
1191         return dlopen(name, flags);
1192 #else
1193         return NULL;
1194 #endif
1195 }
1196
1197 void *sys_dlsym(void *handle, const char *symbol)
1198 {
1199 #if defined(HAVE_DLSYM)
1200     return dlsym(handle, symbol);
1201 #else
1202     return NULL;
1203 #endif
1204 }
1205
1206 int sys_dlclose (void *handle)
1207 {
1208 #if defined(HAVE_DLCLOSE)
1209         return dlclose(handle);
1210 #else
1211         return 0;
1212 #endif
1213 }
1214
1215 const char *sys_dlerror(void)
1216 {
1217 #if defined(HAVE_DLERROR)
1218         return dlerror();
1219 #else
1220         return NULL;
1221 #endif
1222 }
1223
1224 int sys_dup2(int oldfd, int newfd) 
1225 {
1226 #if defined(HAVE_DUP2)
1227         return dup2(oldfd, newfd);
1228 #else
1229         errno = ENOSYS;
1230         return -1;
1231 #endif
1232 }
1233
1234 /**************************************************************************
1235  Wrapper for Admin Logs.
1236 ****************************************************************************/
1237
1238  void sys_adminlog(int priority, const char *format_str, ...) 
1239 {
1240         va_list ap;
1241         int ret;
1242         char *msgbuf = NULL;
1243
1244         va_start( ap, format_str );
1245         ret = vasprintf( &msgbuf, format_str, ap );
1246         va_end( ap );
1247
1248         if (ret == -1)
1249                 return;
1250
1251 #if defined(HAVE_SYSLOG)
1252         syslog( priority, "%s", msgbuf );
1253 #else
1254         DEBUG(0,("%s", msgbuf ));
1255 #endif
1256         SAFE_FREE(msgbuf);
1257 }
1258
1259 /**************************************************************************
1260  Wrappers for extented attribute calls. Based on the Linux package with
1261  support for IRIX also. Expand as other systems have them.
1262 ****************************************************************************/
1263
1264 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1265 {
1266 #if defined(HAVE_GETXATTR)
1267         return getxattr(path, name, value, size);
1268 #elif defined(HAVE_ATTR_GET)
1269         int retval, flags = 0;
1270         int valuelength = (int)size;
1271         char *attrname = strchr(name,'.') +1;
1272         
1273         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1274
1275         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1276
1277         return retval ? retval : valuelength;
1278 #else
1279         errno = ENOSYS;
1280         return -1;
1281 #endif
1282 }
1283
1284 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1285 {
1286 #if defined(HAVE_LGETXATTR)
1287         return lgetxattr(path, name, value, size);
1288 #elif defined(HAVE_ATTR_GET)
1289         int retval, flags = ATTR_DONTFOLLOW;
1290         int valuelength = (int)size;
1291         char *attrname = strchr(name,'.') +1;
1292         
1293         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1294
1295         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1296
1297         return retval ? retval : valuelength;
1298 #else
1299         errno = ENOSYS;
1300         return -1;
1301 #endif
1302 }
1303
1304 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1305 {
1306 #if defined(HAVE_FGETXATTR)
1307         return fgetxattr(filedes, name, value, size);
1308 #elif defined(HAVE_ATTR_GETF)
1309         int retval, flags = 0;
1310         int valuelength = (int)size;
1311         char *attrname = strchr(name,'.') +1;
1312         
1313         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1314
1315         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1316
1317         return retval ? retval : valuelength;
1318 #else
1319         errno = ENOSYS;
1320         return -1;
1321 #endif
1322 }
1323
1324 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1325 static char attr_buffer[ATTR_MAX_VALUELEN];
1326
1327 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1328 {
1329         int retval = 0, index;
1330         attrlist_cursor_t *cursor = 0;
1331         int total_size = 0;
1332         attrlist_t * al = (attrlist_t *)attr_buffer;
1333         attrlist_ent_t *ae;
1334         size_t ent_size, left = size;
1335         char *bp = list;
1336
1337         while (True) {
1338             if (filedes)
1339                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1340             else
1341                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1342             if (retval) break;
1343             for (index = 0; index < al->al_count; index++) {
1344                 ae = ATTR_ENTRY(attr_buffer, index);
1345                 ent_size = strlen(ae->a_name) + sizeof("user.");
1346                 if (left >= ent_size) {
1347                     strncpy(bp, "user.", sizeof("user."));
1348                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1349                     bp += ent_size;
1350                     left -= ent_size;
1351                 } else if (size) {
1352                     errno = ERANGE;
1353                     retval = -1;
1354                     break;
1355                 }
1356                 total_size += ent_size;
1357             }
1358             if (al->al_more == 0) break;
1359         }
1360         if (retval == 0) {
1361             flags |= ATTR_ROOT;
1362             cursor = 0;
1363             while (True) {
1364                 if (filedes)
1365                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1366                 else
1367                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1368                 if (retval) break;
1369                 for (index = 0; index < al->al_count; index++) {
1370                     ae = ATTR_ENTRY(attr_buffer, index);
1371                     ent_size = strlen(ae->a_name) + sizeof("system.");
1372                     if (left >= ent_size) {
1373                         strncpy(bp, "system.", sizeof("system."));
1374                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1375                         bp += ent_size;
1376                         left -= ent_size;
1377                     } else if (size) {
1378                         errno = ERANGE;
1379                         retval = -1;
1380                         break;
1381                     }
1382                     total_size += ent_size;
1383                 }
1384                 if (al->al_more == 0) break;
1385             }
1386         }
1387         return (ssize_t)(retval ? retval : total_size);
1388 }
1389
1390 #endif
1391
1392 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1393 {
1394 #if defined(HAVE_LISTXATTR)
1395         return listxattr(path, list, size);
1396 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1397         return irix_attr_list(path, 0, list, size, 0);
1398 #else
1399         errno = ENOSYS;
1400         return -1;
1401 #endif
1402 }
1403
1404 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1405 {
1406 #if defined(HAVE_LLISTXATTR)
1407         return llistxattr(path, list, size);
1408 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1409         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1410 #else
1411         errno = ENOSYS;
1412         return -1;
1413 #endif
1414 }
1415
1416 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1417 {
1418 #if defined(HAVE_FLISTXATTR)
1419         return flistxattr(filedes, list, size);
1420 #elif defined(HAVE_ATTR_LISTF)
1421         return irix_attr_list(NULL, filedes, list, size, 0);
1422 #else
1423         errno = ENOSYS;
1424         return -1;
1425 #endif
1426 }
1427
1428 int sys_removexattr (const char *path, const char *name)
1429 {
1430 #if defined(HAVE_REMOVEXATTR)
1431         return removexattr(path, name);
1432 #elif defined(HAVE_ATTR_REMOVE)
1433         int flags = 0;
1434         char *attrname = strchr(name,'.') +1;
1435         
1436         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1437
1438         return attr_remove(path, attrname, flags);
1439 #else
1440         errno = ENOSYS;
1441         return -1;
1442 #endif
1443 }
1444
1445 int sys_lremovexattr (const char *path, const char *name)
1446 {
1447 #if defined(HAVE_LREMOVEXATTR)
1448         return lremovexattr(path, name);
1449 #elif defined(HAVE_ATTR_REMOVE)
1450         int flags = ATTR_DONTFOLLOW;
1451         char *attrname = strchr(name,'.') +1;
1452         
1453         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1454
1455         return attr_remove(path, attrname, flags);
1456 #else
1457         errno = ENOSYS;
1458         return -1;
1459 #endif
1460 }
1461
1462 int sys_fremovexattr (int filedes, const char *name)
1463 {
1464 #if defined(HAVE_FREMOVEXATTR)
1465         return fremovexattr(filedes, name);
1466 #elif defined(HAVE_ATTR_REMOVEF)
1467         int flags = 0;
1468         char *attrname = strchr(name,'.') +1;
1469         
1470         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1471
1472         return attr_removef(filedes, attrname, flags);
1473 #else
1474         errno = ENOSYS;
1475         return -1;
1476 #endif
1477 }
1478
1479 #if !defined(HAVE_SETXATTR)
1480 #define XATTR_CREATE  0x1       /* set value, fail if attr already exists */
1481 #define XATTR_REPLACE 0x2       /* set value, fail if attr does not exist */
1482 #endif
1483
1484 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1485 {
1486 #if defined(HAVE_SETXATTR)
1487         return setxattr(path, name, value, size, flags);
1488 #elif defined(HAVE_ATTR_SET)
1489         int myflags = 0;
1490         char *attrname = strchr(name,'.') +1;
1491         
1492         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1493         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1494         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1495
1496         return attr_set(path, attrname, (const char *)value, size, myflags);
1497 #else
1498         errno = ENOSYS;
1499         return -1;
1500 #endif
1501 }
1502
1503 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1504 {
1505 #if defined(HAVE_LSETXATTR)
1506         return lsetxattr(path, name, value, size, flags);
1507 #elif defined(HAVE_ATTR_SET)
1508         int myflags = ATTR_DONTFOLLOW;
1509         char *attrname = strchr(name,'.') +1;
1510         
1511         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1512         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1513         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1514
1515         return attr_set(path, attrname, (const char *)value, size, myflags);
1516 #else
1517         errno = ENOSYS;
1518         return -1;
1519 #endif
1520 }
1521
1522 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
1523 {
1524 #if defined(HAVE_FSETXATTR)
1525         return fsetxattr(filedes, name, value, size, flags);
1526 #elif defined(HAVE_ATTR_SETF)
1527         int myflags = 0;
1528         char *attrname = strchr(name,'.') +1;
1529         
1530         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1531         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1532         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1533
1534         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
1535 #else
1536         errno = ENOSYS;
1537         return -1;
1538 #endif
1539 }