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