1 /*
2 * fcntl.c - fcntl interface
3 *
4 * Copyright (c) 2000-2020 Shiro Kawai <shiro@acm.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the authors nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #define _GNU_SOURCE /* for Linux, this enables additional features */
35
36 #include <gauche.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <gauche/class.h>
40 #include <gauche/extend.h>
41
42 #include "gauche/fcntl.h"
43
44 /* struct flock */
45
46 static ScmObj flock_allocate(ScmClass *klass, ScmObj initargs);
47
48 SCM_DEFINE_BUILTIN_CLASS(Scm_SysFlockClass,
49 NULL, NULL, NULL,
50 flock_allocate,
51 NULL);
52
flock_allocate(ScmClass * klass SCM_UNUSED,ScmObj initargs SCM_UNUSED)53 static ScmObj flock_allocate(ScmClass *klass SCM_UNUSED,
54 ScmObj initargs SCM_UNUSED)
55 {
56 ScmSysFlock *f = SCM_NEW(ScmSysFlock);
57 SCM_SET_CLASS(f, SCM_CLASS_SYS_FLOCK);
58 memset(&f->lock, 0, sizeof(f->lock));
59 return SCM_OBJ(f);
60 }
61
62 #define FLOCK_GET_N_SET(name, type, make, get) \
63 static ScmObj SCM_CPP_CAT3(flock_, name, _get)(ScmSysFlock* t) \
64 { return make(t->lock.name); } \
65 static void SCM_CPP_CAT3(flock_, name, _set)(ScmSysFlock* t, ScmObj v) \
66 { \
67 if (!SCM_INTEGERP(v)) Scm_Error("integer required, but got %S", v); \
68 t->lock.name = (type)get(v); \
69 }
70
71 FLOCK_GET_N_SET(l_type, short, Scm_MakeInteger, Scm_GetInteger)
72 FLOCK_GET_N_SET(l_whence, short, Scm_MakeInteger, Scm_GetInteger)
73 FLOCK_GET_N_SET(l_start, off_t, Scm_OffsetToInteger, Scm_IntegerToOffset)
74 FLOCK_GET_N_SET(l_len, off_t, Scm_OffsetToInteger, Scm_IntegerToOffset)
75 FLOCK_GET_N_SET(l_pid, pid_t, Scm_MakeInteger, Scm_GetInteger)
76
77 static ScmClassStaticSlotSpec flock_slots[] = {
78 SCM_CLASS_SLOT_SPEC("type", flock_l_type_get, flock_l_type_set),
79 SCM_CLASS_SLOT_SPEC("whence", flock_l_whence_get, flock_l_whence_set),
80 SCM_CLASS_SLOT_SPEC("start", flock_l_start_get, flock_l_start_set),
81 SCM_CLASS_SLOT_SPEC("len", flock_l_len_get, flock_l_len_set),
82 SCM_CLASS_SLOT_SPEC("pid", flock_l_pid_get, flock_l_pid_set),
83 SCM_CLASS_SLOT_SPEC_END()
84 };
85
Scm_MakeSysFlock(void)86 ScmObj Scm_MakeSysFlock(void)
87 {
88 return flock_allocate(SCM_CLASS_SYS_FLOCK, SCM_NIL);
89 }
90
91 /*
92 * Fcntl bridge
93 */
94 #if defined(HAVE_FCNTL)
flag_name(int flag)95 static const char *flag_name(int flag)
96 {
97 #define FLAG_NAME(n) case n: return #n
98 switch (flag) {
99 FLAG_NAME(F_GETFD);
100 FLAG_NAME(F_SETFD);
101 FLAG_NAME(F_GETFL);
102 FLAG_NAME(F_SETFL);
103 FLAG_NAME(F_DUPFD);
104 FLAG_NAME(F_GETLK);
105 FLAG_NAME(F_SETLK);
106 FLAG_NAME(F_SETLKW);
107 #if defined(F_GETOWN)
108 FLAG_NAME(F_GETOWN);
109 #endif
110 #if defined(F_SETOWN)
111 FLAG_NAME(F_SETOWN);
112 #endif
113 #if defined(F_GETSIG)
114 FLAG_NAME(F_GETSIG);
115 #endif
116 #if defined(F_SETSIG)
117 FLAG_NAME(F_SETSIG);
118 #endif
119 #if defined(F_GETLEASE)
120 FLAG_NAME(F_GETLEASE);
121 #endif
122 #if defined(F_SETLEASE)
123 FLAG_NAME(F_SETLEASE);
124 #endif
125 #if defined(F_NOTIFY)
126 FLAG_NAME(F_NOTIFY);
127 #endif
128 }
129 return "(unknown flag)";
130 #undef FLAG_NAME
131 }
132 #endif /* HAVE_FCNTL */
133
Scm_SysFcntl(ScmObj port_or_fd,int op,ScmObj arg)134 ScmObj Scm_SysFcntl(ScmObj port_or_fd, int op, ScmObj arg)
135 {
136 #if defined(HAVE_FCNTL)
137 int fd = Scm_GetPortFd(port_or_fd, TRUE), r;
138
139 switch (op) {
140 case F_GETFD:; case F_GETFL:;
141 #if defined(F_GETOWN) /* BSD and Linux specific */
142 case F_GETOWN:;
143 #endif /*F_GETOWN*/
144 #if defined(F_GETSIG) /* Linux specific */
145 case F_GETSIG:;
146 #endif /*F_GETSIG */
147 #if defined(F_GETLEASE) /* Linux specific */
148 case F_GETLEASE:;
149 #endif /*F_GETLEASE */
150 SCM_SYSCALL(r, fcntl(fd, op));
151 if (r == -1) { /*NB: F_GETOWN may return a negative value on success*/
152 Scm_SysError("fcntl(%s) failed", flag_name(op));
153 }
154 return Scm_MakeInteger(r);
155 case F_SETFD:; case F_SETFL:; case F_DUPFD:;
156 #if defined(F_SETOWN) /* BSD and Linux specific */
157 case F_SETOWN:;
158 #endif /*F_SETOWN*/
159 #if defined(F_SETSIG) /* Linux specific */
160 case F_SETSIG:;
161 #endif /*F_SETSIG */
162 #if defined(F_SETLEASE) /* Linux specific */
163 case F_SETLEASE:;
164 #endif /*F_SETLEASE */
165 #if defined(F_NOTIFY) /* Linux specific */
166 case F_NOTIFY:;
167 #endif /*F_NOTIFY */
168 if (!SCM_EXACTP(arg)) {
169 Scm_Error("exact integer required for fcntl(%s), but got %S",
170 flag_name(op), arg);
171 }
172 SCM_SYSCALL(r, fcntl(fd, op, Scm_GetInteger(arg)));
173 if (r < 0) {
174 Scm_SysError("fcntl(%s) failed", flag_name(op));
175 }
176 return Scm_MakeInteger(r);
177 case F_GETLK:; case F_SETLK:; case F_SETLKW:;
178 if (!SCM_SYS_FLOCK_P(arg)) {
179 Scm_Error("flock object required for fcntl(%s), but got %S",
180 flag_name(op), arg);
181 }
182 ScmSysFlock *fl = SCM_SYS_FLOCK(arg);
183 SCM_SYSCALL(r, fcntl(fd, op, &fl->lock));
184 if (op == F_SETLK) {
185 if (r >= 0) return SCM_TRUE;
186 if (errno == EAGAIN) return SCM_FALSE;
187 }
188 if (r < 0) Scm_SysError("fcntl(%s) failed", flag_name(op));
189 return SCM_TRUE;
190 default:
191 Scm_Error("unknown operation code (%d) for fcntl", op);
192 return SCM_UNDEFINED; /* dummy */
193 }
194 #else /*!HAVE_FCNTL*/
195 (void)port_or_fd; /* suppress unused var warning */
196 (void)op; /* suppress unused var warning */
197 (void)arg; /* suppress unused var warning */
198 Scm_Error("fcntl not supported on MinGW port");
199 return SCM_UNDEFINED; /*dummy*/
200 #endif /*!HAVE_FCNTL*/
201 }
202
203 /*
204 * Initialization
205 */
206
Scm_Init_fcntl(void)207 void Scm_Init_fcntl(void)
208 {
209 ScmModule *mod = SCM_FIND_MODULE("gauche.fcntl", SCM_FIND_MODULE_CREATE);
210 Scm_InitStaticClass(&Scm_SysFlockClass, "<sys-flock>",
211 mod, flock_slots, 0);
212 }
213