Ключевые слова:proc, vm, (найти похожие документы)
- RU.UNIX.BSD (2:5077/15.22) ------------------------------------ RU.UNIX.BSD -
From : Vadim Kolontsov 2:5020/400 27 Apr 00 15:50:40
Subj : Получить список процессов из C
-------------------------------------------------------------------------------
From: nospam.vadim@tversu.ru (Vadim Kolontsov)
Reply-To: nospam.vadim@tversu.ru
In article <gq4ggso087d7le5s4l931o80ahtmjt4v8d@4ax.com>, Yury Lazarev wrote:
>Каким образом можно вытащить командную строку, с которой были запущены
>процессы в Unix (наподобие того, что выдает команда ps).
в новых unix'ах для этого используется псевдо-FS: /proc. Там все просто:
cd /proc; ls -l; cd 3354; cat cmdline.. В Linux и PicoBSD, если мне память
не изменяет, 'ps' работает именно через /proc
Традиционно же ps (и другие подобные вещи, скажем, netstat или top)
делается через kernel virtual memory interface (KVM).
kvm позволяет получить доступ к памяти ядра, погулять по внутренним
структурам (например, списку процессов). Интерфейс прост: kvm_open и
kvm_openfiles (позволяющие открыть не только ядро в памяти, но и мертвое
ядро на диске); kvm_read, переносящая буфер произвольной длины из памяти
ядра ко мне в приложение; kvm_write, выполняющая обратные функции;
kvm_geterr (сообщение о произошедшей ошибке); kvm_close и прочее.
В ядре много интересной информации. Hо как узнать смещения этих
структур? С помощью kvm_nlist(3) (ее аналог для обычных файлов - nlist(3)).
kvm_nlist позволяет получить адреса символических переменных. Используя
эти адреса, мы считываем в нашу память содержимое областей памяти ядра.
Примерчик:
----------------------------------------------------------------------
/* Как посмотреть load average на Solaris'е прямо в ядре */
struct nlist nlst[] ={
{"avenrun"},
{0}
};
if (kvm_nlist(kd, nlst) == -1) {
(сообщаем об ошибке; exit())
}
if (nlst->n_type == 0) {
(сообщаем об ошибке; exit())
}
----------------------------------------------------------------------
После того, как адрес массива avenrun выяснен, мы можем прочитать его
в память:
----------------------------------------------------------------------
long avenrun[3];
if (kvm_read(kd, nlst->n_value, (char *)avenrun, sizeof(avenrun)) == -1) {
(сообщаем об ошибке; exit())
}
----------------------------------------------------------------------
FreeBSD несколько облегает работу с KVM/procs, вводя дополнительные
функции: kvm_getprocs, kvm_getargv etc.
Однако kvm_read() приходится использовать часто. Пусть мы хотим
выяснить, какие сетевые соединений какими процессами используется. Пишем:
----------------------------------------------------------------------
kp = kvm_getprocs(...KERN_PROC_ALL..., &cntproc);
for( i = 0; i < cntproc; i++) {
struct filedesc filedesc;
struct file **files;
struct file file;
int fileslen;
/* Список открытых файлов */
kvm_read(kd, kp[c].kp_proc.p_fd, &filedesc, sizeof(filedesc) ..)
fileslen = filedesc.fd_nfiles*sizeof(struct file *);
files = malloc(fileslen);
/* Загружаем массив указатель на fd'ы */
kvm_read(kd, filedesc.fd_ofiles, files, fileslen);
/* Пробегаем по файлам */
for (j = 0; j < filedesc.fd_nfiles; j++, files++) {
дальше загружаем структуру 'file' для каждого fd..
kvm_read(kd, *files, &file, sizeof(struct file));
выясняем тип fd:
if (file.f_type = DTYPE_SOCKET) ...
далее загружаем file.f_data как структуру socket,
для определения socket family загружаем socket.so_proto (protosw),
загружаем protosw.pr_domain и проверяем: domain.dom_faimyly == AF_INET
sock.so_type == SOCK_DGRAM/SOCK_STREAM;
далее загружаем protocol control block (pcb) - socket.so_pcb,
и так далее, пока не выясним все, что нам интересно..
довольно нудно, конечно; /proc - удобнее; но kvm дает доступ
к чему угодно!
}
}
----------------------------------------------------------------------
в 97-м году я кидал такую программку в freebsd-hackers как пример
использования KVM. Пример вывода:
21319 tcp:ESTABLISHED aa.bb.cc.dd:1339 aa.bb.dd.ee:119
451 tcp:LISTEN aa.bb.cc.dd:80 *:*
6622 udp *:NNNN *:*
и т.д...
>Может быть кто-нибудь подскажет, как это проще сделать?
kvm_getargv() возвращает массив (а-ля argv[]), в которым указаны
параметры запуска (= командная строка). ps использует именно kvm_getargv().
Можно извлечь те же данные и руками - через kvm_read() (см. описание
структуры proc).
char **a;
a = kvm_getargv(...)
if (a) while (*a) printf("%s ", *a++);
>Пытался разобраться с исходниками ps - дохлый номер (маловато знаний).
упорство и упорство - и все получится :)
>В man как-то весьма невнятно описаны функции kvm. Где бы найти
>какое-нибудь более подробное описание, желательно с примерами.
4.4BSD Daemon Book, исходники ядра, исходные тексты программ...
V.
P.S. KVM в man pages описан нормально :)
--- ifmail v.2.15dev5 * Origin: Tver State University NOC (2:5020/400)