source: rtems/cpukit/libmisc/shell/shell_script.c @ e4a3d93

4.104.115
Last change on this file since e4a3d93 was 6d8720c4, checked in by Joel Sherrill <joel.sherrill@…>, on 05/10/09 at 14:55:43

2009-05-10 Joel Sherrill <joel.sherrill@…>

  • libmisc/shell/login_prompt.c, libmisc/shell/shell_script.c, rtems/include/rtems/rtems/timer.h: Fix warnings.
  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 *  Shell Script Invocation
3 *
4 *  Pseudo-code from Chris Johns, implemented and debugged
5 *  by Joel Sherrill.
6 *
7 *  COPYRIGHT (c) 1989-2009.
8 *  On-Line Applications Research Corporation (OAR).
9 *
10 *  The license and distribution terms for this file may be
11 *  found in the file LICENSE in this distribution or at
12 *  http://www.rtems.com/license/LICENSE.
13 *
14 *  $Id$
15 */
16
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <stdio.h>
22#include <unistd.h>
23#include <string.h>
24#include <errno.h>
25#include <inttypes.h>
26#include <sys/types.h>
27#include <unistd.h>
28#define __need_getopt_newlib
29#include <getopt.h>
30
31#include <rtems.h>
32#include <rtems/shell.h>
33#include "internal.h"
34
35static void rtems_shell_joel_usage(void)
36{
37  printf(
38    "joel [args] where args may be:\n"
39    "  -o FILE     output file (default=stdout)\n"
40    "  -p PRIORITY task priority\n"
41    "  -s SIZE     task stack size\n"
42    "  -t NAME     task name\n"
43  );
44}
45
46static int findOnPATH(
47  const char *userScriptName,
48  char       *scriptFile
49)
50{
51  int sc;
52
53  /*
54   *  If the user script name starts with a / assume it is a fully
55   *  qualified path name and just use it.
56   */
57  if ( userScriptName[0] == '/' ) {
58    strcpy( scriptFile, userScriptName );
59  } else {
60    /*
61     *  For now, the provided name is just turned into a fully
62     *  qualified path name and used.  There is no attempt to
63     *  search along a path for it.
64     */
65
66    /* XXX should use strncat but what is the limit? */
67    getcwd( scriptFile, PATH_MAX );
68    strcat( scriptFile, "/" );
69    strcat(
70      scriptFile,
71      ( (userScriptName[0] == '.' && userScriptName[1] == '/') ?
72         &userScriptName[2] : userScriptName)
73    );
74  }
75
76  sc = access( scriptFile, R_OK );
77  if ( sc ) {
78    return -1;
79  }
80
81  return 0;
82
83#if 0
84   /*
85    * Does the command (argv[0]) contain a path ?, i.e. starts with
86    * '.' or contains a '/'?
87    */
88   /* TODO: Add concept of PATH */
89   if (!contains_path) {
90     /* check PATH environment variable */
91     for (path_part = PATH; path_part; skip to ':')
92     {
93     }
94     if (not found)
95       return -1;
96   }
97#endif
98}
99
100int rtems_shell_main_joel(
101  int    argc,
102  char **argv
103);
104
105int rtems_shell_main_joel(
106  int    argc,
107  char **argv
108)
109{
110  int                  option;
111  int                  sc;
112  int                  verbose = 0;
113  char                *taskName = "JOEL";
114  uint32_t             stackSize = RTEMS_MINIMUM_STACK_SIZE * 10;
115  rtems_task_priority  taskPriority = 20;
116  char                *outputFile = "stdout";
117  rtems_status_code    result;
118  char                 scriptFile[PATH_MAX];
119  struct getopt_data   getopt_reent;
120
121  memset(&getopt_reent, 0, sizeof(getopt_data));
122  while ( (option = getopt_r( argc, argv, "o:p:s:t:v", &getopt_reent)) != -1 ) {
123    switch ((char)option) {
124      case 'o':
125        outputFile = getopt_reent.optarg;
126        break;
127      case 'p':
128        taskPriority =
129          (rtems_task_priority) rtems_shell_str2int(getopt_reent.optarg);
130        break;
131      case 's':
132        stackSize = (uint32_t) rtems_shell_str2int(getopt_reent.optarg);
133        break;
134      case 't':
135        taskName = getopt_reent.optarg;
136        break;
137      case 'v': 
138        verbose = 1;
139        break;
140      case '?': 
141      default:
142        rtems_shell_joel_usage();
143        return -1;
144    }
145  }
146
147  if ( verbose ) {
148    fprintf( stderr,
149      "outputFile: %s\n"
150      "taskPriority: %" PRId32 "\n"
151      "stackSize: %" PRId32 "\n"
152      "taskName: %s\n",
153      outputFile,
154      taskPriority,
155      stackSize,
156      taskName
157   );
158  }
159
160  /*
161   *  Verify there is a script name past the end of the arguments.
162   *  Preincrement to skip program name.
163   */
164  if ( getopt_reent.optind >= argc ) {
165    fprintf( stderr, "Shell: No script to execute\n" );
166    return -1;
167  }
168 
169  /*
170   *  Find script on the path. 
171   *
172   *  NOTE: It is terrible that this is done twice but it
173   *        seems to be the most expedient thing.
174   */
175  sc = findOnPATH( argv[getopt_reent.optind], scriptFile );
176  if ( sc ) {
177    fprintf( stderr, "%s: command not found\n", argv[0] );
178    return -1;
179  }
180
181  /* fprintf( stderr, "SCRIPT: -%s-\n", scriptFile ); */
182
183  /*
184   *  I assume that argv[optind...] will have the arguments to
185   *  the shell script.  But that remains to be implemented.
186   */
187
188  /*
189   * Run the script
190   */
191  result = rtems_shell_script(
192    taskName,        /* the name of the task */
193    stackSize,       /* stack size */
194    taskPriority,    /* task priority */
195    scriptFile,      /* the script file */
196    outputFile,      /* where to redirect the script */
197    0,               /* run once and exit */
198    1,               /* we will wait */
199    verbose          /* do we echo */
200  );
201  if (result)
202    return -1;
203  return 0;
204}
205     
206rtems_shell_cmd_t rtems_shell_JOEL_Command = {
207  "joel",                        /* name */
208  "joel [args] SCRIPT",          /* usage */
209  "misc",                        /* topic */
210  rtems_shell_main_joel,         /* command */
211  NULL,                          /* alias */
212  NULL                           /* next */
213};
214
215/*
216 *  This is a helper function which takes a command as arguments
217 *  which has not been located as a built-in command and attempts
218 *  to find something in the filesystem with the same name that
219 *  appears to be a shell script.
220 */
221int rtems_shell_script_file(
222  int   argc __attribute__((unused)),
223  char *argv[]
224)
225{
226  #define FIRST_LINE_LENGTH 128
227  #define SCRIPT_ARGV_LIMIT 32
228  char    scriptFile[PATH_MAX];
229  char   *scriptHead;
230  char    scriptHeadBuffer[FIRST_LINE_LENGTH];
231  int     sc;
232  FILE   *script;
233  size_t  length;
234  int     scriptArgc;
235  char   *scriptArgv[SCRIPT_ARGV_LIMIT];
236
237  /*
238   *  Clear argv pointer array
239   */
240  for ( scriptArgc=0 ; scriptArgc<SCRIPT_ARGV_LIMIT ; scriptArgc++ )
241    scriptArgv[scriptArgc] = NULL;
242
243  /*
244   *  Find argv[0] on the path
245   */
246  sc = findOnPATH( argv[0], scriptFile );
247  if ( sc ) {
248    fprintf( stderr, "%s: command not found\n", argv[0] );
249    return -1;
250  }
251
252  /*
253   *  Open the file so we can see if it looks like a script.
254   */
255  script = fopen( scriptFile, "r" );
256  if ( !script ) {
257    fprintf( stderr, "%s: Unable to open %s\n", argv[0], scriptFile );
258    return -1;
259  }
260
261  /*
262   *  Is the script OK to run?
263   *  Verify the current user has permission to execute it.
264   *
265   *  NOTE: May not work on all file systems
266   */
267  sc = access( scriptFile, X_OK );
268  if ( sc ) {
269    fprintf( stderr, "Unable to execute %s\n", scriptFile );
270    fclose( script );
271    return -1;
272  }
273
274  /*
275   *  Try to read the first line from the potential script file
276   */
277  scriptHead = fgets(scriptHeadBuffer, FIRST_LINE_LENGTH, script);
278  if ( !scriptHead ) {
279    fprintf(
280      stderr, "%s: Unable to read first line of %s\n", argv[0], scriptFile );
281    fclose( script );
282    return -1;
283  }
284
285  fclose(script);
286
287  length = strnlen(scriptHead, FIRST_LINE_LENGTH);
288  scriptHead[length - 1] = '\0';
289
290  /* fprintf( stderr, "FIRST LINE: -%s-\n", scriptHead ); */
291   
292  /*
293   *  Verify the name of the "shell" is joel.  This means
294   *  the line starts with "#! joel".
295   */
296  if (strncmp("#! joel", scriptHead, 7) != 0) {
297    fprintf( stderr, "%s: Not a joel script %s\n", argv[0], scriptFile );
298    return -1;
299  }
300
301  /*
302   * Do not worry about search path further.  We have found the
303   * script, it is executable, and we have successfully read the
304   * first line and found out it is a script.
305   */
306
307  /*
308   * Check for arguments in fist line of the script.  This changes
309   * how the shell task is run.
310   */
311
312  sc = rtems_shell_make_args(
313    &scriptHead[3],
314    &scriptArgc,
315    scriptArgv,
316    SCRIPT_ARGV_LIMIT - 1
317  );
318  if ( sc ) {
319    fprintf(
320      stderr, "%s: Error parsing joel arguments %s\n", argv[0], scriptFile );
321    return -1;
322  }
323
324  scriptArgv[ scriptArgc++ ] = scriptFile;
325
326  /*
327   *  TODO: How do we pass arguments from here to the script?
328   *        At this point, it doesn't matter because we don't
329   *        have any way for a shell script to access them.
330   */
331  return rtems_shell_main_joel( scriptArgc, scriptArgv );
332
333  return 0;
334}
Note: See TracBrowser for help on using the repository browser.