1/*
2 * Copyright 2002-2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Francois Revol (mmu_man)
7 *		Salvatore Benedetto <salvatore.benedetto@gmail.com>
8 *		Bjoern Herzig (xRaich[o]2x)
9 *		Thomas Schmidt <thomas.compix@googlemail.com>
10 */
11#include <stdio.h>
12#include <unistd.h>
13#include <string.h>
14
15#include <OS.h>
16
17
18enum {
19	Team = 0,
20	Id,
21	Threads,
22	Gid,
23	Uid
24};
25
26struct ColumnIndo {
27	const char* name;
28	const char* header;
29	const char* format;
30} Infos[] = {
31	{ "Team",		"%-50s",	"%-50s"  },
32	{ "Id",			"%5s",		"%5" B_PRId32  },
33	{ "Threads",	"#%7s",		"%8" B_PRId32 },
34	{ "Gid",		"%4s",		"%4d" },
35	{ "Uid",		"%4s",		"%4d" }
36};
37
38#define maxColumns  10
39int Columns[maxColumns] = { Team, Id, Threads, Gid, Uid, 0 };
40int ColumnsCount = 5;
41
42const char* sStates[] = {"run", "rdy", "msg", "zzz", "sus", "wait"};
43
44static void printTeamThreads(team_info* teamInfo, bool printSemaphoreInfo);
45static void printTeamInfo(team_info* teamInfo, bool printHeader);
46
47
48static void
49printTeamInfo(team_info* teamInfo, bool printHeader)
50{
51	int i = 0;
52	if (printHeader) {
53		for (i = 0; i < ColumnsCount; i++) {
54			printf(Infos[Columns[i]].header, Infos[Columns[i]].name);
55			putchar(' ');
56		}
57		puts("");
58	}
59
60
61	for (i = 0; i < ColumnsCount; i++) {
62		switch (Columns[i]) {
63			case Team:
64				printf(Infos[Team].format, teamInfo->args);
65				break;
66			case Id:
67				printf(Infos[Id].format, teamInfo->team);
68				break;
69			case Threads:
70				printf(Infos[Threads].format, teamInfo->thread_count);
71				break;
72			case Gid:
73				printf(Infos[Gid].format, teamInfo->gid);
74				break;
75			case Uid:
76				printf(Infos[Uid].format, teamInfo->uid);
77				break;
78		}
79		putchar(' ');
80	}
81	puts("");
82}
83
84
85static void
86printTeamThreads(team_info* teamInfo, bool printSemaphoreInfo)
87{
88	const char* threadState;
89	int32 threadCookie = 0;
90	sem_info semaphoreInfo;
91	thread_info threadInfo;
92
93	// Print all info about its threads too
94	while (get_next_thread_info(teamInfo->team, &threadCookie, &threadInfo)
95		>= B_OK) {
96		if (threadInfo.state < B_THREAD_RUNNING
97			|| threadInfo.state > B_THREAD_WAITING)
98			// This should never happen
99			threadState = "???";
100		else
101			threadState = sStates[threadInfo.state - 1];
102
103		printf("%-37s %5" B_PRId32 " %8s %4" B_PRId32 " %8" B_PRIu64 " %8"
104			B_PRId64 " ", threadInfo.name, threadInfo.thread, threadState,
105			threadInfo.priority, (threadInfo.user_time / 1000),
106			(threadInfo.kernel_time / 1000));
107
108		if (printSemaphoreInfo) {
109			if (threadInfo.state == B_THREAD_WAITING && threadInfo.sem != -1) {
110				status_t status = get_sem_info(threadInfo.sem, &semaphoreInfo);
111				if (status == B_OK) {
112					printf("%s(%" B_PRId32 ")\n", semaphoreInfo.name,
113						semaphoreInfo.sem);
114				} else {
115					printf("%s(%" B_PRId32 ")\n", strerror(status),
116						threadInfo.sem);
117				}
118			} else
119				puts("");
120		} else
121			puts("");
122	}
123}
124
125
126int
127main(int argc, char** argv)
128{
129	team_info teamInfo;
130	int32 teamCookie = 0;
131	system_info systemInfo;
132	bool printSystemInfo = false;
133	bool printThreads = false;
134	bool printHeader = true;
135	bool printSemaphoreInfo = false;
136	bool customizeColumns = false;
137	// match this in team name
138	char* string_to_match;
139
140	int c;
141
142	while ((c = getopt(argc, argv, "-ihaso:")) != EOF) {
143		switch (c) {
144			case 'i':
145				printSystemInfo = true;
146				break;
147			case 'h':
148				printf( "usage: ps [-hais] [-o columns list] [team]\n"
149						"-h : show help\n"
150						"-i : show system info\n"
151						"-s : show semaphore info\n"
152						"-o : display team info associated with the list\n"
153						"-a : show threads too (by default only teams are "
154							"displayed)\n");
155				return 0;
156				break;
157			case 'a':
158				printThreads = true;
159				break;
160			case 's':
161				printSemaphoreInfo = true;
162				break;
163			case 'o':
164				if (!customizeColumns)
165					ColumnsCount = 0;
166				customizeColumns = true;
167				/* fallthrough */
168			case 1:
169			{
170				size_t i = 0;
171				if (c == 1 && !customizeColumns)
172					break;
173				for (i = 0; i < sizeof(Infos) / sizeof(Infos[0]); i++)
174					if (strcmp(optarg, Infos[i].name) == 0
175							&& ColumnsCount < maxColumns) {
176						Columns[ColumnsCount++] = i;
177						continue;
178					}
179				break;
180			}
181		}
182	}
183
184	// TODO: parse command line
185	// Possible command line options:
186	//      -t  pstree like output
187
188	if (argc == 2 && (printSystemInfo || printThreads))
189		string_to_match = NULL;
190	else
191		string_to_match = (argc >= 2 && !customizeColumns)
192			? argv[argc - 1] : NULL;
193
194	if (!string_to_match) {
195		while (get_next_team_info(&teamCookie, &teamInfo) >= B_OK) {
196			printTeamInfo(&teamInfo, printHeader);
197			printHeader = false;
198			if (printThreads) {
199				printf("\n%-37s %5s %8s %4s %8s %8s\n", "Thread", "Id", \
200					"State", "Prio", "UTime", "KTime");
201				printTeamThreads(&teamInfo, printSemaphoreInfo);
202				printf("----------------------------------------------" \
203					"-----------------------------\n");
204				printHeader = true;
205			}
206		}
207	} else {
208		while (get_next_team_info(&teamCookie, &teamInfo) >= B_OK) {
209			char* p = teamInfo.args;
210			if ((p = strchr(p, ' ')))
211				*p = '\0'; /* remove arguments, keep only argv[0] */
212			p = strrchr(teamInfo.args, '/'); /* forget the path */
213			if (p == NULL)
214				p = teamInfo.args;
215			if (strstr(p, string_to_match) == NULL)
216				continue;
217			printTeamInfo(&teamInfo, true);
218			printf("\n%-37s %5s %8s %4s %8s %8s\n", "Thread", "Id", "State", \
219				"Prio", "UTime", "KTime");
220			printTeamThreads(&teamInfo, printSemaphoreInfo);
221		}
222	}
223
224	if (printSystemInfo) {
225		// system stats
226		get_system_info(&systemInfo);
227		printf("\nSystem Info\n");
228		printf("%" B_PRIu64 "k (%" B_PRIu64 " bytes) total memory\n",
229			(systemInfo.max_pages * B_PAGE_SIZE / 1024),
230			(systemInfo.max_pages * B_PAGE_SIZE));
231		printf("%" B_PRIu64 "k (%" B_PRIu64 " bytes) currently committed\n",
232			(systemInfo.used_pages * B_PAGE_SIZE / 1024),
233			(systemInfo.used_pages * B_PAGE_SIZE));
234		printf("%" B_PRIu64 "k (%" B_PRIu64 " bytes) currently available\n",
235			(systemInfo.max_pages - systemInfo.used_pages) * B_PAGE_SIZE / 1024,
236			(systemInfo.max_pages - systemInfo.used_pages) * B_PAGE_SIZE);
237		printf("%2.1f%% memory utilisation\n",
238			(float)100 * systemInfo.used_pages / systemInfo.max_pages);
239	}
240	return 0;
241}
242