]>
Commit | Line | Data |
---|---|---|
058e8154 SK |
1 | #include <inttypes.h> |
2 | ||
e5995acd | 3 | #include "c.h" |
b5504a3d | 4 | #include "nls.h" |
058e8154 | 5 | #include "xalloc.h" |
e5995acd SK |
6 | #include "path.h" |
7 | #include "pathnames.h" | |
8 | #include "ipcutils.h" | |
56692a67 | 9 | #include "strutils.h" |
e5995acd SK |
10 | |
11 | #ifndef SEMVMX | |
12 | # define SEMVMX 32767 /* <= 32767 semaphore maximum value */ | |
13 | #endif | |
14 | #ifndef SHMMIN | |
15 | # define SHMMIN 1 /* min shared segment size in bytes */ | |
16 | #endif | |
17 | ||
18 | ||
19 | int ipc_msg_get_limits(struct ipc_limits *lim) | |
20 | { | |
21 | if (path_exist(_PATH_PROC_IPC_MSGMNI) && | |
22 | path_exist(_PATH_PROC_IPC_MSGMNB) && | |
23 | path_exist(_PATH_PROC_IPC_MSGMAX)) { | |
24 | ||
25 | lim->msgmni = path_read_s32(_PATH_PROC_IPC_MSGMNI); | |
26 | lim->msgmnb = path_read_s32(_PATH_PROC_IPC_MSGMNB); | |
27 | lim->msgmax = path_read_s32(_PATH_PROC_IPC_MSGMAX); | |
28 | } else { | |
29 | struct msginfo msginfo; | |
30 | ||
31 | if (msgctl(0, IPC_INFO, (struct msqid_ds *) &msginfo) < 0) | |
32 | return 1; | |
33 | lim->msgmni = msginfo.msgmni; | |
34 | lim->msgmnb = msginfo.msgmnb; | |
35 | lim->msgmax = msginfo.msgmax; | |
36 | } | |
37 | ||
38 | return 0; | |
39 | } | |
40 | ||
41 | int ipc_sem_get_limits(struct ipc_limits *lim) | |
42 | { | |
43 | FILE *f; | |
44 | int rc = 0; | |
45 | ||
46 | lim->semvmx = SEMVMX; | |
47 | ||
48 | f = path_fopen("r", 0, _PATH_PROC_IPC_SEM); | |
49 | if (f) { | |
50 | rc = fscanf(f, "%d\t%d\t%d\t%d", | |
51 | &lim->semmsl, &lim->semmns, &lim->semopm, &lim->semmni); | |
52 | fclose(f); | |
53 | ||
54 | } | |
55 | ||
56 | if (rc == 4) { | |
57 | struct seminfo seminfo; | |
58 | union semun arg = { .array = (ushort *) &seminfo }; | |
59 | ||
60 | if (semctl(0, 0, IPC_INFO, arg) < 0) | |
61 | return 1; | |
62 | lim->semmni = seminfo.semmni; | |
63 | lim->semmsl = seminfo.semmsl; | |
64 | lim->semmns = seminfo.semmns; | |
65 | lim->semopm = seminfo.semopm; | |
66 | } | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
71 | int ipc_shm_get_limits(struct ipc_limits *lim) | |
72 | { | |
73 | lim->shmmin = SHMMIN; | |
74 | ||
75 | if (path_exist(_PATH_PROC_IPC_SHMALL) && | |
76 | path_exist(_PATH_PROC_IPC_SHMMAX) && | |
77 | path_exist(_PATH_PROC_IPC_SHMMNI)) { | |
78 | ||
79 | lim->shmall = path_read_u64(_PATH_PROC_IPC_SHMALL); | |
80 | lim->shmmax = path_read_u64(_PATH_PROC_IPC_SHMMAX); | |
81 | lim->shmmni = path_read_u64(_PATH_PROC_IPC_SHMMNI); | |
82 | ||
83 | } else { | |
929c2575 KZ |
84 | struct shminfo *shminfo; |
85 | struct shmid_ds shmbuf; | |
e5995acd | 86 | |
929c2575 | 87 | if (shmctl(0, IPC_INFO, &shmbuf) < 0) |
e5995acd | 88 | return 1; |
929c2575 KZ |
89 | shminfo = (struct shminfo *) &shmbuf; |
90 | lim->shmmni = shminfo->shmmni; | |
91 | lim->shmall = shminfo->shmall; | |
92 | lim->shmmax = shminfo->shmmax; | |
e5995acd SK |
93 | } |
94 | ||
95 | return 0; | |
96 | } | |
058e8154 | 97 | |
61e14b4a | 98 | int ipc_shm_get_info(int id, struct shm_data **shmds) |
058e8154 SK |
99 | { |
100 | FILE *f; | |
7d8ea9df | 101 | int i = 0, maxid; |
058e8154 | 102 | struct shm_data *p; |
3ce29d6d | 103 | struct shmid_ds dummy; |
058e8154 | 104 | |
7d94d1ce | 105 | p = *shmds = xcalloc(1, sizeof(struct shm_data)); |
058e8154 SK |
106 | p->next = NULL; |
107 | ||
108 | f = path_fopen("r", 0, _PATH_PROC_SYSV_SHM); | |
109 | if (!f) | |
9bcacde1 | 110 | goto shm_fallback; |
058e8154 SK |
111 | |
112 | while (fgetc(f) != '\n'); /* skip header */ | |
113 | ||
7d94d1ce | 114 | while (feof(f) == 0) { |
058e8154 SK |
115 | if (fscanf(f, |
116 | "%d %d %o %"SCNu64 " %u %u " | |
278e7203 | 117 | "%"SCNu64 " %u %u %u %u %"SCNi64 " %"SCNi64 " %"SCNi64 |
058e8154 SK |
118 | " %"SCNu64 " %"SCNu64 "\n", |
119 | &p->shm_perm.key, | |
120 | &p->shm_perm.id, | |
121 | &p->shm_perm.mode, | |
122 | &p->shm_segsz, | |
123 | &p->shm_cprid, | |
124 | &p->shm_lprid, | |
125 | &p->shm_nattch, | |
126 | &p->shm_perm.uid, | |
127 | &p->shm_perm.gid, | |
128 | &p->shm_perm.cuid, | |
129 | &p->shm_perm.cgid, | |
130 | &p->shm_atim, | |
131 | &p->shm_dtim, | |
132 | &p->shm_ctim, | |
133 | &p->shm_rss, | |
134 | &p->shm_swp) != 16) | |
135 | continue; | |
136 | ||
7d94d1ce KZ |
137 | if (id > -1) { |
138 | /* ID specified */ | |
139 | if (id == p->shm_perm.id) { | |
140 | i = 1; | |
141 | break; | |
142 | } else | |
143 | continue; | |
058e8154 | 144 | } |
7d94d1ce KZ |
145 | |
146 | p->next = xcalloc(1, sizeof(struct shm_data)); | |
147 | p = p->next; | |
148 | p->next = NULL; | |
149 | i++; | |
058e8154 SK |
150 | } |
151 | ||
152 | if (i == 0) | |
153 | free(*shmds); | |
154 | fclose(f); | |
155 | return i; | |
156 | ||
157 | /* Fallback; /proc or /sys file(s) missing. */ | |
9bcacde1 | 158 | shm_fallback: |
3ce29d6d | 159 | maxid = shmctl(0, SHM_INFO, &dummy); |
61e14b4a | 160 | |
b507e426 | 161 | for (int j = 0; j <= maxid; j++) { |
058e8154 SK |
162 | int shmid; |
163 | struct shmid_ds shmseg; | |
164 | struct ipc_perm *ipcp = &shmseg.shm_perm; | |
165 | ||
b507e426 RM |
166 | shmid = shmctl(j, SHM_STAT, &shmseg); |
167 | if (shmid < 0 || (id > -1 && shmid != id)) { | |
058e8154 SK |
168 | continue; |
169 | } | |
170 | ||
b507e426 | 171 | i++; |
058e8154 SK |
172 | p->shm_perm.key = ipcp->KEY; |
173 | p->shm_perm.id = shmid; | |
174 | p->shm_perm.mode = ipcp->mode; | |
175 | p->shm_segsz = shmseg.shm_segsz; | |
176 | p->shm_cprid = shmseg.shm_cpid; | |
177 | p->shm_lprid = shmseg.shm_lpid; | |
178 | p->shm_nattch = shmseg.shm_nattch; | |
179 | p->shm_perm.uid = ipcp->uid; | |
180 | p->shm_perm.gid = ipcp->gid; | |
181 | p->shm_perm.cuid = ipcp->cuid; | |
182 | p->shm_perm.cgid = ipcp->cuid; | |
183 | p->shm_atim = shmseg.shm_atime; | |
184 | p->shm_dtim = shmseg.shm_dtime; | |
185 | p->shm_ctim = shmseg.shm_ctime; | |
186 | p->shm_rss = 0xdead; | |
187 | p->shm_swp = 0xdead; | |
188 | ||
189 | if (id < 0) { | |
7d94d1ce | 190 | p->next = xcalloc(1, sizeof(struct shm_data)); |
058e8154 SK |
191 | p = p->next; |
192 | p->next = NULL; | |
058e8154 | 193 | } else |
b507e426 | 194 | break; |
058e8154 SK |
195 | } |
196 | ||
b507e426 RM |
197 | if (i == 0) |
198 | free(*shmds); | |
058e8154 SK |
199 | return i; |
200 | } | |
201 | ||
202 | void ipc_shm_free_info(struct shm_data *shmds) | |
203 | { | |
204 | while (shmds) { | |
205 | struct shm_data *next = shmds->next; | |
206 | free(shmds); | |
207 | shmds = next; | |
208 | } | |
209 | } | |
210 | ||
b5504a3d SK |
211 | static void get_sem_elements(struct sem_data *p) |
212 | { | |
213 | size_t i; | |
214 | ||
215 | if (!p || !p->sem_nsems || p->sem_perm.id < 0) | |
216 | return; | |
217 | ||
218 | p->elements = xcalloc(p->sem_nsems, sizeof(struct sem_elem)); | |
219 | ||
220 | for (i = 0; i < p->sem_nsems; i++) { | |
221 | struct sem_elem *e = &p->elements[i]; | |
222 | union semun arg = { .val = 0 }; | |
223 | ||
224 | e->semval = semctl(p->sem_perm.id, i, GETVAL, arg); | |
225 | if (e->semval < 0) | |
226 | err(EXIT_FAILURE, _("%s failed"), "semctl(GETVAL)"); | |
227 | ||
228 | e->ncount = semctl(p->sem_perm.id, i, GETNCNT, arg); | |
229 | if (e->ncount < 0) | |
230 | err(EXIT_FAILURE, _("%s failed"), "semctl(GETNCNT)"); | |
231 | ||
232 | e->zcount = semctl(p->sem_perm.id, i, GETZCNT, arg); | |
233 | if (e->zcount < 0) | |
234 | err(EXIT_FAILURE, _("%s failed"), "semctl(GETZCNT)"); | |
235 | ||
236 | e->pid = semctl(p->sem_perm.id, i, GETPID, arg); | |
237 | if (e->pid < 0) | |
238 | err(EXIT_FAILURE, _("%s failed"), "semctl(GETPID)"); | |
239 | } | |
240 | } | |
241 | ||
1e2418a2 SK |
242 | int ipc_sem_get_info(int id, struct sem_data **semds) |
243 | { | |
244 | FILE *f; | |
7d8ea9df | 245 | int i = 0, maxid; |
1e2418a2 SK |
246 | struct sem_data *p; |
247 | struct seminfo dummy; | |
248 | union semun arg; | |
249 | ||
250 | p = *semds = xcalloc(1, sizeof(struct sem_data)); | |
251 | p->next = NULL; | |
252 | ||
253 | f = path_fopen("r", 0, _PATH_PROC_SYSV_SEM); | |
254 | if (!f) | |
255 | goto sem_fallback; | |
256 | ||
257 | while (fgetc(f) != '\n') ; /* skip header */ | |
258 | ||
259 | while (feof(f) == 0) { | |
260 | if (fscanf(f, | |
278e7203 KZ |
261 | "%d %d %o %" SCNu64 " %u %u %u %u %" |
262 | SCNi64 " %" SCNi64 "\n", | |
1e2418a2 SK |
263 | &p->sem_perm.key, |
264 | &p->sem_perm.id, | |
265 | &p->sem_perm.mode, | |
266 | &p->sem_nsems, | |
267 | &p->sem_perm.uid, | |
268 | &p->sem_perm.gid, | |
269 | &p->sem_perm.cuid, | |
270 | &p->sem_perm.cgid, | |
271 | &p->sem_otime, | |
272 | &p->sem_ctime) != 10) | |
273 | continue; | |
274 | ||
275 | if (id > -1) { | |
276 | /* ID specified */ | |
277 | if (id == p->sem_perm.id) { | |
b5504a3d | 278 | get_sem_elements(p); |
1e2418a2 SK |
279 | i = 1; |
280 | break; | |
281 | } else | |
282 | continue; | |
283 | } | |
284 | ||
285 | p->next = xcalloc(1, sizeof(struct sem_data)); | |
286 | p = p->next; | |
287 | p->next = NULL; | |
288 | i++; | |
289 | } | |
290 | ||
291 | if (i == 0) | |
292 | free(*semds); | |
293 | fclose(f); | |
294 | return i; | |
295 | ||
296 | /* Fallback; /proc or /sys file(s) missing. */ | |
9bcacde1 | 297 | sem_fallback: |
1e2418a2 SK |
298 | arg.array = (ushort *) (void *)&dummy; |
299 | maxid = semctl(0, 0, SEM_INFO, arg); | |
1e2418a2 | 300 | |
5078a0d3 | 301 | for (int j = 0; j <= maxid; j++) { |
1e2418a2 SK |
302 | int semid; |
303 | struct semid_ds semseg; | |
304 | struct ipc_perm *ipcp = &semseg.sem_perm; | |
305 | arg.buf = (struct semid_ds *)&semseg; | |
306 | ||
5078a0d3 RM |
307 | semid = semctl(j, 0, SEM_STAT, arg); |
308 | if (semid < 0 || (id > -1 && semid != id)) { | |
1e2418a2 SK |
309 | continue; |
310 | } | |
311 | ||
5078a0d3 | 312 | i++; |
1e2418a2 SK |
313 | p->sem_perm.key = ipcp->KEY; |
314 | p->sem_perm.id = semid; | |
315 | p->sem_perm.mode = ipcp->mode; | |
316 | p->sem_nsems = semseg.sem_nsems; | |
317 | p->sem_perm.uid = ipcp->uid; | |
318 | p->sem_perm.gid = ipcp->gid; | |
319 | p->sem_perm.cuid = ipcp->cuid; | |
320 | p->sem_perm.cgid = ipcp->cuid; | |
321 | p->sem_otime = semseg.sem_otime; | |
322 | p->sem_ctime = semseg.sem_ctime; | |
323 | ||
324 | if (id < 0) { | |
325 | p->next = xcalloc(1, sizeof(struct sem_data)); | |
326 | p = p->next; | |
327 | p->next = NULL; | |
328 | i++; | |
b5504a3d SK |
329 | } else { |
330 | get_sem_elements(p); | |
5078a0d3 | 331 | break; |
b5504a3d | 332 | } |
1e2418a2 SK |
333 | } |
334 | ||
5078a0d3 RM |
335 | if (i == 0) |
336 | free(*semds); | |
1e2418a2 SK |
337 | return i; |
338 | } | |
339 | ||
340 | void ipc_sem_free_info(struct sem_data *semds) | |
341 | { | |
342 | while (semds) { | |
343 | struct sem_data *next = semds->next; | |
b5504a3d | 344 | free(semds->elements); |
1e2418a2 SK |
345 | free(semds); |
346 | semds = next; | |
347 | } | |
348 | } | |
349 | ||
35118dfc SK |
350 | int ipc_msg_get_info(int id, struct msg_data **msgds) |
351 | { | |
352 | FILE *f; | |
7d8ea9df | 353 | int i = 0, maxid; |
35118dfc SK |
354 | struct msg_data *p; |
355 | struct msqid_ds dummy; | |
2bd2f79d | 356 | struct msqid_ds msgseg; |
35118dfc SK |
357 | |
358 | p = *msgds = xcalloc(1, sizeof(struct msg_data)); | |
359 | p->next = NULL; | |
360 | ||
361 | f = path_fopen("r", 0, _PATH_PROC_SYSV_MSG); | |
362 | if (!f) | |
363 | goto msg_fallback; | |
364 | ||
365 | while (fgetc(f) != '\n') ; /* skip header */ | |
366 | ||
367 | while (feof(f) == 0) { | |
368 | if (fscanf(f, | |
278e7203 KZ |
369 | "%d %d %o %" SCNu64 " %" SCNu64 |
370 | " %u %u %u %u %u %u %" SCNi64 " %" SCNi64 " %" SCNi64 "\n", | |
35118dfc SK |
371 | &p->msg_perm.key, |
372 | &p->msg_perm.id, | |
373 | &p->msg_perm.mode, | |
374 | &p->q_cbytes, | |
375 | &p->q_qnum, | |
376 | &p->q_lspid, | |
377 | &p->q_lrpid, | |
378 | &p->msg_perm.uid, | |
379 | &p->msg_perm.gid, | |
380 | &p->msg_perm.cuid, | |
381 | &p->msg_perm.cgid, | |
382 | &p->q_stime, | |
383 | &p->q_rtime, | |
384 | &p->q_ctime) != 14) | |
385 | continue; | |
386 | ||
387 | if (id > -1) { | |
388 | /* ID specified */ | |
389 | if (id == p->msg_perm.id) { | |
2bd2f79d SK |
390 | /* |
391 | * FIXME: q_qbytes are not in /proc | |
392 | * | |
393 | */ | |
394 | if (msgctl(id, IPC_STAT, &msgseg) != -1) | |
395 | p->q_qbytes = msgseg.msg_qbytes; | |
35118dfc SK |
396 | i = 1; |
397 | break; | |
398 | } else | |
399 | continue; | |
400 | } | |
401 | ||
402 | p->next = xcalloc(1, sizeof(struct msg_data)); | |
403 | p = p->next; | |
404 | p->next = NULL; | |
405 | i++; | |
406 | } | |
407 | ||
408 | if (i == 0) | |
409 | free(*msgds); | |
410 | fclose(f); | |
411 | return i; | |
412 | ||
413 | /* Fallback; /proc or /sys file(s) missing. */ | |
9bcacde1 | 414 | msg_fallback: |
08e7d10b | 415 | maxid = msgctl(0, MSG_INFO, &dummy); |
35118dfc | 416 | |
08e7d10b | 417 | for (int j = 0; j <= maxid; j++) { |
35118dfc | 418 | int msgid; |
35118dfc SK |
419 | struct ipc_perm *ipcp = &msgseg.msg_perm; |
420 | ||
08e7d10b RM |
421 | msgid = msgctl(j, MSG_STAT, &msgseg); |
422 | if (msgid < 0 || (id > -1 && msgid != id)) { | |
35118dfc SK |
423 | continue; |
424 | } | |
425 | ||
08e7d10b | 426 | i++; |
35118dfc SK |
427 | p->msg_perm.key = ipcp->KEY; |
428 | p->msg_perm.id = msgid; | |
429 | p->msg_perm.mode = ipcp->mode; | |
430 | p->q_cbytes = msgseg.msg_cbytes; | |
431 | p->q_qnum = msgseg.msg_qnum; | |
432 | p->q_lspid = msgseg.msg_lspid; | |
433 | p->q_lrpid = msgseg.msg_lrpid; | |
434 | p->msg_perm.uid = ipcp->uid; | |
435 | p->msg_perm.gid = ipcp->gid; | |
436 | p->msg_perm.cuid = ipcp->cuid; | |
437 | p->msg_perm.cgid = ipcp->cgid; | |
438 | p->q_stime = msgseg.msg_stime; | |
439 | p->q_rtime = msgseg.msg_rtime; | |
440 | p->q_ctime = msgseg.msg_ctime; | |
2bd2f79d | 441 | p->q_qbytes = msgseg.msg_qbytes; |
35118dfc SK |
442 | |
443 | if (id < 0) { | |
444 | p->next = xcalloc(1, sizeof(struct msg_data)); | |
445 | p = p->next; | |
446 | p->next = NULL; | |
35118dfc | 447 | } else |
08e7d10b | 448 | break; |
35118dfc SK |
449 | } |
450 | ||
08e7d10b RM |
451 | if (i == 0) |
452 | free(*msgds); | |
35118dfc SK |
453 | return i; |
454 | } | |
455 | ||
456 | void ipc_msg_free_info(struct msg_data *msgds) | |
457 | { | |
458 | while (msgds) { | |
459 | struct msg_data *next = msgds->next; | |
460 | free(msgds); | |
461 | msgds = next; | |
462 | } | |
463 | } | |
464 | ||
058e8154 SK |
465 | void ipc_print_perms(FILE *f, struct ipc_stat *is) |
466 | { | |
467 | struct passwd *pw; | |
468 | struct group *gr; | |
469 | ||
470 | fprintf(f, "%-10d %-10o", is->id, is->mode & 0777); | |
471 | ||
472 | if ((pw = getpwuid(is->cuid))) | |
473 | fprintf(f, " %-10s", pw->pw_name); | |
474 | else | |
475 | fprintf(f, " %-10u", is->cuid); | |
476 | ||
477 | if ((gr = getgrgid(is->cgid))) | |
478 | fprintf(f, " %-10s", gr->gr_name); | |
479 | else | |
480 | fprintf(f, " %-10u", is->cgid); | |
481 | ||
482 | if ((pw = getpwuid(is->uid))) | |
483 | fprintf(f, " %-10s", pw->pw_name); | |
484 | else | |
485 | fprintf(f, " %-10u", is->uid); | |
486 | ||
487 | if ((gr = getgrgid(is->gid))) | |
488 | fprintf(f, " %-10s\n", gr->gr_name); | |
489 | else | |
490 | fprintf(f, " %-10u\n", is->gid); | |
491 | } | |
56692a67 | 492 | |
873e7a59 | 493 | void ipc_print_size(int unit, char *msg, uint64_t size, const char *end, |
56692a67 SK |
494 | int width) |
495 | { | |
873e7a59 | 496 | char format[32]; |
56692a67 SK |
497 | |
498 | if (!msg) | |
499 | /* NULL */ ; | |
500 | else if (msg[strlen(msg) - 1] == '=') | |
501 | printf("%s", msg); | |
502 | else if (unit == IPC_UNIT_BYTES) | |
503 | printf(_("%s (bytes) = "), msg); | |
504 | else if (unit == IPC_UNIT_KB) | |
505 | printf(_("%s (kbytes) = "), msg); | |
506 | else | |
507 | printf("%s = ", msg); | |
508 | ||
509 | switch (unit) { | |
510 | case IPC_UNIT_DEFAULT: | |
511 | case IPC_UNIT_BYTES: | |
873e7a59 | 512 | sprintf(format, "%%%dju", width); |
56692a67 SK |
513 | printf(format, size); |
514 | break; | |
515 | case IPC_UNIT_KB: | |
873e7a59 | 516 | sprintf(format, "%%%dju", width); |
56692a67 SK |
517 | printf(format, size / 1024); |
518 | break; | |
519 | case IPC_UNIT_HUMAN: | |
520 | sprintf(format, "%%%ds", width); | |
521 | printf(format, size_to_human_string(SIZE_SUFFIX_1LETTER, size)); | |
522 | break; | |
523 | default: | |
524 | /* impossible occurred */ | |
525 | abort(); | |
526 | } | |
527 | ||
528 | if (end) | |
529 | printf("%s", end); | |
530 | } |