chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / mach / hurd / fcntl.c
1 /* Copyright (C) 1992-1997,1999,2000,2002,2007 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 Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the 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    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <hurd.h>
22 #include <hurd/fd.h>
23 #include <stdarg.h>
24 #include <sys/file.h>           /* XXX for LOCK_* */
25
26 /* Perform file control operations on FD.  */
27 int
28 __libc_fcntl (int fd, int cmd, ...)
29 {
30   va_list ap;
31   struct hurd_fd *d;
32   int result;
33
34   d = _hurd_fd_get (fd);
35
36   if (d == NULL)
37     return __hurd_fail (EBADF);
38
39   va_start (ap, cmd);
40
41   switch (cmd)
42     {
43       error_t err;
44
45     default:                    /* Bad command.  */
46       errno = EINVAL;
47       result = -1;
48       break;
49
50       /* First the descriptor-based commands, which do no RPCs.  */
51
52     case F_DUPFD:               /* Duplicate the file descriptor.  */
53     case F_DUPFD_CLOEXEC:
54       {
55         struct hurd_fd *new;
56         io_t port, ctty;
57         struct hurd_userlink ulink, ctty_ulink;
58         int flags;
59
60         HURD_CRITICAL_BEGIN;
61
62         /* Extract the ports and flags from the file descriptor.  */
63         __spin_lock (&d->port.lock);
64         flags = d->flags;
65         ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
66         port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D.  */
67
68         if (cmd == F_DUPFD_CLOEXEC)
69           flags |= FD_CLOEXEC;
70         else
71           /* Duplication clears the FD_CLOEXEC flag.  */
72           flags &= ~FD_CLOEXEC;
73
74         /* Get a new file descriptor.  The third argument to __fcntl is the
75            minimum file descriptor number for it.  */
76         new = _hurd_alloc_fd (&result, va_arg (ap, int));
77         if (new == NULL)
78           /* _hurd_alloc_fd has set errno.  */
79           result = -1;
80         else
81           {
82             /* Give the ports each a user ref for the new descriptor.  */
83             __mach_port_mod_refs (__mach_task_self (), port,
84                                   MACH_PORT_RIGHT_SEND, 1);
85             if (ctty != MACH_PORT_NULL)
86               __mach_port_mod_refs (__mach_task_self (), ctty,
87                                     MACH_PORT_RIGHT_SEND, 1);
88
89             /* Install the ports and flags in the new descriptor.  */
90             if (ctty != MACH_PORT_NULL)
91               _hurd_port_set (&new->ctty, ctty);
92             new->flags = flags;
93             _hurd_port_locked_set (&new->port, port); /* Unlocks NEW.  */
94           }
95
96         HURD_CRITICAL_END;
97
98         _hurd_port_free (&d->port, &ulink, port);
99         if (ctty != MACH_PORT_NULL)
100           _hurd_port_free (&d->ctty, &ctty_ulink, port);
101
102         break;
103       }
104
105       /* Set RESULT by evaluating EXPR with the descriptor locked.
106          Check for an empty descriptor and return EBADF.  */
107 #define LOCKED(expr)                                                          \
108       HURD_CRITICAL_BEGIN;                                                    \
109       __spin_lock (&d->port.lock);                                            \
110       if (d->port.port == MACH_PORT_NULL)                                     \
111         result = __hurd_fail (EBADF);                                         \
112       else                                                                    \
113         result = (expr);                                                      \
114       __spin_unlock (&d->port.lock);                                          \
115       HURD_CRITICAL_END;
116
117     case F_GETFD:               /* Get descriptor flags.  */
118       LOCKED (d->flags);
119       break;
120
121     case F_SETFD:               /* Set descriptor flags.  */
122       LOCKED ((d->flags = va_arg (ap, int), 0));
123       break;
124
125
126       /* Now the real io operations, done by RPCs to io servers.  */
127
128     case F_GETLK:
129     case F_SETLK:
130     case F_SETLKW:
131       {
132         /* XXX
133            We need new RPCs to support POSIX.1 fcntl file locking!!
134            For the time being we support the whole-file case only,
135            with all kinds of WRONG WRONG WRONG semantics,
136            by using flock.  This is definitely the Wrong Thing,
137            but it might be better than nothing (?).  */
138         struct flock *fl = va_arg (ap, struct flock *);
139         va_end (ap);
140         switch (cmd)
141           {
142           case F_GETLK:
143             errno = ENOSYS;
144             return -1;
145           case F_SETLK:
146             cmd = LOCK_NB;
147             break;
148           default:
149             cmd = 0;
150             break;
151           }
152         switch (fl->l_type)
153           {
154           case F_RDLCK: cmd |= LOCK_SH; break;
155           case F_WRLCK: cmd |= LOCK_EX; break;
156           case F_UNLCK: cmd |= LOCK_UN; break;
157           default:
158             errno = EINVAL;
159             return -1;
160           }
161         switch (fl->l_whence)
162           {
163           case SEEK_SET:
164             if (fl->l_start == 0 && fl->l_len == 0) /* Whole file request.  */
165               break;
166             /* It seems to be common for applications to lock the first
167                byte of the file when they are really doing whole-file locking.
168                So, since it's so wrong already, might as well do that too.  */
169             if (fl->l_start == 0 && fl->l_len == 1)
170               break;
171             /* FALLTHROUGH */
172           case SEEK_CUR:
173           case SEEK_END:
174             errno = ENOTSUP;
175             return -1;
176           default:
177             errno = EINVAL;
178             return -1;
179           }
180
181         return __flock (fd, cmd);
182       }
183
184     case F_GETFL:               /* Get per-open flags.  */
185       if (err = HURD_FD_PORT_USE (d, __io_get_openmodes (port, &result)))
186         result = __hurd_dfail (fd, err);
187       break;
188
189     case F_SETFL:               /* Set per-open flags.  */
190       err = HURD_FD_PORT_USE (d, __io_set_all_openmodes (port,
191                                                          va_arg (ap, int)));
192       result = err ? __hurd_dfail (fd, err) : 0;
193       break;
194
195     case F_GETOWN:              /* Get owner.  */
196       if (err = HURD_FD_PORT_USE (d, __io_get_owner (port, &result)))
197         result = __hurd_dfail (fd, err);
198       break;
199
200     case F_SETOWN:              /* Set owner.  */
201       err = HURD_FD_PORT_USE (d, __io_mod_owner (port, va_arg (ap, pid_t)));
202       result = err ? __hurd_dfail (fd, err) : 0;
203       break;
204     }
205
206   va_end (ap);
207
208   return result;
209 }
210 libc_hidden_def (__libc_fcntl)
211 weak_alias (__libc_fcntl, __fcntl)
212 libc_hidden_weak (__fcntl)
213 weak_alias (__libc_fcntl, fcntl)