Cygwin: sched_setscheduler: allow changes of the priority
[newlib-cygwin.git] / winsup / cygwin / fhandler / procsysvipc.cc
blobdac565c07092fe5e540c616b116624ed9c840d1f
1 /* fhandler_procsysvipc.cc: fhandler for /proc/sysvipc virtual filesystem
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <sys/cygwin.h>
13 #include "cygerrno.h"
14 #include "cygserver.h"
15 #include "security.h"
16 #include "path.h"
17 #include "fhandler.h"
18 #include "fhandler_virtual.h"
19 #include "pinfo.h"
20 #include "shared_info.h"
21 #include "dtable.h"
22 #include "cygheap.h"
23 #include "ntdll.h"
24 #include "cygtls.h"
25 #include "tls_pbuf.h"
26 #include <sys/param.h>
27 #include <ctype.h>
29 #define _LIBC
30 #include <dirent.h>
32 #define _KERNEL
33 #include <sys/ipc.h>
34 #include <sys/msg.h>
35 #include <sys/sem.h>
36 #include <sys/shm.h>
38 static off_t format_procsysvipc_msg (void *, char *&);
39 static off_t format_procsysvipc_sem (void *, char *&);
40 static off_t format_procsysvipc_shm (void *, char *&);
42 static const virt_tab_t procsysvipc_tab[] =
44 { _VN ("."), FH_PROCSYSVIPC, virt_directory, NULL },
45 { _VN (".."), FH_PROCSYSVIPC, virt_directory, NULL },
46 { _VN ("msg"), FH_PROCSYSVIPC, virt_file, format_procsysvipc_msg },
47 { _VN ("sem"), FH_PROCSYSVIPC, virt_file, format_procsysvipc_sem },
48 { _VN ("shm"), FH_PROCSYSVIPC, virt_file, format_procsysvipc_shm },
49 { NULL, 0, FH_NADA, virt_none, NULL }
52 static const int PROCSYSVIPC_LINK_COUNT =
53 (sizeof (procsysvipc_tab) / sizeof (virt_tab_t)) - 1;
55 virtual_ftype_t
56 fhandler_procsysvipc::exists ()
58 const char *path = get_name ();
59 debug_printf ("exists (%s)", path);
60 path += proc_len + 1;
61 while (*path != 0 && !isdirsep (*path))
62 path++;
63 if (*path == 0)
65 fileid () = 0;
66 return virt_rootdir;
69 virt_tab_t *entry = virt_tab_search (path + 1, true, procsysvipc_tab,
70 PROCSYSVIPC_LINK_COUNT);
72 cygserver_init ();
74 if (entry)
76 if (entry->type == virt_file)
78 if (cygserver_running != CYGSERVER_OK)
79 return virt_none;
81 fileid () = entry - procsysvipc_tab;
82 return entry->type;
84 fileid () = -1;
85 return virt_none;
88 fhandler_procsysvipc::fhandler_procsysvipc ():
89 fhandler_proc ()
93 int
94 fhandler_procsysvipc::fstat (struct stat *buf)
96 fhandler_base::fstat (buf);
97 buf->st_mode &= ~_IFMT & NO_W;
98 int file_type = exists ();
99 switch (file_type)
101 case virt_none:
102 set_errno (ENOENT);
103 return -1;
104 case virt_directory:
105 case virt_rootdir:
106 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
107 buf->st_nlink = 2;
108 return 0;
109 case virt_file:
110 default:
111 buf->st_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
112 return 0;
117 fhandler_procsysvipc::readdir (DIR *dir, dirent *de)
119 int res = ENMFILE;
120 if (dir->__d_position >= PROCSYSVIPC_LINK_COUNT)
121 goto out;
123 cygserver_init ();
124 if (cygserver_running != CYGSERVER_OK)
125 goto out;
127 strcpy (de->d_name, procsysvipc_tab[dir->__d_position].name);
128 de->d_type = virt_ftype_to_dtype (procsysvipc_tab[dir->__d_position].type);
129 dir->__d_position++;
130 dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
131 res = 0;
132 out:
133 syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
134 return res;
138 fhandler_procsysvipc::open (int flags, mode_t mode)
140 int res = fhandler_virtual::open (flags, mode);
141 if (!res)
142 goto out;
144 nohandle (true);
146 const char *path;
147 path = get_name () + proc_len + 1;
148 pid = atoi (path);
149 while (*path != 0 && !isdirsep (*path))
150 path++;
152 if (*path == 0)
154 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
156 set_errno (EEXIST);
157 res = 0;
158 goto out;
160 else if (flags & O_WRONLY)
162 set_errno (EISDIR);
163 res = 0;
164 goto out;
166 else
168 diropen = true;
169 goto success;
173 virt_tab_t *entry;
174 entry = virt_tab_search (path + 1, true, procsysvipc_tab, PROCSYSVIPC_LINK_COUNT);
175 if (!entry)
177 set_errno ((flags & O_CREAT) ? EROFS : ENOENT);
178 res = 0;
179 goto out;
181 if (flags & O_WRONLY)
183 set_errno (EROFS);
184 res = 0;
185 goto out;
188 fileid () = entry - procsysvipc_tab;
189 if (!fill_filebuf ())
191 res = 0;
192 goto out;
195 if (flags & O_APPEND)
196 position = filesize;
197 else
198 position = 0;
200 success:
201 res = 1;
202 set_flags ((flags & ~O_TEXT) | O_BINARY);
203 set_open_status ();
204 out:
205 syscall_printf ("%d = fhandler_proc::open(%p, 0%o)", res, flags, mode);
206 return res;
209 bool
210 fhandler_procsysvipc::fill_filebuf ()
212 if (procsysvipc_tab[fileid ()].format_func)
214 filesize = procsysvipc_tab[fileid ()].format_func (NULL, filebuf);
215 return true;
217 return false;
220 #define MSG_HEADLINE " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n"
222 static off_t
223 format_procsysvipc_msg (void *, char *&destbuf)
225 char *buf;
226 struct msginfo msginfo;
227 struct msqid_ds *xmsqids;
229 msgctl (0, IPC_INFO, (struct msqid_ds *) &msginfo);
230 /* Don't use tmp_pathbuf. The required buffer sizes can be up to 128K! */
231 xmsqids = (struct msqid_ds *) malloc (sizeof (struct msqid_ds)
232 * msginfo.msgmni);
233 if (!xmsqids)
234 return 0;
235 /* buf size = sizeof headline + 128 bytes per msg queue entry. */
236 buf = (char *) malloc (sizeof (MSG_HEADLINE) + msginfo.msgmni * 128);
237 if (!buf)
239 free (xmsqids);
240 return 0;
243 char *bufptr = stpcpy (buf, MSG_HEADLINE);
244 msgctl (msginfo.msgmni, IPC_INFO, (struct msqid_ds *) xmsqids);
245 for (int i = 0; i < msginfo.msgmni; i++)
247 if (xmsqids[i].msg_qbytes != 0)
249 bufptr += sprintf (bufptr,
250 "%10llu %10u %5o %11u %10u %5d %5d %5u %5u %5u %5u "
251 "%10ld %10ld %10ld\n",
252 xmsqids[i].msg_perm.key,
253 IXSEQ_TO_IPCID(i, xmsqids[i].msg_perm),
254 xmsqids[i].msg_perm.mode,
255 xmsqids[i].msg_cbytes,
256 xmsqids[i].msg_qnum,
257 xmsqids[i].msg_lspid,
258 xmsqids[i].msg_lrpid,
259 (unsigned) xmsqids[i].msg_perm.uid,
260 (unsigned) xmsqids[i].msg_perm.gid,
261 (unsigned) xmsqids[i].msg_perm.cuid,
262 (unsigned) xmsqids[i].msg_perm.cgid,
263 xmsqids[i].msg_stime,
264 xmsqids[i].msg_rtime,
265 xmsqids[i].msg_ctime);
269 off_t size = bufptr - buf;
270 destbuf = (char *) crealloc_abort (destbuf, size);
271 memcpy (destbuf, buf, size);
272 free (buf);
273 free (xmsqids);
274 return size;
277 #undef MSG_HEADLINE
279 #define SEM_HEADLINE " key semid perms nsems uid gid cuid cgid otime ctime\n"
281 static off_t
282 format_procsysvipc_sem (void *, char *&destbuf)
284 char *buf;
285 union semun semun;
286 struct seminfo seminfo;
287 struct semid_ds *xsemids;
289 semun.buf = (struct semid_ds *) &seminfo;
290 semctl (0, 0, IPC_INFO, semun);
291 /* Don't use tmp_pathbuf. The required buffer sizes can be up to 96K! */
292 xsemids = (struct semid_ds *) malloc (sizeof (struct semid_ds)
293 * seminfo.semmni);
294 if (!xsemids)
295 return 0;
296 /* buf size = sizeof headline + 96 bytes per semaphore entry. */
297 buf = (char *) malloc (sizeof (SEM_HEADLINE) + seminfo.semmni * 96);
298 if (!buf)
300 free (xsemids);
301 return 0;
304 char *bufptr = stpcpy (buf, SEM_HEADLINE);
305 semun.buf = xsemids;
306 semctl (seminfo.semmni, 0, IPC_INFO, semun);
307 for (int i = 0; i < seminfo.semmni; i++)
309 if ((xsemids[i].sem_perm.mode & SEM_ALLOC) != 0)
311 bufptr += sprintf (bufptr,
312 "%10llu %10u %5o %10d %5u %5u %5u %5u %10ld %10ld\n",
313 xsemids[i].sem_perm.key,
314 IXSEQ_TO_IPCID(i, xsemids[i].sem_perm),
315 xsemids[i].sem_perm.mode,
316 xsemids[i].sem_nsems,
317 (unsigned) xsemids[i].sem_perm.uid,
318 (unsigned) xsemids[i].sem_perm.gid,
319 (unsigned) xsemids[i].sem_perm.cuid,
320 (unsigned) xsemids[i].sem_perm.cgid,
321 xsemids[i].sem_otime,
322 xsemids[i].sem_ctime);
326 off_t size = bufptr - buf;
327 destbuf = (char *) crealloc_abort (destbuf, size);
328 memcpy (destbuf, buf, size);
329 free (buf);
330 free (xsemids);
331 return size;
334 #undef SEM_HEADLINE
336 #define SHM_HEADLINE " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n"
338 static off_t
339 format_procsysvipc_shm (void *, char *&destbuf)
341 char *buf;
342 struct shminfo shminfo;
343 struct shmid_ds *xshmids;
345 shmctl (0, IPC_INFO, (struct shmid_ds *) &shminfo);
346 /* Don't use tmp_pathbuf. The required buffer sizes can be up to 120K! */
347 xshmids = (struct shmid_ds *) malloc (sizeof (struct shmid_ds)
348 * shminfo.shmmni);
349 if (!xshmids)
350 return 0;
351 /* buf size = sizeof headline + 120 bytes per shmem entry. */
352 buf = (char *) malloc (sizeof (SHM_HEADLINE) + shminfo.shmmni * 120);
353 if (!buf)
355 free (xshmids);
356 return 0;
359 char *bufptr = stpcpy (buf, SHM_HEADLINE);
360 shmctl (shminfo.shmmni, IPC_INFO, (struct shmid_ds *) xshmids);
361 for (int i = 0; i < shminfo.shmmni; i++)
363 if (xshmids[i].shm_perm.mode & 0x0800)
365 bufptr += sprintf (bufptr,
366 "%10llu %10u %5o %10u %5d %5d %6u %5u %5u %5u %5u "
367 "%10ld %10ld %10ld\n",
368 xshmids[i].shm_perm.key,
369 IXSEQ_TO_IPCID(i, xshmids[i].shm_perm),
370 xshmids[i].shm_perm.mode,
371 xshmids[i].shm_segsz,
372 xshmids[i].shm_cpid,
373 xshmids[i].shm_lpid,
374 xshmids[i].shm_nattch,
375 (unsigned) xshmids[i].shm_perm.uid,
376 (unsigned) xshmids[i].shm_perm.gid,
377 (unsigned) xshmids[i].shm_perm.cuid,
378 (unsigned) xshmids[i].shm_perm.cgid,
379 xshmids[i].shm_atime,
380 xshmids[i].shm_dtime,
381 xshmids[i].shm_ctime);
385 off_t size = bufptr - buf;
386 destbuf = (char *) crealloc_abort (destbuf, size);
387 memcpy (destbuf, buf, size);
388 free (buf);
389 free (xshmids);
390 return size;
393 #undef SHM_HEADLINE