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