Minor changes.
[reactos.git] / reactos / subsys / system / shell / shell.c
1 /* $Id: shell.c,v 1.7 2001/07/30 11:50:44 ea Exp $
2 *
3 * PROJECT : ReactOS Operating System
4 * DESCRIPTION: ReactOS' Native Shell
5 * LICENSE : See top level directory
6 *
7 */
8 #define NTOS_MODE_USER
9 #include <ntos.h>
10 #include <windows.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16
17
18 HANDLE InputHandle, OutputHandle;
19 BOOL bCanExit = TRUE;
20
21
22 void debug_printf(char* fmt, ...)
23 {
24 va_list args;
25 char buffer[512];
26 DWORD nbChar;
27
28 va_start(args,fmt);
29 _vsnprintf(buffer,512,fmt,args);
30 va_end(args);
31 WriteConsoleA(OutputHandle, buffer, strlen(buffer), &nbChar, NULL);
32 }
33
34
35 void ExecuteVer(void)
36 {
37 debug_printf(
38 "Reactos Simple Shell\n(compiled on %s, at %s)\n",
39 __DATE__,
40 __TIME__
41 );
42 }
43
44 void ExecuteCd(char* cmdline)
45 {
46 if (!SetCurrentDirectoryA(cmdline))
47 {
48 debug_printf("Invalid directory\n");
49 }
50 }
51
52 void ExecuteMd (char *cmdline)
53 {
54 if (!CreateDirectoryA (cmdline, NULL))
55 {
56 debug_printf("Create Directory failed!\n");
57 }
58 }
59
60 void ExecuteDir(char* cmdline)
61 {
62 HANDLE shandle;
63 WIN32_FIND_DATA FindData;
64 int nFile=0, nRep=0;
65 FILETIME fTime;
66 SYSTEMTIME sTime;
67
68 shandle = FindFirstFile("*",&FindData);
69
70 if (shandle==INVALID_HANDLE_VALUE)
71 {
72 debug_printf("File not found\n\n");
73 return;
74 }
75 do
76 {
77 debug_printf("%-15.15s",FindData.cAlternateFileName);
78 if(FindData.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
79 debug_printf("<DIR> "),nRep++;
80 else
81 debug_printf(" %10d ",FindData.nFileSizeLow),nFile++;
82
83 FileTimeToLocalFileTime(&FindData.ftLastWriteTime ,&fTime);
84 FileTimeToSystemTime(&fTime, &sTime);
85 debug_printf("%02d/%02d/%04d %02d:%02d:%02d "
86 ,sTime.wMonth,sTime.wDay,sTime.wYear
87 ,sTime.wHour,sTime.wMinute,sTime.wSecond);
88
89 debug_printf("%s\n",FindData.cFileName);
90 } while(FindNextFile(shandle,&FindData));
91 debug_printf("\n %d files\n %d directories\n\n",nFile,nRep);
92 FindClose(shandle);
93 }
94
95
96 void ExecuteReboot(char* cmdline)
97 {
98 NtShutdownSystem (ShutdownReboot);
99 }
100
101
102 void ExecuteShutdown(char* cmdline)
103 {
104 NtShutdownSystem (ShutdownNoReboot);
105 }
106
107
108 void ExecuteType(char* cmdline)
109 {
110 HANDLE FileHandle;
111 char c;
112 DWORD Result;
113
114 FileHandle = CreateFile(cmdline,
115 FILE_GENERIC_READ,
116 0,
117 NULL,
118 OPEN_EXISTING,
119 0,
120 NULL);
121 if (FileHandle == NULL)
122 {
123 debug_printf("Unknown file\n");
124 return;
125 }
126 while (ReadFile(FileHandle,
127 &c,
128 1,
129 &Result,
130 NULL))
131 {
132 debug_printf("%c",c);
133 c = 0;
134 }
135 CloseHandle(FileHandle);
136 }
137
138 int ExecuteProcess(char* name, char* cmdline, BOOL detached)
139 {
140 PROCESS_INFORMATION ProcessInformation;
141 STARTUPINFO StartupInfo;
142 BOOL ret;
143 CHAR fullname[260];
144 PCHAR p;
145
146 /* append '.exe' if needed */
147 strcpy (fullname, name);
148 p = strrchr (fullname, '.');
149 if ((p == NULL) ||
150 (_stricmp (p, ".exe") != 0))
151 {
152 strcat (fullname, ".exe");
153 }
154
155 memset(&StartupInfo, 0, sizeof(StartupInfo));
156 StartupInfo.cb = sizeof (STARTUPINFO);
157 StartupInfo.lpTitle = name;
158 if( cmdline && *cmdline )
159 *(cmdline-1) = ' '; // fix command line so it is the FULL command, including exe name
160 ret = CreateProcessA(fullname,
161 name,
162 NULL,
163 NULL,
164 FALSE,
165 ((TRUE == detached)
166 ? CREATE_NEW_CONSOLE
167 : 0
168 ),
169 NULL,
170 NULL,
171 & StartupInfo,
172 & ProcessInformation
173 );
174 if (TRUE == detached)
175 {
176 if (ret)
177 {
178 debug_printf("\"%s\" detached:\n"
179 "\thProcess = %08X\n"
180 "\thThread = %08X\n"
181 "\tPID = %d\n"
182 "\tTID = %d\n\n",
183 fullname,
184 ProcessInformation.hProcess,
185 ProcessInformation.hThread,
186 ProcessInformation.dwProcessId,
187 ProcessInformation.dwThreadId);
188 CloseHandle(ProcessInformation.hProcess);
189 CloseHandle(ProcessInformation.hThread);
190 }
191 else
192 {
193 debug_printf("Could not detach %s\n", name);
194 }
195 }
196 else
197 {
198 if (ret)
199 {
200 // debug_printf("ProcessInformation.hThread %x\n",
201 // ProcessInformation.hThread);
202 WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
203 CloseHandle(ProcessInformation.hProcess);
204 // debug_printf("Thandle %x\n", ProcessInformation.hThread);
205 CloseHandle(ProcessInformation.hThread);
206 }
207 }
208 return(ret);
209 }
210
211 void ExecuteStart(char* CommandLine)
212 {
213 char *ImageName = CommandLine;
214
215 for ( ;
216 ( (*CommandLine)
217 && (*CommandLine != ' ')
218 && (*CommandLine != '\t')
219 );
220 CommandLine++
221 );
222 *CommandLine++ = '\0';
223 while ( (*CommandLine)
224 && ( (*CommandLine == ' ')
225 || (*CommandLine == '\t')
226 )
227 );
228 ExecuteProcess(
229 ImageName,
230 CommandLine,
231 TRUE
232 );
233 return;
234 }
235
236 void
237 ExecuteKill(char * lpPid)
238 {
239 HANDLE hProcess;
240 DWORD dwProcessId;
241
242 dwProcessId = (DWORD) atol(lpPid);
243 debug_printf("Killing PID %d...\n",dwProcessId);
244 hProcess = OpenProcess(
245 PROCESS_TERMINATE,
246 FALSE,
247 dwProcessId
248 );
249 if (NULL == hProcess)
250 {
251 debug_printf(
252 "Could not open the process with PID = %d\n",
253 dwProcessId
254 );
255 return;
256 }
257 if (FALSE == TerminateProcess(
258 hProcess,
259 0
260 )
261 ) {
262 debug_printf(
263 "Could not terminate the process with PID = %d\n",
264 dwProcessId
265 );
266 }
267 CloseHandle(hProcess);
268 return;
269 }
270
271 void ExecuteHelp (void * dummy)
272 {
273 debug_printf (
274 "A:\t\t\tCurrent drive is A:\n"
275 "C:\t\t\tCurrent drive is C:\n"
276 "cd [directory]\t\tChange current directory\n"
277 "dir [directory]\t\tList directory\n"
278 "exit\t\t\tTerminate the shell\n"
279 "help\t\t\tPrint this help message\n"
280 "kill [pid]\t\tKill process which PID is pid\n"
281 "md [directory]\t\tCreate a new directory\n"
282 "reboot\t\t\tRestart the system\n"
283 "start [program.exe]\tDetach program.exe\n"
284 "type [file]\t\tPrint the file on console\n"
285 "validate\t\tValidate the process' heap\n"
286 "ver\t\t\tPrint version information\n"
287 "[program.exe]\t\tStart synchronously program.exe\n\n"
288 );
289 }
290
291 void ExecuteCommand(char* line)
292 {
293 char* cmd;
294 char* tail;
295
296 if (isalpha(line[0]) && line[1] == ':' && line[2] == 0)
297 {
298 char szPath[MAX_PATH];
299 char szVar[5];
300
301 /* save curent directory in environment variable */
302 GetCurrentDirectory (MAX_PATH, szPath);
303
304 strcpy (szVar, "=A:");
305 szVar[1] = toupper (szPath[0]);
306 SetEnvironmentVariable (szVar, szPath);
307
308 /* check for current directory of new drive */
309 strcpy (szVar, "=A:");
310 szVar[1] = toupper (line[0]);
311 if (GetEnvironmentVariable (szVar, szPath, MAX_PATH) == 0)
312 {
313 /* no environment variable found */
314 strcpy (szPath, "A:\\");
315 szPath[0] = toupper (line[0]);
316 }
317
318 /* set new current directory */
319 SetCurrentDirectory (szPath);
320 GetCurrentDirectory (MAX_PATH, szPath);
321 if (szPath[0] != (char)toupper (line[0]))
322 debug_printf("Invalid drive\n");
323
324 return;
325 }
326
327 tail = line;
328 while ((*tail)!=' ' && (*tail)!=0)
329 {
330 tail++;
331 }
332 if ((*tail)==' ')
333 {
334 *tail = 0;
335 tail++;
336 }
337 cmd = line;
338
339
340 if (cmd==NULL || *cmd == '\0' )
341 {
342 return;
343 }
344 if (strcmp(cmd,"cd")==0)
345 {
346 ExecuteCd(tail);
347 return;
348 }
349 if (strcmp(cmd,"dir")==0)
350 {
351 ExecuteDir(tail);
352 return;
353 }
354 if (strcmp(cmd,"kill")==0)
355 {
356 ExecuteKill(tail);
357 return;
358 }
359 if (strcmp(cmd,"md")==0)
360 {
361 ExecuteMd(tail);
362 return;
363 }
364 if (strcmp(cmd,"reboot")==0)
365 {
366 ExecuteReboot(tail);
367 return;
368 }
369 if (strcmp(cmd,"shutdown")==0)
370 {
371 ExecuteShutdown(tail);
372 return;
373 }
374 if (strcmp(cmd,"type")==0)
375 {
376 ExecuteType(tail);
377 return;
378 }
379 if (strcmp(cmd,"ver")==0)
380 {
381 ExecuteVer();
382 return;
383 }
384 if (strcmp(cmd,"validate")==0)
385 {
386 debug_printf("Validating heap...");
387 if (HeapValidate(GetProcessHeap(),0,NULL))
388 {
389 debug_printf("succeeded\n");
390 }
391 else
392 {
393 debug_printf("failed\n");
394 }
395 return;
396 }
397 if (strcmp(cmd,"start") == 0)
398 {
399 ExecuteStart(tail);
400 return;
401 }
402 if ((strcmp(cmd,"help") * strcmp(cmd,"?")) == 0)
403 {
404 ExecuteHelp(tail);
405 return;
406 }
407 if (strcmp(cmd,"exit")==0)
408 {
409 if (bCanExit == TRUE)
410 {
411 ExitProcess(0);
412 }
413 return;
414 }
415 if (ExecuteProcess(cmd,tail,FALSE))
416 {
417 return;
418 }
419 debug_printf("Unknown command '%s'\n", cmd);
420 }
421
422 void ReadLine(char* line)
423 {
424 DWORD Result;
425 UCHAR CurrentDir[255];
426
427 GetCurrentDirectoryA(255,CurrentDir);
428 debug_printf("%s>", CurrentDir);
429 if ( !ReadConsoleA(InputHandle, line, 252, &Result, NULL) )
430 {
431 debug_printf("Failed to read from console\n");
432 for(;;);
433 }
434 // If the \n is in there, so is the \r so null it, otherwise, null the last char
435 if( line[Result-1] == '\n' )
436 line[Result-2] = 0;
437 else {
438 line[Result] = 0;
439 }
440 }
441
442 void ParseCommandLine (void)
443 {
444 char *pszCommandLine;
445
446 pszCommandLine = GetCommandLineA ();
447 _strupr (pszCommandLine);
448 if (strstr (pszCommandLine, "/P") != NULL)
449 {
450 debug_printf("Permanent shell\n");
451 bCanExit = FALSE;
452 }
453 }
454
455 int main(void)
456 {
457 static char line[256];
458
459 AllocConsole();
460 InputHandle = GetStdHandle(STD_INPUT_HANDLE);
461 OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
462
463 debug_printf("Shell Starting...\n");
464
465 ParseCommandLine ();
466
467 for(;;)
468 {
469 ReadLine(line);
470 ExecuteCommand(line);
471 }
472
473 return 0;
474 }
475
476 /* EOF */