]>
Commit | Line | Data |
---|---|---|
b168057a | 1 | /* Copyright (C) 1992-2015 Free Software Foundation, Inc. |
ebbad4cc | 2 | This file is part of the GNU C Library. |
28f540f4 | 3 | |
ebbad4cc | 4 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
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. | |
28f540f4 | 8 | |
ebbad4cc UD |
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 | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
28f540f4 | 13 | |
41bdb6e2 | 14 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
15 | License along with the GNU C Library; if not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
28f540f4 | 17 | |
28f540f4 RM |
18 | #include <errno.h> |
19 | #include <fcntl.h> | |
20 | #include <hurd.h> | |
21 | #include <hurd/fd.h> | |
22 | #include <stdarg.h> | |
0702b5f4 | 23 | #include <sys/file.h> /* XXX for LOCK_* */ |
28f540f4 | 24 | |
28f540f4 RM |
25 | /* Perform file control operations on FD. */ |
26 | int | |
c1301d9a | 27 | __libc_fcntl (int fd, int cmd, ...) |
28f540f4 RM |
28 | { |
29 | va_list ap; | |
30 | struct hurd_fd *d; | |
31 | int result; | |
32 | ||
33 | d = _hurd_fd_get (fd); | |
34 | ||
35 | if (d == NULL) | |
36 | return __hurd_fail (EBADF); | |
37 | ||
38 | va_start (ap, cmd); | |
39 | ||
40 | switch (cmd) | |
41 | { | |
42 | error_t err; | |
43 | ||
44 | default: /* Bad command. */ | |
45 | errno = EINVAL; | |
46 | result = -1; | |
47 | break; | |
48 | ||
49 | /* First the descriptor-based commands, which do no RPCs. */ | |
50 | ||
51 | case F_DUPFD: /* Duplicate the file descriptor. */ | |
bd92328d | 52 | case F_DUPFD_CLOEXEC: |
28f540f4 RM |
53 | { |
54 | struct hurd_fd *new; | |
55 | io_t port, ctty; | |
56 | struct hurd_userlink ulink, ctty_ulink; | |
57 | int flags; | |
58 | ||
59 | HURD_CRITICAL_BEGIN; | |
60 | ||
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. */ | |
66 | ||
bd92328d RM |
67 | if (cmd == F_DUPFD_CLOEXEC) |
68 | flags |= FD_CLOEXEC; | |
69 | else | |
70 | /* Duplication clears the FD_CLOEXEC flag. */ | |
71 | flags &= ~FD_CLOEXEC; | |
72 | ||
28f540f4 RM |
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 | |
80 | { | |
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); | |
87 | ||
88 | /* Install the ports and flags in the new descriptor. */ | |
89 | if (ctty != MACH_PORT_NULL) | |
90 | _hurd_port_set (&new->ctty, ctty); | |
bd92328d | 91 | new->flags = flags; |
28f540f4 RM |
92 | _hurd_port_locked_set (&new->port, port); /* Unlocks NEW. */ |
93 | } | |
94 | ||
95 | HURD_CRITICAL_END; | |
96 | ||
97 | _hurd_port_free (&d->port, &ulink, port); | |
98 | if (ctty != MACH_PORT_NULL) | |
99 | _hurd_port_free (&d->ctty, &ctty_ulink, port); | |
100 | ||
101 | break; | |
102 | } | |
103 | ||
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; | |
115 | ||
116 | case F_GETFD: /* Get descriptor flags. */ | |
117 | LOCKED (d->flags); | |
118 | break; | |
119 | ||
120 | case F_SETFD: /* Set descriptor flags. */ | |
121 | LOCKED ((d->flags = va_arg (ap, int), 0)); | |
122 | break; | |
123 | ||
124 | ||
125 | /* Now the real io operations, done by RPCs to io servers. */ | |
126 | ||
127 | case F_GETLK: | |
128 | case F_SETLK: | |
129 | case F_SETLKW: | |
130 | { | |
0702b5f4 RM |
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 (?). */ | |
28f540f4 | 137 | struct flock *fl = va_arg (ap, struct flock *); |
0702b5f4 RM |
138 | va_end (ap); |
139 | switch (cmd) | |
140 | { | |
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; | |
150 | } | |
151 | switch (fl->l_type) | |
152 | { | |
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; | |
159 | } | |
160 | switch (fl->l_whence) | |
161 | { | |
162 | case SEEK_SET: | |
8bbd8b0b RM |
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) | |
0702b5f4 RM |
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; | |
178 | } | |
179 | ||
180 | return __flock (fd, cmd); | |
28f540f4 RM |
181 | } |
182 | ||
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; | |
187 | ||
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; | |
8ec2f309 | 192 | break; |
28f540f4 RM |
193 | |
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; | |
198 | ||
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; | |
203 | } | |
204 | ||
205 | va_end (ap); | |
206 | ||
207 | return result; | |
208 | } | |
37ba7d66 | 209 | libc_hidden_def (__libc_fcntl) |
c1301d9a | 210 | weak_alias (__libc_fcntl, __fcntl) |
37ba7d66 | 211 | libc_hidden_weak (__fcntl) |
c1301d9a | 212 | weak_alias (__libc_fcntl, fcntl) |