···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2013 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include "proc.h"
2121+#include <fstream>
2222+#include <sstream>
2323+#include <string>
2424+#include <errno.h>
2525+#include <unistd.h>
2626+#include <cstring>
2727+#include <dirent.h>
2828+#include <sys/stat.h>
2929+#include <sys/types.h>
3030+#include <sys/syscall.h>
3131+#include <ctype.h>
3232+#include <string>
3333+#include <memory>
3434+#include "../libc/darwin_errno_codes.h"
3535+#include "../libc/errno.h"
3636+3737+static std::string getProcStatElement(const char* pid, int elem);
3838+static int sys_syslog(int type, char *bufp, int len); /* No wrapper provided in glibc */
3939+4040+int proc_name(int pid, void * buffer, uint32_t buffersize)
4141+{
4242+ std::stringstream path;
4343+ std::ifstream procf;
4444+ char procname[1024];
4545+ size_t read;
4646+4747+ path << "/proc/" << pid << "/cmdline";
4848+ procf.open(path.str().c_str());
4949+5050+ if (!procf.is_open())
5151+ {
5252+ errno = DARWIN_ENOENT;
5353+ return 0;
5454+ }
5555+5656+ procf.read(procname, sizeof procname);
5757+ read = procf.gcount();
5858+5959+ for (size_t i = 0; i < read-1; i++)
6060+ {
6161+ if (!procname[i])
6262+ procname[i] = ' ';
6363+ }
6464+6565+ if (buffer)
6666+ {
6767+ if (buffersize >= read)
6868+ {
6969+ memcpy(buffer, procname, read);
7070+ return read;
7171+ }
7272+ else
7373+ {
7474+ *((char*) buffer) = 0;
7575+ return 0;
7676+ }
7777+ }
7878+7979+ return 0;
8080+}
8181+8282+int proc_pidpath(int pid, void * buffer, uint32_t buffersize)
8383+{
8484+ std::stringstream path;
8585+ char exe[1024];
8686+ ssize_t len;
8787+8888+ path << "/proc/" << pid << "/exe";
8989+9090+ if (access(path.str().c_str(), F_OK) != 0)
9191+ {
9292+ errno = DARWIN_ENOENT;
9393+ return 0;
9494+ }
9595+9696+ len = readlink(path.str().c_str(), exe, sizeof(exe)-1);
9797+ if (len < 0)
9898+ {
9999+ errnoOut();
100100+ return 0;
101101+ }
102102+ exe[len] = 0;
103103+104104+ if (buffer && buffersize >= len+1)
105105+ {
106106+ memcpy(buffer, exe, len+1);
107107+ return len+1;
108108+ }
109109+110110+ return 0;
111111+}
112112+113113+int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize)
114114+{
115115+ // TODO
116116+ return 0;
117117+}
118118+119119+int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)
120120+{
121121+ // buffer is an array of pid_t
122122+ pid_t* pidOut = static_cast<pid_t*>(buffer);
123123+ DIR* dirProc = opendir("/proc");
124124+ const uid_t uid = getuid();
125125+ int count = 0;
126126+127127+ if (!dirProc)
128128+ return 0;
129129+130130+ while (struct dirent* ent = readdir(dirProc))
131131+ {
132132+ if (!isdigit(ent->d_name[0]))
133133+ continue;
134134+135135+ bool pass;
136136+137137+ if (type == PROC_ALL_PIDS)
138138+ pass = true;
139139+ else if (type == PROC_UID_ONLY || type == PROC_RUID_ONLY) // not sure what to do with PROC_RUID_ONLY
140140+ {
141141+ char path[100];
142142+ struct stat st;
143143+144144+ strcpy(path, "/proc/");
145145+ strcat(path, ent->d_name);
146146+ strcat(path, "/cmdline");
147147+148148+ if (stat(path, &st) == -1)
149149+ continue;
150150+151151+ pass = st.st_uid == uid;
152152+ }
153153+ else if (type == PROC_PGRP_ONLY)
154154+ {
155155+ std::string grp = getProcStatElement(ent->d_name, 4);
156156+ if (atoi(grp.c_str()) == typeinfo)
157157+ pass = true;
158158+ }
159159+ else if (type == PROC_TTY_ONLY)
160160+ {
161161+ std::string grp = getProcStatElement(ent->d_name, 6);
162162+ if (atoi(grp.c_str()) == typeinfo)
163163+ pass = true;
164164+ }
165165+ else
166166+ return 0;
167167+168168+ if (pidOut && count < buffersize / sizeof(pid_t))
169169+ pidOut[count++] = atoi(ent->d_name);
170170+ }
171171+172172+ closedir(dirProc);
173173+174174+ return count*sizeof(pid_t);
175175+}
176176+177177+int proc_pidfdinfo(int pid, int fd, int flavor, void* buffer, int buffersize)
178178+{
179179+ // TODO
180180+ return 0;
181181+}
182182+183183+int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
184184+{
185185+ std::ifstream file;
186186+ std::string line;
187187+ std::stringstream fname;
188188+189189+ fname << "/proc/" << pid << "/maps";
190190+ file.open(fname.str().c_str());
191191+192192+ if (!file.is_open())
193193+ return 0;
194194+195195+ while (std::getline(file, line))
196196+ {
197197+ if (line.empty()) continue;
198198+199199+ const char* s = line.c_str();
200200+ uint64_t start, end;
201201+202202+ start = strtoll(s, (char**) &s, 16);
203203+ s++;
204204+ end = strtoll(s, (char**) &s, 16);
205205+206206+ if (address >= start && address < end)
207207+ {
208208+ if (line.size() > 74)
209209+ {
210210+ const char* file = line.c_str()+73;
211211+212212+ strncpy((char*) buffer, file, buffersize-1);
213213+ *((char*) buffer + buffersize) = 0;
214214+215215+ return strlen((char*) buffer) + 1;
216216+ }
217217+ else
218218+ {
219219+ *((char*) buffer) = 0;
220220+ return 1;
221221+ }
222222+ }
223223+224224+ }
225225+ return 0;
226226+}
227227+228228+int proc_kmsgbuf(void* buffer, uint32_t buffersize)
229229+{
230230+ if (buffer)
231231+ {
232232+ int rv = sys_syslog(/*SYSLOG_ACTION_READ_ALL*/ 3, static_cast<char*>(buffer), buffersize);
233233+ if (rv == -1)
234234+ {
235235+ errnoOut();
236236+ return 0;
237237+ }
238238+ else
239239+ return rv;
240240+ }
241241+242242+ return 0;
243243+}
244244+245245+int proc_libversion(int *major, int * minor)
246246+{
247247+ if (major)
248248+ *major = 1;
249249+ if (minor)
250250+ *minor = 1;
251251+ return 0;
252252+}
253253+254254+int proc_setpcontrol(const int control)
255255+{
256256+ // TODO: specify options how to react on resource starvation
257257+ // Doable on Linux?
258258+ return 0;
259259+}
260260+261261+int proc_listpidspath(uint32_t type, uint32_t typeInfo, const char* path, uint32_t pathFlags, void* buffer, int buffersize)
262262+{
263263+ // fuser-like functionality
264264+ std::unique_ptr<pid_t[]> pids(new pid_t[4096]);
265265+ int count = 0;
266266+ int npids;
267267+ dev_t devid;
268268+269269+ auto AddElem = [&](pid_t pid) -> void
270270+ {
271271+ if (buffer)
272272+ {
273273+ pid_t* p = static_cast<pid_t*>(buffer);
274274+ if (buffersize/sizeof(pid_t) >= (count+1))
275275+ p[count++] = pid;
276276+ }
277277+ };
278278+279279+ if (pathFlags & PROC_LISTPIDSPATH_PATH_IS_VOLUME)
280280+ {
281281+ struct stat st;
282282+ if (stat(path, &st) == -1)
283283+ return 0;
284284+ devid = st.st_dev;
285285+ }
286286+287287+ npids = proc_listpids(type, typeInfo, pids.get(), 4096*sizeof(pid_t));
288288+289289+ for (int i = 0; i < npids/sizeof(pid_t); i++)
290290+ {
291291+ char dpath[100];
292292+ DIR* dir;
293293+ struct dirent* ent;
294294+ int orig;
295295+296296+ sprintf(dpath, "/proc/%d/fd/", pids[i]);
297297+ orig = strlen(dpath);
298298+ dir = opendir(dpath);
299299+300300+ if (!dir)
301301+ continue;
302302+303303+ while ((ent = readdir(dir)))
304304+ {
305305+ if (ent->d_name[0] == '.')
306306+ continue;
307307+308308+ strcat(dpath, ent->d_name);
309309+310310+ if (pathFlags & PROC_LISTPIDSPATH_PATH_IS_VOLUME) // like `fuser -m`
311311+ {
312312+ struct stat st;
313313+ int rv;
314314+315315+ rv = stat(dpath, &st);
316316+ dpath[orig] = 0;
317317+318318+ if (rv == -1)
319319+ continue;
320320+321321+ if (st.st_dev == devid)
322322+ AddElem(pids[i]);
323323+ }
324324+ else // like `fuser`
325325+ {
326326+ char lpath[PATH_MAX];
327327+ ssize_t bytes;
328328+329329+ bytes = readlink(dpath, lpath, sizeof(lpath));
330330+ dpath[orig] = 0;
331331+332332+ if (bytes < 0)
333333+ continue;
334334+335335+ lpath[bytes] = 0;
336336+337337+ if (strcmp(lpath, path) == 0)
338338+ AddElem(pids[i]);
339339+ }
340340+ }
341341+342342+ closedir(dir);
343343+ }
344344+345345+ return count*sizeof(pid_t);
346346+}
347347+348348+std::string getProcStatElement(const char* pid, int elem)
349349+{
350350+ char path[100] = "/proc/";
351351+ std::ifstream file;
352352+ std::string result;
353353+354354+ strcat(path, pid);
355355+ strcat(path, "/stat");
356356+357357+ file.open(path);
358358+359359+ if (!file.is_open())
360360+ return std::string();
361361+362362+ for (int p = 0; p <= elem; p++)
363363+ {
364364+ int par = 0;
365365+ while (true)
366366+ {
367367+ int c = file.get();
368368+ if (!par && c == ' ')
369369+ break;
370370+ if (par == 2 && c == ')')
371371+ {
372372+ file.get();
373373+ break;
374374+ }
375375+ if (!par && c == '(')
376376+ par = 2;
377377+ else
378378+ {
379379+ par = 1;
380380+ result += char(c);
381381+ }
382382+ }
383383+ }
384384+385385+ return result;
386386+}
387387+388388+int sys_syslog(int type, char *bufp, int len)
389389+{
390390+ return syscall(SYS_syslog, type, bufp, len);
391391+}
392392+
+98
src/libSystem/kernel-bsd/proc.h
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2013 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef MACH_PROC_H
2121+#define MACH_PROC_H
2222+#include <stdint.h>
2323+2424+extern "C"
2525+{
2626+2727+// For proc_listpidspath
2828+#define PROC_LISTPIDSPATH_PATH_IS_VOLUME 1
2929+#define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY 2 // exclude O_EVTONLY fds, not doable on Linux (no O_EVTONLY on Linux)
3030+3131+// For proc_listpids
3232+#define PROC_ALL_PIDS 1
3333+#define PROC_PGRP_ONLY 2
3434+#define PROC_TTY_ONLY 3
3535+#define PROC_UID_ONLY 4
3636+#define PROC_RUID_ONLY 5
3737+3838+ int proc_name(int pid, void* buffer, uint32_t buffersize);
3939+ int proc_pidpath(int pid, void* buffer, uint32_t buffersize);
4040+ int proc_pidinfo(int pid, int flavor, uint64_t arg, void* buffer, int buffersize);
4141+ int proc_listpids(uint32_t type, uint32_t typeinfo, void* buffer, int buffersize);
4242+ int proc_pidfdinfo(int pid, int fd, int flavor, void* buffer, int buffersize);
4343+ int proc_regionfilename(int pid, uint64_t address, void* buffer, uint32_t buffersize);
4444+ int proc_kmsgbuf(void* buffer, uint32_t buffersize);
4545+ int proc_libversion(int* major, int* minor);
4646+ int proc_setpcontrol(const int control);
4747+ int proc_listpidspath(uint32_t type, uint32_t typeInfo, const char* path, uint32_t pathFlags, void* buffer, int buffersize);
4848+4949+ struct proc_taskinfo
5050+ {
5151+ uint64_t pti_virtual_size,
5252+ pti_resident_size,
5353+ pti_total_user,
5454+ pti_total_system,
5555+ pti_threads_user,
5656+ pti_threads_system;
5757+ int32_t pti_policy,
5858+ pti_faults,
5959+ pti_pageins,
6060+ pti_cow_faults,
6161+ pti_messages_sent,
6262+ pti_messages_received,
6363+ pti_syscalls_mach,
6464+ pti_syscalls_unix,
6565+ pti_csw,
6666+ pti_threadnum,
6767+ pti_numrunning,
6868+ pti_priority;
6969+ };
7070+7171+ struct proc_regioninfo
7272+ {
7373+ uint32_t pri_protection,
7474+ pri_max_protection,
7575+ pri_inheritance,
7676+ pri_flags;
7777+ uint64_t pri_offset;
7878+ uint32_t pri_behavior,
7979+ pri_user_wired_count,
8080+ pri_user_tag,
8181+ pri_pages_resident,
8282+ pri_pages_shared_now_private,
8383+ pri_pages_swapped_out,
8484+ pri_pages_dirtied,
8585+ pri_ref_count,
8686+ pri_shadow_depth,
8787+ pri_share_mode,
8888+ pri_private_pages_resident,
8989+ pri_shared_pages_resident,
9090+ pri_obj_id,
9191+ pri_depth;
9292+ uint64_t pri_address,
9393+ pri_size;
9494+ };
9595+}
9696+9797+#endif
9898+