static RList *xnu_desc_list (int pid) { #if TARGET_OS_IPHONE return NULL; #else #define xwr2rwx(x) ((x&1)<<2) | (x&2) | ((x&4)>>2) RDebugDesc *desc; RList *ret = r_list_new(); struct vnode_fdinfowithpath vi; int i, nb, type = 0; int maxfd = getMaxFiles(); for (i=0 ; i<maxfd; i++) { nb = proc_pidfdinfo (pid, i, PROC_PIDFDVNODEPATHINFO, &vi, sizeof (vi)); if (nb<1) { continue; } if (nb < sizeof (vi)) { perror ("too few bytes"); break; } //printf ("FD %d RWX %x ", i, vi.pfi.fi_openflags); //printf ("PATH %s\n", vi.pvip.vip_path); desc = r_debug_desc_new (i, vi.pvip.vip_path, xwr2rwx(vi.pfi.fi_openflags), type, 0); r_list_append (ret, desc); } return ret; #endif }
void genSocketDescriptor(int pid, int descriptor, QueryData& results) { struct socket_fdinfo si; if (proc_pidfdinfo(pid, descriptor, PROC_PIDFDSOCKETINFO, &si, PROC_PIDFDSOCKETINFO_SIZE) <= 0) { return; } if (si.psi.soi_family == AF_INET || si.psi.soi_family == AF_INET6) { Row r; r["pid"] = INTEGER(pid); r["fd"] = BIGINT(descriptor); r["socket"] = BIGINT(si.psi.soi_so); r["path"] = ""; // Darwin/OSX SOCKINFO_TCP is not IPPROTO_TCP if (si.psi.soi_kind == SOCKINFO_TCP) { r["protocol"] = INTEGER(6); } else { r["protocol"] = INTEGER(17); } // Darwin/OSX AF_INET6 == 30 if (si.psi.soi_family == AF_INET) { r["family"] = INTEGER(2); } else { r["family"] = INTEGER(10); } parseNetworkSocket(si, r); results.push_back(r); } else if (si.psi.soi_family == AF_UNIX) { Row r; r["pid"] = INTEGER(pid); r["socket"] = INTEGER(descriptor); r["family"] = "0"; r["protocol"] = "0"; r["local_address"] = ""; r["local_port"] = "0"; r["remote_address"] = ""; r["remote_port"] = "0"; if ((char*)si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path != nullptr) { r["path"] = si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path; } else { r["path"] = ""; } results.push_back(r); } else if (si.psi.soi_family == AF_APPLETALK) { // AF_APPLETALK = 17 } else if (si.psi.soi_family == AF_NATM) { // AF_NATM = 32 } else { // Unsupported socket type. } }
void genFileDescriptor(int pid, int descriptor, QueryData& results) { struct vnode_fdinfowithpath vi; if (proc_pidfdinfo(pid, descriptor, PROC_PIDFDVNODEPATHINFO, &vi, PROC_PIDFDVNODEPATHINFO_SIZE) <= 0) { return; } Row r; r["pid"] = INTEGER(pid); r["fd"] = INTEGER(descriptor); r["path"] = std::string(vi.pvip.vip_path); results.push_back(r); }
char *common_get_fd_path(int fd) { struct stat st; if (fstat(fd, &st)) { return NULL; } #if defined WIN32 // Windows HANDLE hdl = (HANDLE) _get_osfhandle(fd); if (hdl != INVALID_HANDLE_VALUE) { DWORD size = GetFinalPathNameByHandle(hdl, NULL, 0, 0); if (size) { char *path = g_malloc(size); DWORD ret = GetFinalPathNameByHandle(hdl, path, size - 1, 0); if (ret > 0 && ret <= size) { return path; } g_free(path); } } #elif defined HAVE_PROC_PIDFDINFO // Mac OS X // Ignore kqueues, since they can be opened behind our back for // Grand Central Dispatch struct kqueue_fdinfo kqi; if (proc_pidfdinfo(getpid(), fd, PROC_PIDFDKQUEUEINFO, &kqi, sizeof(kqi))) { return NULL; } char *path = g_malloc(MAXPATHLEN); if (!fcntl(fd, F_GETPATH, path)) { return path; } g_free(path); #else // Fallback; works only on Linux char *link_path = g_strdup_printf("/proc/%d/fd/%d", getpid(), fd); char *path = g_file_read_link(link_path, NULL); g_free(link_path); if (path) { return path; } #endif return g_strdup("<unknown>"); }
void tt_fs_status_dump_ntv(IN tt_u32_t flag) { pid_t pid; int size; struct proc_fdinfo *fdinfo; pid = getpid(); size = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (size <= 0) { return; } fdinfo = (struct proc_fdinfo *)malloc(size); if (fdinfo == NULL) { return; } size = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo, size); if (size > 0) { int n, i; n = size / PROC_PIDLISTFD_SIZE; for (i = 0; i < n; ++i) { if (fdinfo[i].proc_fdtype == PROX_FDTYPE_VNODE) { struct vnode_fdinfowithpath vi; int vs = proc_pidfdinfo(pid, fdinfo[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vi, PROC_PIDFDVNODEPATHINFO_SIZE); if (vs == PROC_PIDFDVNODEPATHINFO_SIZE) { tt_printf("%s[fd: %d] [%s]\n", TT_COND(flag & TT_FS_STATUS_PREFIX, "<<FS>> ", ""), fdinfo[i].proc_fd, vi.pvip.vip_path); } } } } free(fdinfo); }
int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd) { int count = 0; int bufferSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, 0, 0); struct stat stat_buf; if (bufferSize < 0) { printf("Error :/, cannot proc_pidinfo\n"); return 0; } struct proc_fdinfo *procFDInfo = (struct proc_fdinfo *)malloc(bufferSize); proc_pidinfo(pid, PROC_PIDLISTFDS, 0, procFDInfo, bufferSize); int numberOfProcFDs = bufferSize / PROC_PIDLISTFD_SIZE; int i; for(i = 0; i < numberOfProcFDs; i++) { if(procFDInfo[i].proc_fdtype == PROX_FDTYPE_VNODE) { struct vnode_fdinfowithpath vnodeInfo; proc_pidfdinfo(pid, procFDInfo[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE); if (stat(vnodeInfo.pvip.vip_path, &stat_buf) < 0) { if (flag_debug) perror("sstat"); continue; } if (!S_ISREG(stat_buf.st_mode) && !S_ISBLK(stat_buf.st_mode)) continue; if (is_ignored_file(vnodeInfo.pvip.vip_path)) continue; // OK, we've found a potential interesting file. fd_list[count++] = procFDInfo[i].proc_fd; //~ printf("[debug] %s\n",vnodeInfo.pvip.vip_path); if(count == max_fd) break; } } return count; }
/* * Return process TCP and UDP connections as a list of tuples. * References: * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0 * - /usr/include/sys/proc_info.h */ static PyObject* get_process_connections(PyObject* self, PyObject* args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer; struct proc_fdinfo *fdp_pointer; struct socket_fdinfo si; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; PyObject *laddr = NULL; PyObject *raddr = NULL; PyObject *af_filter = NULL; PyObject *type_filter = NULL; if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { return NULL; } if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); return NULL; } if (pid == 0) { return retList; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { goto error; } fds_pointer = malloc(pidinfo_result); pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); free(fds_pointer); if (pidinfo_result <= 0) { goto error; } iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); for (i = 0; i < iterations; i++) { errno = 0; fdp_pointer = &fds_pointer[i]; // if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si)); // --- errors checking if (nb <= 0) { if (errno == EBADF) { // let's assume socket has been closed continue; } if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); } } if (nb < sizeof(si)) { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)"); } // --- /errors checking // int fd, family, type, lport, rport; char lip[200], rip[200]; char *state; int inseq; PyObject* _family; PyObject* _type; fd = (int)fdp_pointer->proc_fd; family = si.psi.soi_family; type = si.psi.soi_kind; if (type == 2) { type = SOCK_STREAM; } else if (type == 1) { type = SOCK_DGRAM; } else { continue; } // apply filters _family = PyLong_FromLong((long)family); inseq = PySequence_Contains(af_filter, _family); Py_DECREF(_family); if (inseq == 0) { continue; } _type = PyLong_FromLong((long)type); inseq = PySequence_Contains(type_filter, _type); Py_DECREF(_type); if (inseq == 0) { continue; } if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } if (family == AF_INET) { inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4, lip, sizeof(lip)); inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4, rip, sizeof(lip)); } else { inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6, lip, sizeof(lip)); inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6, lip, sizeof(rip)); } // check for inet_ntop failures if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); if (type == SOCK_STREAM) { state = get_connection_status((int)si.psi.soi_proto.pri_tcp.tcpsi_state); } else { state = ""; } laddr = Py_BuildValue("(si)", lip, lport); if (rport != 0) { raddr = Py_BuildValue("(si)", rip, rport); } else { raddr = PyTuple_New(0); } // --- construct python list tuple = Py_BuildValue("(iiiNNs)", fd, family, type, laddr, raddr, state); PyList_Append(retList, tuple); Py_DECREF(tuple); // --- /construct python list } } return retList; error: if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else if (! pid_exists(pid) ) { return NoSuchProcess(); } else { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); } }
/* * Return process open files as a Python tuple. * References: * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd * - /usr/include/sys/proc_info.h */ static PyObject* get_process_open_files(PyObject* self, PyObject* args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer; struct proc_fdinfo *fdp_pointer; struct vnode_fdinfowithpath vi; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { goto error; } fds_pointer = malloc(pidinfo_result); pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); free(fds_pointer); if (pidinfo_result <= 0) { goto error; } iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); for (i = 0; i < iterations; i++) { fdp_pointer = &fds_pointer[i]; // if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi)); // --- errors checking if (nb <= 0) { if ((errno == ENOENT) || (errno == EBADF)) { // no such file or directory or bad file descriptor; // let's assume the file has been closed or removed continue; } if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); } if (nb < sizeof(vi)) { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)"); } // --- /errors checking // --- construct python list tuple = Py_BuildValue("(si)", vi.pvip.vip_path, (int)fdp_pointer->proc_fd); PyList_Append(retList, tuple); Py_DECREF(tuple); // --- /construct python list } } return retList; error: if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else if (! pid_exists(pid) ) { return NoSuchProcess(); } else { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); } }
/* * check_process_fds * check [process] open file descriptors * * in : pid * out : -1 if error * 0 if no match * 1 if match */ static int check_process_fds(fdOpenInfoRef info, int pid) { int buf_used; int i; int status; // get list of open file descriptors buf_used = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (buf_used <= 0) { return -1; } while (1) { if (buf_used > info->fds_size) { // if we need to allocate [more] space while (buf_used > info->fds_size) { info->fds_size += (sizeof(struct proc_fdinfo) * 32); } if (info->fds == NULL) { info->fds = malloc(info->fds_size); } else { info->fds = reallocf(info->fds, info->fds_size); } if (info->fds == NULL) { return -1; } } buf_used = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, info->fds, (int)info->fds_size); if (buf_used <= 0) { return -1; } if ((buf_used + sizeof(struct proc_fdinfo)) >= info->fds_size) { // if not enough room in the buffer for an extra fd buf_used = (int)(info->fds_size + sizeof(struct proc_fdinfo)); continue; } info->fds_count = (int)(buf_used / sizeof(struct proc_fdinfo)); break; } // iterate through each file descriptor for (i = 0; i < info->fds_count; i++) { struct proc_fdinfo *fdp; fdp = &info->fds[i]; switch (fdp->proc_fdtype) { case PROX_FDTYPE_VNODE : { int buf_used; struct vnode_fdinfo vi; buf_used = proc_pidfdinfo(pid, fdp->proc_fd, PROC_PIDFDVNODEINFO, &vi, sizeof(vi)); if (buf_used <= 0) { if (errno == ENOENT) { /* * The file descriptor's vnode may have been revoked. This is a * bit of a hack, since an ENOENT error might not always mean the * descriptor's vnode has been revoked. As the libproc API * matures, this code may need to be revisited. */ continue; } return -1; } else if (buf_used < sizeof(vi)) { // if we didn't get enough information return -1; } if ((info->flags & PROC_LISTPIDSPATH_EXCLUDE_EVTONLY) && (vi.pfi.fi_openflags & O_EVTONLY)) { // if this file should be excluded continue; } status = check_file(info, &vi.pvi.vi_stat); if (status != 0) { // if error or match return status; } break; } default : break; } } return 0; }
signed char get_fdinfo(pid_t pid, int fdnum, fdinfo_t *fd_info) { struct stat stat_buf; #ifndef __APPLE__ char fdpath[MAXPATHLEN + 1]; char line[LINE_LEN]; FILE *fp; #endif struct timezone tz; fd_info->num = fdnum; #ifdef __APPLE__ struct vnode_fdinfowithpath vnodeInfo; if (proc_pidfdinfo(pid, fdnum, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE) <= 0) return 0; strncpy(fd_info->name, vnodeInfo.pvip.vip_path, MAXPATHLEN); #else ssize_t len; snprintf(fdpath, MAXPATHLEN, "%s/%d/fd/%d", PROC_PATH, pid, fdnum); len=readlink(fdpath, fd_info->name, MAXPATHLEN); if(len != -1) fd_info->name[len] = 0; else { //~ perror("readlink"); return 0; } #endif if(stat(fd_info->name, &stat_buf) == -1) { //~ printf("[debug] %i - %s\n",pid,fd_info->name); if (!flag_quiet) perror("stat (get_fdinfo)"); return 0; } if(S_ISBLK(stat_buf.st_mode)) { int fd; fd = open(fd_info->name, O_RDONLY); if (fd < 0) { if (!flag_quiet) perror("open (get_fdinfo)"); return 0; } #ifdef __APPLE__ uint64_t bc; uint32_t bs; bs = 0; bc = 0; if (ioctl(fd, DKIOCGETBLOCKSIZE, &bs) < 0 || ioctl(fd, DKIOCGETBLOCKCOUNT, &bc) < 0) { if (!flag_quiet) perror("ioctl (get_fdinfo)"); return 0; } fd_info->size = bc*bs; printf("Size: %lld\n", fd_info->size); #else if (ioctl(fd, BLKGETSIZE64, &fd_info->size) < 0) { if (!flag_quiet) perror("ioctl (get_fdinfo)"); return 0; } #endif } else { fd_info->size = stat_buf.st_size; } #ifdef __APPLE__ fd_info->pos = vnodeInfo.pfi.fi_offset; gettimeofday(&fd_info->tv, &tz); #else fd_info->pos = 0; snprintf(fdpath, MAXPATHLEN, "%s/%d/fdinfo/%d", PROC_PATH, pid, fdnum); fp = fopen(fdpath, "rt"); gettimeofday(&fd_info->tv, &tz); if(!fp) { if (!flag_quiet) perror("fopen (get_fdinfo)"); return 0; } while(fgets(line, LINE_LEN - 1, fp) != NULL) { line[4]=0; if(!strcmp(line, "pos:")) { fd_info->pos = atoll(line + 5); break; } } #endif return 1; }
int main(int argc, char **argv) { int listenfd, n; struct sockaddr_in servaddr; void sig_chld(int); void sig_int(int); struct socket_fdinfo si; if (argc != 4) err_quit("Usage: %s <port> <#children> <#max>", basename(argv[0])); listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(atoi(argv[1])); Bind(listenfd, (SA *) & servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); maxconn = atoi(argv[3]); Pch = Calloc(maxconn, sizeof(struct child)); if ((nchildren = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) err_sys("mmap error"); if ((Pstat = mmap(0, sizeof(long) * maxconn, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) err_sys("mmap error"); minconn = *nchildren = atoi(argv[2]); if ((lock_fd = open("/tmp/lock.fd", O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) err_sys("open lock_fd error"); if (unlink("/tmp/lock.fd") < 0) err_sys("unlink error"); #if 0 Signal(SIGCHLD, sig_chld); /* must call waitpid() */ #endif _signal(SIGTERM, sig_term); int i, nsel; fd_set masterset, rset; FD_ZERO(&masterset); FD_SET(listenfd, &masterset); for (i = 0; i < *nchildren; i++) { /* parent prefork children */ child_make(i, listenfd); #if (_DEBUG) printf("%d status: %d\n", i, Pch[i].child_status); #endif } _signal(SIGINT, _sig_int); _signal(SIGCHLD, sig_chld); for (;;) { rset = masterset; if ((nsel = select(listenfd+1, &rset, NULL, NULL, NULL)) < 0) { if (errno == EINTR) continue; else err_sys("select error"); } else if (nsel == 0) { /* _no_ need */ err_msg("select timeout"); continue; } if ((n = proc_pidfdinfo(getpid(), listenfd, PROC_PIDFDSOCKETINFO, &si, sizeof(si))) <= 0) err_sys("proc_pidfdinfo error"); if (n < sizeof(si)) err_quit("proc_pidfdinfo failed"); /* * struct socket_info {} * soi_qlen: half-connction * soi_incqlen: incoming-connection * soi_rcv.sbi_cc: establish but not delivered connection * soi_snd.sbi_cc: send but not delivered connection */ mode_lock_wait(lock_fd); if (si.psi.soi_qlen + si.psi.soi_incqlen > 1 && *nchildren < maxconn && quitflag != 1) #if 0 if (si.psi.soi_rcv.sbi_cc + si.psi.soi_snd.sbi_cc > 0 && *nchildren < maxconn && !quitflag) #endif /* On BSD always 0 */ { for (i = 0; i < maxconn; i++) { if (Pch[i].child_status == 0) break; } child_make(i, listenfd); (*nchildren)++; } mode_lock_release(lock_fd); } exit(0); }