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