2 * Copyright (c) 2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/fcntl.h>
28 #include <sys/errno.h>
29 #include <sys/param.h>
30 #include <sys/mount.h>
40 // open file descriptors
41 struct proc_fdinfo
*fds
;
45 // file/volume of interest
46 struct stat match_stat
;
51 } fdOpenInfo
, *fdOpenInfoRef
;
58 check_init(const char *path
, uint32_t flags
)
63 info
= malloc(sizeof(*info
));
75 status
= stat(path
, &info
->match_stat
);
95 check_free(fdOpenInfoRef info
)
97 if (info
->pids
!= NULL
) {
101 if (info
->fds
!= NULL
) {
113 * check if a process vnode is of interest
121 check_file(fdOpenInfoRef info
, struct vinfo_stat
*sb
)
123 if (sb
->vst_dev
== 0) {
128 if (sb
->vst_dev
!= info
->match_stat
.st_dev
) {
129 // if not the requested filesystem
133 if (!(info
->flags
& PROC_LISTPIDSPATH_PATH_IS_VOLUME
) &&
134 (sb
->vst_ino
!= info
->match_stat
.st_ino
)) {
135 // if not the requested file
144 * check_process_vnodes
145 * check [process] current working directory
146 * check [process] root directory
154 check_process_vnodes(fdOpenInfoRef info
, int pid
)
158 struct proc_vnodepathinfo vpi
;
160 buf_used
= proc_pidinfo(pid
, PROC_PIDVNODEPATHINFO
, 0, &vpi
, sizeof(vpi
));
162 if (errno
== ESRCH
) {
163 // if the process is gone
167 } else if (buf_used
< sizeof(vpi
)) {
168 // if we didn't get enough information
172 // processing current working directory
173 status
= check_file(info
, &vpi
.pvi_cdir
.vip_vi
.vi_stat
);
179 // processing root directory
180 status
= check_file(info
, &vpi
.pvi_rdir
.vip_vi
.vi_stat
);
192 * check [process] text (memory)
200 check_process_text(fdOpenInfoRef info
, int pid
)
205 while (1) { // for all memory regions
207 struct proc_regionwithpathinfo rwpi
;
209 // processing next address
210 buf_used
= proc_pidinfo(pid
, PROC_PIDREGIONPATHINFO
, a
, &rwpi
, sizeof(rwpi
));
212 if ((errno
== ESRCH
) || (errno
== EINVAL
)) {
213 // if no more text information is available for this process.
217 } else if (buf_used
< sizeof(rwpi
)) {
218 // if we didn't get enough information
222 //if (rwpi.prp_vip.vip_path[0])
223 status
= check_file(info
, &rwpi
.prp_vip
.vip_vi
.vi_stat
);
229 a
= rwpi
.prp_prinfo
.pri_address
+ rwpi
.prp_prinfo
.pri_size
;
238 * check [process] open file descriptors
246 check_process_fds(fdOpenInfoRef info
, int pid
)
252 // get list of open file descriptors
253 buf_used
= proc_pidinfo(pid
, PROC_PIDLISTFDS
, 0, NULL
, 0);
259 if (buf_used
> info
->fds_size
) {
260 // if we need to allocate [more] space
261 while (buf_used
> info
->fds_size
) {
262 info
->fds_size
+= (sizeof(struct proc_fdinfo
) * 32);
265 if (info
->fds
== NULL
) {
266 info
->fds
= malloc(info
->fds_size
);
268 info
->fds
= reallocf(info
->fds
, info
->fds_size
);
270 if (info
->fds
== NULL
) {
275 buf_used
= proc_pidinfo(pid
, PROC_PIDLISTFDS
, 0, info
->fds
, info
->fds_size
);
280 if ((buf_used
+ sizeof(struct proc_fdinfo
)) >= info
->fds_size
) {
281 // if not enough room in the buffer for an extra fd
282 buf_used
= info
->fds_size
;
286 info
->fds_count
= buf_used
/ sizeof(struct proc_fdinfo
);
290 // iterate through each file descriptor
291 for (i
= 0; i
< info
->fds_count
; i
++) {
292 struct proc_fdinfo
*fdp
;
295 switch (fdp
->proc_fdtype
) {
296 case PROX_FDTYPE_VNODE
: {
298 struct vnode_fdinfo vi
;
300 buf_used
= proc_pidfdinfo(pid
, fdp
->proc_fd
, PROC_PIDFDVNODEINFO
, &vi
, sizeof(vi
));
302 if (errno
== ENOENT
) {
304 * The file descriptor's vnode may have been revoked. This is a
305 * bit of a hack, since an ENOENT error might not always mean the
306 * descriptor's vnode has been revoked. As the libproc API
307 * matures, this code may need to be revisited.
312 } else if (buf_used
< sizeof(vi
)) {
313 // if we didn't get enough information
317 if ((info
->flags
& PROC_LISTPIDSPATH_EXCLUDE_EVTONLY
) &&
318 (vi
.pfi
.fi_openflags
& O_EVTONLY
)) {
319 // if this file should be excluded
323 status
= check_file(info
, &vi
.pvi
.vi_stat
);
341 * check [process] current working and root directories
342 * check [process] text (memory)
343 * check [process] open file descriptors
351 check_process(fdOpenInfoRef info
, int pid
)
355 // check root and current working directory
356 status
= check_process_vnodes(info
, pid
);
362 // check process text (memory)
363 status
= check_process_text(info
, pid
);
369 // check open file descriptors
370 status
= check_process_fds(info
, pid
);
389 * out : buffer filled with process IDs that have open file
390 * references that match the specified path or volume;
391 * return value is the bytes of the returned buffer
392 * that contains valid information.
395 proc_listpidspath(uint32_t type
,
403 int *buf_next
= (int *)buffer
;
408 if (buffer
== NULL
) {
409 // if this is a sizing request
410 return proc_listpids(type
, typeinfo
, NULL
, 0);
413 buffersize
-= (buffersize
% sizeof(int)); // make whole number of ints
414 if (buffersize
< sizeof(int)) {
415 // if we can't even return a single PID
421 info
= check_init(path
, pathflags
);
426 // get list of processes
427 buf_used
= proc_listpids(type
, typeinfo
, NULL
, 0);
433 if (buf_used
> info
->pids_size
) {
434 // if we need to allocate [more] space
435 while (buf_used
> info
->pids_size
) {
436 info
->pids_size
+= (sizeof(int) * 32);
439 if (info
->pids
== NULL
) {
440 info
->pids
= malloc(info
->pids_size
);
442 info
->pids
= reallocf(info
->pids
, info
->pids_size
);
444 if (info
->pids
== NULL
) {
449 buf_used
= proc_listpids(type
, typeinfo
, info
->pids
, info
->pids_size
);
454 if ((buf_used
+ sizeof(int)) >= info
->pids_size
) {
455 // if not enough room in the buffer for an extra pid
456 buf_used
= info
->pids_size
;
460 info
->pids_count
= buf_used
/ sizeof(int);
464 // iterate through each process
466 for (i
= info
->pids_count
- 1; i
>= 0; i
--) {
475 status
= check_process(info
, pid
);
482 buf_used
+= sizeof(int);
484 if (buf_used
>= buffersize
) {
485 // if we have filled the buffer