Добавим новые записи в учетный файл, запустив еще несколько команд:
$ sleep 15 &
[1] 18063
$ ulimit — c unlimited
$ cat
Quit (core dumped)
$
[1]+ Done sleep 15
$ grep xxx badfile
grep: badfile: No such file or directory
$ echo $?
2
Следующие две команды запускают программы, представленные в предыдущих главах (листинги 27.1 и 24.1). Первая из них выполняет файл /bin/echo, в результате чего в учетный файл попадает запись о процессе с именем echo. Вторая создает дочерний процесс, который не выполняет вызов exec().
$ ./t_execve /bin/echo
hello world goodbye
$ ./t_fork
PID=18350 (child) idata=333 istack=666
PID=18349 (parent) idata=111 istack=222
Наконец, выведем содержимое учетного файла, воспользовавшись программой из листинга 28.2:
$ ./acct_view pacct
Command flags term. user start time CPU elapsed
status time time
acct_on — S- 0 root 2010-07-23 17:19:05 0.00 0.00
bash — 0 root 2010-07-23 17:18:55 0.02 21.10
su — S- 0 root 2010-07-23 17:18:51 0.01 24.94
cat — XC 0x83 mtk 2010-07-23 17:19:55 0.00 1.72
sleep — 0 mtk 2010-07-23 17:19:42 0.00 15.01
grep — 0x200 mtk 2010-07-23 17:20:12 0.00 0.00
echo — 0 mtk 2010-07-23 17:21:15 0.01 0.01
t_fork F- 0 mtk 2010-07-23 17:21:36 0.00 0.00
t_fork — 0 mtk 2010-07-23 17:21:36 0.00 3.01
В вышеприведенном выводе для каждого процесса, созданного в сессии командной оболочки, выделяется отдельная строка. Команды ulimit и echo встроены в оболочку, поэтому они не приводят к созданию новых процессов. Обратите внимание на то, что команда sleep идет после записи с командой cat, потому что именно в таком порядке они были завершены.
Большая часть этого вывода не нуждается в дополнительных объяснениях. Столбец flags хранит одиночные буквы, указывая на то, какие биты ac_flag установлены для каждой записи (см. табл. 28.1). О том, как интерпретировать значения кода завершения, хранящиеся в столбце term. status, шла речь в подразделе 26.1.3.
Листинг 28.2. Вывод данных из учетного файла
procexec/acct_view.c
#include
#include
#include
#include
#include
#include "ugid_functions.h" /* Объявление функции userNameFromId() */
#include "tlpi_hdr.h"
#define TIME_BUF_SIZE 100
static long long /* Приводим значение comp_t к типу long long */
comptToLL(comp_t ct)
{
const int EXP_SIZE = 3; /* Трехбитная экспонента с основанием 8 */
const int MANTISSA_SIZE = 13; /* За ней следует 13-битная мантисса */
const int MANTISSA_MASK = (1 << MANTISSA_SIZE) — 1;
long long mantissa, exp;
mantissa = ct & MANTISSA_MASK;
exp = (ct >> MANTISSA_SIZE) & ((1 << EXP_SIZE) — 1);
return mantissa << (exp * 3); /* Степень 8 означает сдвиг влево на три бита */
}
int
main(int argc, char *argv[])
{
int acctFile;
struct acct ac;
ssize_t numRead;
char *s;
char timeBuf[TIME_BUF_SIZE];
struct tm *loc;
time_t t;
if (argc!= 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s file\n", argv[0]);
acctFile = open(argv[1], O_RDONLY);
if (acctFile == –1)
errExit("open");
printf("command flags term. user "
"start time CPU elapsed\n");
printf(" status "
" time time\n");
while ((numRead = read(acctFile, ∾, sizeof(struct acct))) > 0) {
if (numRead!= sizeof(struct acct))
fatal("partial read");
printf("%-8.8s", ac.ac_comm);
printf("%c", (ac.ac_flag & AFORK)? 'F': '-');
printf("%c", (ac.ac_flag & ASU)? 'S': '-');
printf("%c", (ac.ac_flag & AXSIG)? 'X': '-');
printf("%c", (ac.ac_flag & ACORE)? 'C': '-');
#ifdef __linux__
printf(" %#6lx", (unsigned long) ac.ac_exitcode);
#else
/* Во многих других реализациях вместо этого предоставляется поле ac_stat */
printf(" %#6lx", (unsigned long) ac.ac_stat);
#endif
s = userNameFromId(ac.ac_uid);
printf("%-8.8s", (s == NULL)?"???": s);
t = ac.ac_btime;
loc = localtime(&t);
if (loc == NULL) {
printf("???Unknown time??? ");
} else {
strftime(timeBuf, TIME_BUF_SIZE, "%Y-%m-%d %T", loc);
printf("%s", timeBuf);
}
printf("%5.2f %7.2f", (double) (comptToLL(ac.ac_utime) +
comptToLL(ac.ac_stime)) / sysconf(_SC_CLK_TCK), (double)
comptToLL(ac.ac_etime) / sysconf(_SC_CLK_TCK));
printf("\n");
}
if (numRead == –1)
errExit("read");
exit(EXIT_SUCCESS);
}
procexec/acct_view.c