d2463efe61ef8e1385ccc3942ba6236ca212be60
[kopensolaris-gnu/glibc.git] / sysdeps / mach / hurd / mknod.c
1 /* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <errno.h>
21 #include <sys/stat.h>
22 #include <hurd.h>
23 #include <hurd/paths.h>
24 #include <fcntl.h>
25 #include "stdio/_itoa.h"
26
27 /* Temporary hack; this belongs in a header file, probably types.h. */
28 #define major(x) ((int)(((unsigned) (x) >> 8) & 0xff))
29 #define minor(x) ((int)((x) & 0xff))
30
31
32 /* Create a device file named PATH, with permission and special bits MODE
33    and device number DEV (which can be constructed from major and minor
34    device numbers with the `makedev' macro above).  */
35 int
36 DEFUN(__mknod, (path, mode, dev),
37       CONST char *path AND mode_t mode AND dev_t dev)
38 {
39   error_t err;
40   file_t dir, node;
41   char *name;
42   char buf[100], *bp;
43   const char *translator;
44   size_t len;
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
62     {
63       errno = EINVAL;
64       return -1;
65     }
66   
67   if (! S_ISFIFO (mode))
68     {
69       /* We set the translator to "ifmt\0major\0minor\0", where IFMT
70          depends on the S_IFMT bits of our MODE argument, and MAJOR and
71          MINOR are ASCII decimal (octal or hex would do as well)
72          representations of our arguments.  Thus the convention is that
73          CHRDEV and BLKDEV translators are invoked with two non-switch
74          arguments, giving the major and minor device numbers in %i format. */
75
76       bp = buf + sizeof (buf);
77       *--bp = '\0';
78       bp = _itoa (minor (dev), bp, 10, 0);
79       *--bp = '\0';
80       bp = _itoa (major (dev), bp, 10, 0);
81       *--bp = '\0';
82       memcpy (bp - len, translator, len);
83       translator = buf;
84       len += buf + sizeof (buf) - bp;
85     }
86   
87   dir = __path_split (path, &name);
88   if (dir == MACH_PORT_NULL)
89     return -1;
90
91   /* Create a new, unlinked node in the target directory.  */
92   err = __dir_mkfile (dir, O_WRITE, mode & ~S_IFMT & _hurd_umask, &node);
93
94   if (! err)
95     /* Set the node's translator to make it a device.  */
96     err = __file_set_translator (node, 
97                                  FS_TRANS_EXCL | FS_TRANS_SET,
98                                  FS_TRANS_EXCL | FS_TRANS_SET, 0,
99                                  translator, len,
100                                  MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
101
102   if (! err)
103     /* Link the node, now a valid device, into the target directory.  */
104     err = __dir_link (node, dir, name);
105
106   __mach_port_deallocate (__mach_task_self (), dir);
107   __mach_port_deallocate (__mach_task_self (), node);
108
109   if (err)
110     return __hurd_fail (err);
111   return 0;
112 }