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