]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/ipcutils.c
2 * SPDX-License-Identifier: GPL-2.0-or-later
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi>
10 * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com>
18 #include "pathnames.h"
23 # define SEMVMX 32767 /* <= 32767 semaphore maximum value */
26 # define SHMMIN 1 /* min shared segment size in bytes */
30 int ipc_msg_get_limits(struct ipc_limits
*lim
)
32 memset(lim
, 0, sizeof(*lim
));
34 if (access(_PATH_PROC_IPC_MSGMNI
, F_OK
) == 0 &&
35 access(_PATH_PROC_IPC_MSGMNB
, F_OK
) == 0 &&
36 access(_PATH_PROC_IPC_MSGMAX
, F_OK
) == 0) {
38 if (ul_path_read_s32(NULL
, &lim
->msgmni
, _PATH_PROC_IPC_MSGMNI
) != 0)
40 if (ul_path_read_s32(NULL
, &lim
->msgmnb
, _PATH_PROC_IPC_MSGMNB
) != 0)
42 if (ul_path_read_u64(NULL
, &lim
->msgmax
, _PATH_PROC_IPC_MSGMAX
) != 0)
45 struct msginfo msginfo
;
47 if (msgctl(0, IPC_INFO
, (struct msqid_ds
*) &msginfo
) < 0)
49 lim
->msgmni
= msginfo
.msgmni
;
50 lim
->msgmnb
= msginfo
.msgmnb
;
51 lim
->msgmax
= msginfo
.msgmax
;
57 int ipc_sem_get_limits(struct ipc_limits
*lim
)
64 f
= fopen(_PATH_PROC_IPC_SEM
, "r");
66 rc
= fscanf(f
, "%d\t%d\t%d\t%d",
67 &lim
->semmsl
, &lim
->semmns
, &lim
->semopm
, &lim
->semmni
);
72 struct seminfo seminfo
= { .semmni
= 0 };
73 union semun arg
= { .array
= (ushort
*) &seminfo
};
75 if (semctl(0, 0, IPC_INFO
, arg
) < 0)
77 lim
->semmni
= seminfo
.semmni
;
78 lim
->semmsl
= seminfo
.semmsl
;
79 lim
->semmns
= seminfo
.semmns
;
80 lim
->semopm
= seminfo
.semopm
;
86 int ipc_shm_get_limits(struct ipc_limits
*lim
)
90 if (access(_PATH_PROC_IPC_SHMALL
, F_OK
) == 0 &&
91 access(_PATH_PROC_IPC_SHMMAX
, F_OK
) == 0 &&
92 access(_PATH_PROC_IPC_SHMMNI
, F_OK
) == 0) {
94 ul_path_read_u64(NULL
, &lim
->shmall
, _PATH_PROC_IPC_SHMALL
);
95 ul_path_read_u64(NULL
, &lim
->shmmax
, _PATH_PROC_IPC_SHMMAX
);
96 ul_path_read_u64(NULL
, &lim
->shmmni
, _PATH_PROC_IPC_SHMMNI
);
99 struct shminfo
*shminfo
;
100 struct shmid_ds shmbuf
;
102 if (shmctl(0, IPC_INFO
, &shmbuf
) < 0)
104 shminfo
= (struct shminfo
*) &shmbuf
;
105 lim
->shmmni
= shminfo
->shmmni
;
106 lim
->shmall
= shminfo
->shmall
;
107 lim
->shmmax
= shminfo
->shmmax
;
113 int ipc_shm_get_info(int id
, struct shm_data
**shmds
)
119 struct shmid_ds dummy
;
121 p
= *shmds
= xcalloc(1, sizeof(struct shm_data
));
124 f
= fopen(_PATH_PROC_SYSV_SHM
, "r");
128 while (fgetc(f
) != '\n'); /* skip header */
130 while (fgets(buf
, sizeof(buf
), f
) != NULL
) {
131 /* scan for the first 14-16 columns (e.g. Linux 2.6.32 has 14) */
135 "%d %d %o %"SCNu64
" %u %u "
136 "%"SCNu64
" %u %u %u %u %"SCNi64
" %"SCNi64
" %"SCNi64
137 " %"SCNu64
" %"SCNu64
"\n",
154 continue; /* invalid line, skipped */
158 if (id
== p
->shm_perm
.id
) {
165 p
->next
= xcalloc(1, sizeof(struct shm_data
));
176 /* Fallback; /proc or /sys file(s) missing. */
178 maxid
= shmctl(0, SHM_INFO
, &dummy
);
180 for (j
= 0; j
<= maxid
; j
++) {
182 struct shmid_ds shmseg
;
183 struct ipc_perm
*ipcp
= &shmseg
.shm_perm
;
185 shmid
= shmctl(j
, SHM_STAT
, &shmseg
);
186 if (shmid
< 0 || (id
> -1 && shmid
!= id
)) {
191 p
->shm_perm
.key
= ipcp
->KEY
;
192 p
->shm_perm
.id
= shmid
;
193 p
->shm_perm
.mode
= ipcp
->mode
;
194 p
->shm_segsz
= shmseg
.shm_segsz
;
195 p
->shm_cprid
= shmseg
.shm_cpid
;
196 p
->shm_lprid
= shmseg
.shm_lpid
;
197 p
->shm_nattch
= shmseg
.shm_nattch
;
198 p
->shm_perm
.uid
= ipcp
->uid
;
199 p
->shm_perm
.gid
= ipcp
->gid
;
200 p
->shm_perm
.cuid
= ipcp
->cuid
;
201 p
->shm_perm
.cgid
= ipcp
->cuid
;
202 p
->shm_atim
= shmseg
.shm_atime
;
203 p
->shm_dtim
= shmseg
.shm_dtime
;
204 p
->shm_ctim
= shmseg
.shm_ctime
;
209 p
->next
= xcalloc(1, sizeof(struct shm_data
));
221 void ipc_shm_free_info(struct shm_data
*shmds
)
224 struct shm_data
*next
= shmds
->next
;
230 static void get_sem_elements(struct sem_data
*p
)
234 if (!p
|| !p
->sem_nsems
|| p
->sem_nsems
> SIZE_MAX
|| p
->sem_perm
.id
< 0)
237 p
->elements
= xcalloc(p
->sem_nsems
, sizeof(struct sem_elem
));
239 for (i
= 0; i
< p
->sem_nsems
; i
++) {
240 struct sem_elem
*e
= &p
->elements
[i
];
241 union semun arg
= { .val
= 0 };
243 e
->semval
= semctl(p
->sem_perm
.id
, i
, GETVAL
, arg
);
245 err(EXIT_FAILURE
, _("%s failed"), "semctl(GETVAL)");
247 e
->ncount
= semctl(p
->sem_perm
.id
, i
, GETNCNT
, arg
);
249 err(EXIT_FAILURE
, _("%s failed"), "semctl(GETNCNT)");
251 e
->zcount
= semctl(p
->sem_perm
.id
, i
, GETZCNT
, arg
);
253 err(EXIT_FAILURE
, _("%s failed"), "semctl(GETZCNT)");
255 e
->pid
= semctl(p
->sem_perm
.id
, i
, GETPID
, arg
);
257 err(EXIT_FAILURE
, _("%s failed"), "semctl(GETPID)");
261 int ipc_sem_get_info(int id
, struct sem_data
**semds
)
266 struct seminfo dummy
;
269 p
= *semds
= xcalloc(1, sizeof(struct sem_data
));
272 f
= fopen(_PATH_PROC_SYSV_SEM
, "r");
276 while (fgetc(f
) != '\n') ; /* skip header */
278 while (feof(f
) == 0) {
280 "%d %d %o %" SCNu64
" %u %u %u %u %"
281 SCNi64
" %" SCNi64
"\n",
291 &p
->sem_ctime
) != 10)
296 if (id
== p
->sem_perm
.id
) {
304 p
->next
= xcalloc(1, sizeof(struct sem_data
));
315 /* Fallback; /proc or /sys file(s) missing. */
317 arg
.array
= (ushort
*) (void *)&dummy
;
318 maxid
= semctl(0, 0, SEM_INFO
, arg
);
320 for (j
= 0; j
<= maxid
; j
++) {
322 struct semid_ds semseg
;
323 struct ipc_perm
*ipcp
= &semseg
.sem_perm
;
324 arg
.buf
= (struct semid_ds
*)&semseg
;
326 semid
= semctl(j
, 0, SEM_STAT
, arg
);
327 if (semid
< 0 || (id
> -1 && semid
!= id
)) {
332 p
->sem_perm
.key
= ipcp
->KEY
;
333 p
->sem_perm
.id
= semid
;
334 p
->sem_perm
.mode
= ipcp
->mode
;
335 p
->sem_nsems
= semseg
.sem_nsems
;
336 p
->sem_perm
.uid
= ipcp
->uid
;
337 p
->sem_perm
.gid
= ipcp
->gid
;
338 p
->sem_perm
.cuid
= ipcp
->cuid
;
339 p
->sem_perm
.cgid
= ipcp
->cuid
;
340 p
->sem_otime
= semseg
.sem_otime
;
341 p
->sem_ctime
= semseg
.sem_ctime
;
344 p
->next
= xcalloc(1, sizeof(struct sem_data
));
359 void ipc_sem_free_info(struct sem_data
*semds
)
362 struct sem_data
*next
= semds
->next
;
363 free(semds
->elements
);
369 int ipc_msg_get_info(int id
, struct msg_data
**msgds
)
374 struct msqid_ds dummy
;
375 struct msqid_ds msgseg
;
377 p
= *msgds
= xcalloc(1, sizeof(struct msg_data
));
380 f
= fopen(_PATH_PROC_SYSV_MSG
, "r");
384 while (fgetc(f
) != '\n') ; /* skip header */
386 while (feof(f
) == 0) {
388 "%d %d %o %" SCNu64
" %" SCNu64
389 " %u %u %u %u %u %u %" SCNi64
" %" SCNi64
" %" SCNi64
"\n",
408 if (id
== p
->msg_perm
.id
) {
409 if (msgctl(id
, IPC_STAT
, &msgseg
) != -1)
410 p
->q_qbytes
= msgseg
.msg_qbytes
;
417 p
->next
= xcalloc(1, sizeof(struct msg_data
));
428 /* Fallback; /proc or /sys file(s) missing. */
430 maxid
= msgctl(0, MSG_INFO
, &dummy
);
432 for (j
= 0; j
<= maxid
; j
++) {
434 struct ipc_perm
*ipcp
= &msgseg
.msg_perm
;
436 msgid
= msgctl(j
, MSG_STAT
, &msgseg
);
437 if (msgid
< 0 || (id
> -1 && msgid
!= id
)) {
442 p
->msg_perm
.key
= ipcp
->KEY
;
443 p
->msg_perm
.id
= msgid
;
444 p
->msg_perm
.mode
= ipcp
->mode
;
445 p
->q_cbytes
= msgseg
.msg_cbytes
;
446 p
->q_qnum
= msgseg
.msg_qnum
;
447 p
->q_lspid
= msgseg
.msg_lspid
;
448 p
->q_lrpid
= msgseg
.msg_lrpid
;
449 p
->msg_perm
.uid
= ipcp
->uid
;
450 p
->msg_perm
.gid
= ipcp
->gid
;
451 p
->msg_perm
.cuid
= ipcp
->cuid
;
452 p
->msg_perm
.cgid
= ipcp
->cgid
;
453 p
->q_stime
= msgseg
.msg_stime
;
454 p
->q_rtime
= msgseg
.msg_rtime
;
455 p
->q_ctime
= msgseg
.msg_ctime
;
456 p
->q_qbytes
= msgseg
.msg_qbytes
;
459 p
->next
= xcalloc(1, sizeof(struct msg_data
));
471 void ipc_msg_free_info(struct msg_data
*msgds
)
474 struct msg_data
*next
= msgds
->next
;
480 void ipc_print_perms(FILE *f
, struct ipc_stat
*is
)
485 fprintf(f
, "%-10d %-10o", is
->id
, is
->mode
& 0777);
487 if ((pw
= getpwuid(is
->cuid
)))
488 fprintf(f
, " %-10s", pw
->pw_name
);
490 fprintf(f
, " %-10u", is
->cuid
);
492 if ((gr
= getgrgid(is
->cgid
)))
493 fprintf(f
, " %-10s", gr
->gr_name
);
495 fprintf(f
, " %-10u", is
->cgid
);
497 if ((pw
= getpwuid(is
->uid
)))
498 fprintf(f
, " %-10s", pw
->pw_name
);
500 fprintf(f
, " %-10u", is
->uid
);
502 if ((gr
= getgrgid(is
->gid
)))
503 fprintf(f
, " %-10s\n", gr
->gr_name
);
505 fprintf(f
, " %-10u\n", is
->gid
);
508 void ipc_print_size(int unit
, char *msg
, uint64_t size
, const char *end
,
515 else if (msg
[strlen(msg
) - 1] == '=')
517 else if (unit
== IPC_UNIT_BYTES
)
518 printf(_("%s (bytes) = "), msg
);
519 else if (unit
== IPC_UNIT_KB
)
520 printf(_("%s (kbytes) = "), msg
);
522 printf("%s = ", msg
);
525 case IPC_UNIT_DEFAULT
:
527 snprintf(format
, sizeof(format
), "%%%dju", width
);
528 printf(format
, size
);
531 snprintf(format
, sizeof(format
), "%%%dju", width
);
532 printf(format
, size
/ 1024);
537 snprintf(format
, sizeof(format
), "%%%ds", width
);
538 printf(format
, (tmp
= size_to_human_string(SIZE_SUFFIX_1LETTER
, size
)));
543 /* impossible occurred */