Back to index

glibc  2.9
xmknodat.c
Go to the documentation of this file.
00001 /* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <fcntl.h>
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <sys/sysmacros.h>
00026 
00027 #include <sysdep.h>
00028 #include <kernel-features.h>
00029 #include <sys/syscall.h>
00030 #include <bp-checks.h>
00031 
00032 
00033 /* Create a device file named PATH relative to FD, with permission and
00034    special bits MODE and device number DEV (which can be constructed
00035    from major and minor device numbers with the `makedev' macro above).  */
00036 int
00037 __xmknodat (int vers, int fd, const char *file, mode_t mode, dev_t *dev)
00038 {
00039   if (vers != _MKNOD_VER)
00040     {
00041       __set_errno (EINVAL);
00042       return -1;
00043     }
00044 
00045   /* We must convert the value to dev_t type used by the kernel.  */
00046   unsigned long long int k_dev =  (*dev) & ((1ULL << 32) - 1);
00047   if (k_dev != *dev)
00048     {
00049       __set_errno (EINVAL);
00050       return -1;
00051     }
00052 
00053 #ifdef __NR_mknodat
00054 # ifndef __ASSUME_ATFCTS
00055   if (__have_atfcts >= 0)
00056 # endif
00057     {
00058       int res = INLINE_SYSCALL (mknodat, 4, fd, file, mode,
00059                             (unsigned int) k_dev);
00060 # ifndef __ASSUME_ATFCTS
00061       if (res == -1 && errno == ENOSYS)
00062        __have_atfcts = -1;
00063       else
00064 # endif
00065        return res;
00066     }
00067 #endif
00068 
00069 #ifndef __ASSUME_ATFCTS
00070   char *buf = NULL;
00071 
00072   if (fd != AT_FDCWD && file[0] != '/')
00073     {
00074       size_t filelen = strlen (file);
00075       static const char procfd[] = "/proc/self/fd/%d/%s";
00076       /* Buffer for the path name we are going to use.  It consists of
00077         - the string /proc/self/fd/
00078         - the file descriptor number
00079         - the file name provided.
00080         The final NUL is included in the sizeof.   A bit of overhead
00081         due to the format elements compensates for possible negative
00082         numbers.  */
00083       size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
00084       buf = alloca (buflen);
00085 
00086       __snprintf (buf, buflen, procfd, fd, file);
00087       file = buf;
00088     }
00089 
00090   return INLINE_SYSCALL (mknod, 3, CHECK_STRING (file), mode,
00091                       (unsigned int) k_dev);
00092 #endif
00093 }
00094 
00095 libc_hidden_def (__xmknodat)