xref: /haiku/src/bin/ps.c (revision ca8ed5ea660fb6275799a3b7f138b201c41a667b)
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 
18 enum {
19 	Team = 0,
20 	Id,
21 	Threads,
22 	Gid,
23 	Uid
24 };
25 
26 struct 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
39 int Columns[maxColumns] = { Team, Id, Threads, Gid, Uid, 0 };
40 int ColumnsCount = 5;
41 
42 const char* sStates[] = {"run", "rdy", "msg", "zzz", "sus", "wait"};
43 
44 static void printTeamThreads(team_info* teamInfo, bool printSemaphoreInfo);
45 static void printTeamInfo(team_info* teamInfo, bool printHeader);
46 
47 
48 static void
49 printTeamInfo(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 
85 static void
86 printTeamThreads(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 
126 int
127 main(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