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

4.104.114.9
Last change on this file since e6ee171 was e6ee171, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 23, 2008 at 8:28:13 PM

2008-07-23 Joel Sherrill <joel.sherrill@…>

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