bsd-user: Add do_bsd___semctl implementation
Add implementation of __semctl(2) syscall for System V semaphore control operations. Handles command translation, endianness conversion for GETVAL/ SETVAL, and array/structure conversions for GETALL/SETALL/IPC_STAT/IPC_SET. Signed-off-by: Stacey Son <sson@FreeBSD.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Signed-off-by: Warner Losh <imp@bsdimp.com>
Stacey Son committed
Feb 2, 2026 at 16:45 UTC
6cefbee70be2c256d58d534df0556907bd8c4ebd
1 file changed
+114
bsd-user/bsd-misc.h
+114
@@ -99,6 +99,120 @@ static inline abi_long do_bsd_semop(int semid, abi_long ptr, unsigned nsops)
99
return semop(semid, sops, nsops);
100
}
101
102
+/* __semctl(2) */
103
+static inline abi_long do_bsd___semctl(int semid, int semnum, int target_cmd,
104
+ abi_ptr un_ptr)
105
+{
106
+ void *target_un;
107
+ union semun arg;
108
+ struct semid_ds dsarg;
109
+ unsigned short *array = NULL;
110
+ int host_cmd;
111
+ abi_long ret = 0;
112
+ abi_ulong target_array, target_buffer;
113
+
114
+ switch (target_cmd) {
115
+ case TARGET_GETVAL:
116
+ host_cmd = GETVAL;
117
+ break;
118
+
119
+ case TARGET_SETVAL:
120
+ host_cmd = SETVAL;
121
+ break;
122
+
123
+ case TARGET_GETALL:
124
+ host_cmd = GETALL;
125
+ break;
126
+
127
+ case TARGET_SETALL:
128
+ host_cmd = SETALL;
129
+ break;
130
+
131
+ case TARGET_IPC_STAT:
132
+ host_cmd = IPC_STAT;
133
+ break;
134
+
135
+ case TARGET_IPC_SET:
136
+ host_cmd = IPC_SET;
137
+ break;
138
+
139
+ case TARGET_IPC_RMID:
140
+ host_cmd = IPC_RMID;
141
+ break;
142
+
143
+ case TARGET_GETPID:
144
+ host_cmd = GETPID;
145
+ break;
146
+
147
+ case TARGET_GETNCNT:
148
+ host_cmd = GETNCNT;
149
+ break;
150
+
151
+ case TARGET_GETZCNT:
152
+ host_cmd = GETZCNT;
153
+ break;
154
+
155
+ default:
156
+ return -TARGET_EINVAL;
157
+ }
158
+
159
+ /*
160
+ * Unlike Linux and the semctl system call, we take a pointer
161
+ * to the union arg here.
162
+ */
163
+ target_un = lock_user(VERIFY_READ, un_ptr, sizeof(union target_semun), 1);
164
+
165
+ switch (host_cmd) {
166
+ case GETVAL:
167
+ case SETVAL:
168
+ __get_user(arg.val, (abi_int *)target_un);
169
+ ret = get_errno(semctl(semid, semnum, host_cmd, arg));
170
+ break;
171
+
172
+ case GETALL:
173
+ case SETALL:
174
+ __get_user(target_array, (abi_ulong *)target_un);
175
+ ret = target_to_host_semarray(semid, &array, target_array);
176
+ if (is_error(ret)) {
177
+ goto out;
178
+ }
179
+ arg.array = array;
180
+ ret = get_errno(semctl(semid, semnum, host_cmd, arg));
181
+ if (!is_error(ret)) {
182
+ ret = host_to_target_semarray(semid, target_array, &array);
183
+ }
184
+ break;
185
+
186
+ case IPC_STAT:
187
+ case IPC_SET:
188
+ __get_user(target_buffer, (abi_ulong *)target_un);
189
+ ret = target_to_host_semid_ds(&dsarg, target_buffer);
190
+ if (is_error(ret)) {
191
+ goto out;
192
+ }
193
+ arg.buf = &dsarg;
194
+ ret = get_errno(semctl(semid, semnum, host_cmd, arg));
195
+ if (!is_error(ret)) {
196
+ ret = host_to_target_semid_ds(target_buffer, &dsarg);
197
+ }
198
+ break;
199
+
200
+ case IPC_RMID:
201
+ case GETPID:
202
+ case GETNCNT:
203
+ case GETZCNT:
204
+ ret = get_errno(semctl(semid, semnum, host_cmd, NULL));
205
+ break;
206
+
207
+ default:
208
+ ret = -TARGET_EINVAL;
209
+ break;
210
+ }
211
+out:
212
+ unlock_user(target_un, un_ptr, 1);
213
+ return ret;
214
+}
215
+
216
/* getdtablesize(2) */
217
static inline abi_long do_bsd_getdtablesize(void)
218
{