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

4.104.115
Last change on this file since b079fe33 was b079fe33, checked in by Joel Sherrill <joel.sherrill@…>, on 10/02/08 at 20:16:16

2008-10-02 Joel Sherrill <joel.sherrill@…>

  • libmisc/shell/main_cp.c, libmisc/shell/main_ls.c, libmisc/shell/main_mv.c, libmisc/shell/main_netstats.c, libmisc/shell/main_rm.c, libmisc/shell/shell_script.c: Newlib > 1.16.0 requires need_getopt_newlib to be defined to get visibility on the reentrancy extensions.
  • 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#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{
105  int                  option;
106  int                  sc;
107  int                  verbose = 0;
108  char                *taskName = "JOEL";
109  uint32_t             stackSize = RTEMS_MINIMUM_STACK_SIZE * 10;
110  rtems_task_priority  taskPriority = 20;
111  char                *outputFile = "stdout";
112  rtems_status_code    result;
113  char                 scriptFile[PATH_MAX];
114  struct getopt_data   getopt_reent;
115
116  memset(&getopt_reent, 0, sizeof(getopt_data));
117  while ( (option = getopt_r( argc, argv, "o:p:s:t:v", &getopt_reent)) != -1 ) {
118    switch ((char)option) {
119      case 'o':
120        outputFile = getopt_reent.optarg;
121        break;
122      case 'p':
123        taskPriority = rtems_shell_str2int(getopt_reent.optarg);
124        break;
125      case 's':
126        stackSize = rtems_shell_str2int(getopt_reent.optarg);
127        break;
128      case 't':
129        taskName = getopt_reent.optarg;
130        break;
131      case 'v': 
132        verbose = 1;
133        break;
134      case '?': 
135      default:
136        rtems_shell_joel_usage();
137        return -1;
138    }
139  }
140
141  if ( verbose ) {
142    fprintf( stderr,
143      "outputFile: %s\n"
144      "taskPriority: %" PRId32 "\n"
145      "stackSize: %" PRId32 "\n"
146      "taskName: %s\n",
147      outputFile,
148      taskPriority,
149      stackSize,
150      taskName
151   );
152  }
153
154  /*
155   *  Verify there is a script name past the end of the arguments.
156   *  Preincrement to skip program name.
157   */
158  if ( getopt_reent.optind >= argc ) {
159    fprintf( stderr, "Shell: No script to execute\n" );
160    return -1;
161  }
162 
163  /*
164   *  Find script on the path. 
165   *
166   *  NOTE: It is terrible that this is done twice but it
167   *        seems to be the most expedient thing.
168   */
169  sc = findOnPATH( argv[getopt_reent.optind], scriptFile );
170  if ( sc ) {
171    fprintf( stderr, "%s: command not found\n", argv[0] );
172    return -1;
173  }
174
175  /* fprintf( stderr, "SCRIPT: -%s-\n", scriptFile ); */
176
177  /*
178   *  I assume that argv[optind...] will have the arguments to
179   *  the shell script.  But that remains to be implemented.
180   */
181
182  /*
183   * Run the script
184   */
185  result = rtems_shell_script(
186    taskName,        /* the name of the task */
187    stackSize,       /* stack size */
188    taskPriority,    /* task priority */
189    scriptFile,      /* the script file */
190    outputFile,      /* where to redirect the script */
191    0,               /* run once and exit */
192    1,               /* we will wait */
193    verbose          /* do we echo */
194  );
195  if (result)
196    return -1;
197  return 0;
198}
199     
200rtems_shell_cmd_t rtems_shell_JOEL_Command = {
201  "joel",                        /* name */
202  "joel [args] SCRIPT",          /* usage */
203  "misc",                        /* topic */
204  rtems_shell_main_joel,         /* command */
205  NULL,                          /* alias */
206  NULL                           /* next */
207};
208
209/*
210 *  This is a helper function which takes a command as arguments
211 *  which has not been located as a built-in command and attempts
212 *  to find something in the filesystem with the same name that
213 *  appears to be a shell script.
214 */
215int rtems_shell_script_file(
216  int   argc,
217  char *argv[]
218)
219{
220  #define FIRST_LINE_LENGTH 128
221  #define SCRIPT_ARGV_LIMIT 32
222  char    scriptFile[PATH_MAX];
223  char   *scriptHead;
224  char    scriptHeadBuffer[FIRST_LINE_LENGTH];
225  int     sc;
226  FILE   *script;
227  size_t  length;
228  int     scriptArgc;
229  char   *scriptArgv[SCRIPT_ARGV_LIMIT];
230
231  /*
232   *  Clear argv pointer array
233   */
234  for ( scriptArgc=0 ; scriptArgc<SCRIPT_ARGV_LIMIT ; scriptArgc++ )
235    scriptArgv[scriptArgc] = NULL;
236
237  /*
238   *  Find argv[0] on the path
239   */
240  sc = findOnPATH( argv[0], scriptFile );
241  if ( sc ) {
242    fprintf( stderr, "%s: command not found\n", argv[0] );
243    return -1;
244  }
245
246  /*
247   *  Open the file so we can see if it looks like a script.
248   */
249  script = fopen( scriptFile, "r" );
250  if ( !script ) {
251    fprintf( stderr, "%s: Unable to open %s\n", argv[0], scriptFile );
252    return -1;
253  }
254
255  /*
256   *  Is the script OK to run?
257   *  Verify the current user has permission to execute it.
258   *
259   *  NOTE: May not work on all file systems
260   */
261  sc = access( scriptFile, X_OK );
262  if ( sc ) {
263    fprintf( stderr, "Unable to execute %s\n", scriptFile );
264    fclose( script );
265    return -1;
266  }
267
268  /*
269   *  Try to read the first line from the potential script file
270   */
271  scriptHead = fgets(scriptHeadBuffer, FIRST_LINE_LENGTH, script);
272  if ( !scriptHead ) {
273    fprintf(
274      stderr, "%s: Unable to read first line of %s\n", argv[0], scriptFile );
275    fclose( script );
276    return -1;
277  }
278
279  fclose(script);
280
281  length = strnlen(scriptHead, FIRST_LINE_LENGTH);
282  scriptHead[length - 1] = '\0';
283
284  /* fprintf( stderr, "FIRST LINE: -%s-\n", scriptHead ); */
285   
286  /*
287   *  Verify the name of the "shell" is joel.  This means
288   *  the line starts with "#! joel".
289   */
290  if (strncmp("#! joel", scriptHead, 7) != 0) {
291    fprintf( stderr, "%s: Not a joel script %s\n", argv[0], scriptFile );
292    return -1;
293  }
294
295  /*
296   * Do not worry about search path further.  We have found the
297   * script, it is executable, and we have successfully read the
298   * first line and found out it is a script.
299   */
300
301  /*
302   * Check for arguments in fist line of the script.  This changes
303   * how the shell task is run.
304   */
305
306  sc = rtems_shell_make_args(
307    &scriptHead[3],
308    &scriptArgc,
309    scriptArgv,
310    SCRIPT_ARGV_LIMIT - 1
311  );
312  if ( sc ) {
313    fprintf(
314      stderr, "%s: Error parsing joel arguments %s\n", argv[0], scriptFile );
315    return -1;
316  }
317
318  scriptArgv[ scriptArgc++ ] = scriptFile;
319
320  /*
321   *  TODO: How do we pass arguments from here to the script?
322   *        At this point, it doesn't matter because we don't
323   *        have any way for a shell script to access them.
324   */
325  return rtems_shell_main_joel( scriptArgc, scriptArgv );
326
327  return 0;
328}
329
Note: See TracBrowser for help on using the repository browser.