Update copyright notices with scripts/update-copyrights.
[jlayton/glibc.git] / sysdeps / mach / hurd / xmknodat.c
1 /* Create a device file relative to an open directory.  Hurd version.
2    Copyright (C) 1991-2013 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <hurd.h>
22 #include <hurd/fd.h>
23 #include <hurd/paths.h>
24 #include <fcntl.h>
25 #include <_itoa.h>
26 #include <string.h>
27 #include <sys/types.h>
28
29 /* Create a device file named PATH relative to FD, with permission and
30    special bits MODE and device number DEV (which can be constructed
31    from major and minor device numbers with the `makedev' macro
32    above).  */
33 int
34 __xmknodat (int vers, int fd, const char *path, mode_t mode, dev_t *dev)
35 {
36   error_t errnode, err;
37   file_t dir, node;
38   char *name;
39   char buf[100], *bp;
40   const char *translator;
41   size_t len;
42
43   if (vers != _MKNOD_VER)
44     return __hurd_fail (EINVAL);
45
46   if (S_ISCHR (mode))
47     {
48       translator = _HURD_CHRDEV;
49       len = sizeof (_HURD_CHRDEV);
50     }
51   else if (S_ISBLK (mode))
52     {
53       translator = _HURD_BLKDEV;
54       len = sizeof (_HURD_BLKDEV);
55     }
56   else if (S_ISFIFO (mode))
57     {
58       translator = _HURD_FIFO;
59       len = sizeof (_HURD_FIFO);
60     }
61   else if (S_ISREG (mode))
62     {
63       translator = NULL;
64       len = 0;
65     }
66   else
67     {
68       errno = EINVAL;
69       return -1;
70     }
71
72   if (translator != NULL && ! S_ISFIFO (mode))
73     {
74       /* We set the translator to "ifmt\0major\0minor\0", where IFMT
75          depends on the S_IFMT bits of our MODE argument, and MAJOR and
76          MINOR are ASCII decimal (octal or hex would do as well)
77          representations of our arguments.  Thus the convention is that
78          CHRDEV and BLKDEV translators are invoked with two non-switch
79          arguments, giving the major and minor device numbers in %i format. */
80
81       bp = buf + sizeof (buf);
82       *--bp = '\0';
83       bp = _itoa (minor (*dev), bp, 10, 0);
84       *--bp = '\0';
85       bp = _itoa (major (*dev), bp, 10, 0);
86       memcpy (bp - len, translator, len);
87       translator = bp - len;
88       len = buf + sizeof (buf) - translator;
89     }
90
91   dir = __file_name_split_at (fd, path, &name);
92   if (dir == MACH_PORT_NULL)
93     return -1;
94
95   /* Create a new, unlinked node in the target directory.  */
96   errnode = err = __dir_mkfile (dir, O_WRITE, (mode & ~S_IFMT) & ~_hurd_umask, &node);
97
98   if (! err && translator != NULL)
99     /* Set the node's translator to make it a device.  */
100     err = __file_set_translator (node,
101                                  FS_TRANS_EXCL | FS_TRANS_SET,
102                                  FS_TRANS_EXCL | FS_TRANS_SET, 0,
103                                  translator, len,
104                                  MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
105
106   if (! err)
107     /* Link the node, now a valid device, into the target directory.  */
108     err = __dir_link (dir, node, name, 1);
109
110   __mach_port_deallocate (__mach_task_self (), dir);
111   if (! errnode)
112     __mach_port_deallocate (__mach_task_self (), node);
113
114   if (err)
115     return __hurd_fail (err);
116   return 0;
117 }