nfs-ganesha 1.4

shell.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00094 #ifdef HAVE_CONFIG_H
00095 #include "config.h"
00096 #endif
00097 
00098 #ifdef _SOLARIS
00099 #include "solaris_port.h"
00100 #endif
00101 
00102 #include "shell.h"
00103 #include "shell_utils.h"
00104 #include "shell_vars.h"
00105 #include "log.h"
00106 #include "commands.h"
00107 #include "cmd_tools.h"
00108 
00109 #include "abstract_mem.h"
00110 #include <unistd.h>
00111 #include <string.h>
00112 
00113 #include <stdio.h>
00114 #include <pthread.h>
00115 
00116 #ifdef HAVE_LIBREADLINE
00117 #include <readline/readline.h>
00118 #include <readline/history.h>
00119 #endif
00120 
00121 #include <sys/time.h>
00122 #include "shell.h"
00123 
00124 #define MAX_OUTPUT_LEN  (1024*1024)     /* 1MB */
00125 
00126 #define TRACEBUFFSIZE 1024
00127 
00128 #define PROMPTSIZE 64
00129 
00130 layer_def_t layer_list[] = {
00131   {"FSAL", commands_FSAL, "File system abstraction layer", fsal_layer_SetLogLevel}
00132   ,
00133   {"Cache_inode", commands_Cache_inode, "Cache inode layer", Cache_inode_layer_SetLogLevel}
00134   ,
00135   {"NFS", commands_NFS,
00136    "NFSv2, NFSv3, MNTv1, MNTv3 protocols (direct calls, not through RPCs)",
00137    nfs_layer_SetLogLevel}
00138   ,
00139   {"NFS_remote", commands_NFS_remote,
00140    "NFSv2, NFSv3, MNTv1, MNTv3 protocols (calls through RPCs)",
00141    nfs_remote_layer_SetLogLevel}
00142   ,
00143   {NULL, NULL, NULL, NULL}      /* End of layer list */
00144 };
00145 
00146 char *shell_special_vars[] = {
00147   "INPUT",                      /* a filename or <stdin> */
00148   "INTERACTIVE",                /* Indicates if we are in interactive mode */
00149   "LAYER",                      /* The current layer */
00150   "STATUS",                     /* Last command status */
00151   "?",                          /* idem */
00152   "VERBOSE",                    /* shel verbose mode */
00153   "DEBUG_LEVEL",                /* layer debug level */
00154   "DBG_LVL",                    /* idem */
00155   "PROMPT",                     /* shell prompt string */
00156   "LINE",                       /* line number */
00157 
00158   /* end of special vars list */
00159   NULL
00160 };
00161 
00162 command_def_t shell_utils[] = {
00163   {"chomp", util_chomp, "removes final newline character"},
00164   {"cmp", util_cmp, "compares two expressions"},
00165   {"diff", util_diff, "lists differences between two expressions"},
00166   {"eq", util_cmp, "test if two expressions are equal"},
00167   {"meminfo", util_meminfo, "prints information about memory use"},
00168   {"ne", util_cmp, "test if two expressions are different"},
00169   {"shell", util_shell, "executes a real shell command"},
00170   {"sleep", util_sleep, "suspends script execution for some time"},
00171   {"timer", util_timer, "timer management command"},
00172   {"wc", util_wc, "counts the number of char/words/lines in a string"},
00173 
00174   {NULL, NULL, NULL}            /* End of command list */
00175 };
00176 
00177 /* ------------------------------------------*
00178  *        Barrier management.
00179  * ------------------------------------------*/
00180 
00181 #define P_shell( _mutex_ ) pthread_mutex_lock( &_mutex_ )
00182 #define V_shell( _mutex_ ) pthread_mutex_unlock( &_mutex_ )
00183 
00184 /* variables for managing barriers */
00185 
00186 /* barrier protection */
00187 static pthread_mutex_t barrier_mutex = PTHREAD_MUTEX_INITIALIZER;
00188 
00189 /* condition for crossing barrier */
00190 static pthread_cond_t barrier_cond = PTHREAD_COND_INITIALIZER;
00191 
00192 /* total number of threads to wait for */
00193 static int total_nb_threads = -1;       /* -1 = not initialized */
00194 
00195 /* number of threads that reached the barrier */
00196 static int nb_waiting_threads = 0;
00197 
00202 int shell_BarrierInit(int nb_threads)
00203 {
00204 
00205   P_shell(barrier_mutex);
00206 
00207   if(total_nb_threads == -1)
00208     {
00209       total_nb_threads = nb_threads;
00210       V_shell(barrier_mutex);
00211       return SHELL_SUCCESS;
00212     }
00213   else
00214     {
00215       V_shell(barrier_mutex);
00216       printf("ganeshell: Error: Barrier already initialized\n");
00217       return SHELL_ERROR;
00218     }
00219 }
00220 
00221 static int shell_BarrierWait()
00222 {
00223 
00224   P_shell(barrier_mutex);
00225 
00226   /* not used in a single thread environment */
00227 
00228   if(total_nb_threads == -1)
00229     {
00230       V_shell(barrier_mutex);
00231       return SHELL_ERROR;
00232     }
00233 
00234   /* increase number of waiting threads */
00235 
00236   nb_waiting_threads++;
00237 
00238   /* test for condition */
00239 
00240   if(nb_waiting_threads == total_nb_threads)
00241     {
00242       /* reset the number of waiting threads */
00243       nb_waiting_threads = 0;
00244 
00245       /* wake up all threads */
00246       pthread_cond_broadcast(&barrier_cond);
00247 
00248     }
00249   else
00250     pthread_cond_wait(&barrier_cond, &barrier_mutex);
00251 
00252   /* leaves the critical section */
00253 
00254   V_shell(barrier_mutex);
00255 
00256   return SHELL_SUCCESS;
00257 
00258 }
00259 
00260 /* ------------------------------------------*
00261  *        Thread safety management.
00262  * ------------------------------------------*/
00263 
00264 /* threads keys */
00265 static pthread_key_t thread_key;
00266 static pthread_once_t once_key = PTHREAD_ONCE_INIT;
00267 
00268 /* init pthtread_key for current thread */
00269 
00270 static void init_keys(void)
00271 {
00272   if(pthread_key_create(&thread_key, NULL) == -1)
00273     printf("Error %d creating pthread key for thread %p : %s\n",
00274            errno, (caddr_t) pthread_self(), strerror(errno));
00275 
00276   return;
00277 }                               /* init_keys */
00278 
00283 static shell_state_t *GetShellContext()
00284 {
00285 
00286   shell_state_t *p_current_thread_vars;
00287 
00288   /* first, we init the keys if this is the first time */
00289   if(pthread_once(&once_key, init_keys) != 0)
00290     {
00291       printf("Error %d calling pthread_once for thread %p : %s\n",
00292              errno, (caddr_t) pthread_self(), strerror(errno));
00293       return NULL;
00294     }
00295 
00296   p_current_thread_vars = (shell_state_t *) pthread_getspecific(thread_key);
00297 
00298   /* we allocate the thread context if this is the first time */
00299   if(p_current_thread_vars == NULL)
00300     {
00301 
00302       /* allocates thread structure */
00303       p_current_thread_vars = gsh_malloc(sizeof(shell_state_t));
00304 
00305       /* panic !!! */
00306       if(p_current_thread_vars == NULL)
00307         {
00308           printf("%p:ganeshell: Not enough memory\n", (caddr_t) pthread_self());
00309           return NULL;
00310         }
00311 
00312       /* Clean thread context */
00313 
00314       memset(p_current_thread_vars, 0, sizeof(shell_state_t));
00315 
00316       /* setting default values */
00317 
00318       p_current_thread_vars->input_stream = stdin;
00319       p_current_thread_vars->interactive = TRUE;
00320       p_current_thread_vars->layer = NULL;
00321       p_current_thread_vars->status = 0;
00322       p_current_thread_vars->verbose = 0;
00323       p_current_thread_vars->debug_level = NIV_EVENT;
00324       p_current_thread_vars->line = 0;
00325 
00326       /* set the specific value */
00327       pthread_setspecific(thread_key, (void *)p_current_thread_vars);
00328 
00329     }
00330 
00331   return p_current_thread_vars;
00332 
00333 }                               /* GetShellContext */
00334 
00335 /*------------------------------------------------------------------
00336  *                    Main shell routines.
00337  *-----------------------------------------------------------------*/
00338 
00344 int shell_Init(int verbose, char *input_file, char *prompt, int shell_index)
00345 {
00346 
00347   int rc;
00348   char localmachine[256];
00349   shell_state_t *context;
00350 
00351   /* Init logging */
00352 
00353   SetNamePgm("ganeshell");
00354   /*if (verbose) */
00355   SetDefaultLogging("STDERR");
00356   /*else
00357      SetDefaultLogging( "/dev/null" ) ; */
00358 
00359   SetNameFunction("shell");
00360 
00361   /* getting the hostname */
00362   if(gethostname(localmachine, sizeof(localmachine)) != 0)
00363     {
00364       fprintf(stderr, "Error %d calling gethostname.\n", errno);
00365       return errno;
00366     }
00367   else
00368     SetNameHost(localmachine);
00369 
00370   InitLogging();
00371 
00372   /* retrieve/initialize shell context */
00373 
00374   context = GetShellContext();
00375 
00376   /* Initializes verbose mode. */
00377 
00378   if((rc = shell_SetVerbose(context, (verbose ? "1" : "0"))))
00379     return rc;
00380 
00381   if((rc = shell_SetDbgLvl(context, "NIV_EVENT")))
00382     return rc;
00383 
00384   /* Then, initializes input file. */
00385 
00386   if((rc = shell_SetInput(context, input_file)))
00387     return rc;
00388 
00389   /* Initialize prompt */
00390 
00391   if((rc = shell_SetPrompt(context, prompt)))
00392     return rc;
00393 
00394   /* Initialize Shell id */
00395 
00396   if((rc = shell_SetShellId(context, shell_index)))
00397     return rc;
00398 
00399   return SHELL_SUCCESS;
00400 
00401 }
00402 
00403 /* reads a line from input, and prints a prompt in interactive mode. */
00404 
00405 
00406 #ifdef HAVE_LIBREADLINE
00407 /* the same as previous, except it doesnt not trunc line at # sign */
00408 
00409 static char *skipblanks2(char *str)
00410 {
00411 
00412   char *curr = str;
00413 
00414   while(1)
00415     {
00416 
00417       switch (*curr)
00418         {
00419           /* end of lines */
00420         case '\0':
00421           return NULL;
00422 
00423         case ' ':
00424         case '\t':
00425         case '\r':
00426         case '\n':
00427           curr++;
00428           break;
00429 
00430         default:
00431           return curr;
00432 
00433         }                       /* switch */
00434 
00435     }                           /* while */
00436 
00437 }                               /* skipblanks2 */
00438 
00439 
00440 #endif
00441 
00442 static char *shell_readline(shell_state_t * context, char *s, int n, FILE * stream,
00443                             int interactive)
00444 {
00445 
00446   char *retval = shell_GetPrompt(context);
00447 
00448 #ifdef HAVE_LIBREADLINE
00449 
00450   char *l;
00451 
00452   if(interactive)
00453     {
00454       /* use readline */
00455       l = readline((retval ? retval : ""));
00456       if(l)
00457         {
00458           strncpy(s, l, n);
00459 
00460           /* add line to history, if it is not empty */
00461           l = skipblanks2(l);
00462 
00463           if(l != NULL)
00464             add_history(l);
00465 
00466           return s;
00467         }
00468       else
00469         return NULL;
00470     }
00471   else
00472     return fgets(s, n, stream);
00473 
00474 #else
00475   if(interactive)
00476     printf("%s", (retval ? retval : ""));
00477 
00478   return fgets(s, n, stream);
00479 #endif
00480 
00481 }
00482 
00486 int shell_Launch()
00487 {
00488 
00489   char cmdline[MAX_LINE_LEN + 1];
00490   char *arglist[MAX_ARGS];
00491   int alloctab[MAX_ARGS];
00492   int argcount;
00493   int rc = 0;
00494 
00495   shell_state_t *context = GetShellContext();
00496 
00497   while(shell_readline(context, cmdline, MAX_LINE_LEN,
00498                        context->input_stream, context->interactive) != NULL)
00499     {
00500 
00501       /* Increments line number */
00502 
00503       shell_SetLine(context, shell_GetLine(context) + 1);
00504 
00505       /* Parse command line */
00506 
00507       if(shell_ParseLine(cmdline, arglist, &argcount))
00508         continue;
00509 
00510       /* nothing to do if the line is empty. */
00511       if(argcount == 0)
00512         continue;
00513 
00514       /* Evaluates arguments */
00515 
00516       if(shell_SolveArgs(argcount, arglist, alloctab))
00517         continue;
00518 
00519       /* Execute command */
00520       rc = shell_Execute(argcount, arglist, stdout);
00521 
00522       /* clean allocated strings */
00523       shell_CleanArgs(argcount, arglist, alloctab);
00524 
00525       /* set command status */
00526       shell_SetStatus(context, rc);
00527 
00528     }
00529   return rc;
00530 }
00531 
00532 /*------------------------------------------------------------------
00533  *                Parsing and execution routines.
00534  *-----------------------------------------------------------------*/
00535 
00536 /* address of the first non blank char if any, null else.*/
00537 
00538 static char *skipblanks(char *str)
00539 {
00540 
00541   char *curr = str;
00542 
00543   while(1)
00544     {
00545 
00546       switch (*curr)
00547         {
00548           /* end of lines */
00549         case '\0':
00550         case '#':
00551           return NULL;
00552 
00553         case ' ':
00554         case '\t':
00555         case '\r':
00556         case '\n':
00557           curr++;
00558           break;
00559 
00560         default:
00561           return curr;
00562 
00563         }                       /* switch */
00564 
00565     }                           /* while */
00566 
00567 }                               /* skipblanks */
00568 
00569 /* adress of the first blank char
00570  * outside a string.
00571  */
00572 static char *nextblank(char *str)
00573 {
00574 
00575   int dquote_string = 0;
00576   int squote_string = 0;
00577   int bquote_string = 0;
00578 
00579   int escaped = 0;
00580 
00581   char *curr = str;
00582 
00583   while(1)
00584     {
00585 
00586       switch (*curr)
00587         {
00588 
00589           /* end of lines */
00590         case ' ':
00591         case '\t':
00592           if(!dquote_string && !squote_string && !bquote_string)
00593             return curr;
00594           else
00595             curr++;
00596           break;
00597 
00598         case '\0':
00599         case '\n':
00600           return curr;
00601           break;
00602 
00603         case '\\':
00604           /* escape sequence */
00605           escaped = 1;
00606           curr++;
00607           break;
00608 
00609         case '"':
00610           /* start or end of double quoted string */
00611           if(dquote_string)
00612             dquote_string = 0;
00613           else
00614             (dquote_string) = 1;
00615           curr++;
00616           break;
00617 
00618         case '\'':
00619           /* start or end of single quoted string */
00620           if(squote_string)
00621             squote_string = 0;
00622           else
00623             (squote_string) = 1;
00624           curr++;
00625           break;
00626 
00627         case '`':
00628           /* start or end of back-quoted string */
00629           if(bquote_string)
00630             bquote_string = 0;
00631           else
00632             (bquote_string) = 1;
00633           curr++;
00634           break;
00635 
00636         default:
00637           curr++;
00638 
00639         }                       /* switch */
00640 
00641       /* escape ? */
00642 
00643       if(escaped && (*curr != '\0'))
00644         {
00645           escaped = 0;
00646           curr++;
00647         }
00648 
00649     }                           /* while */
00650 
00651 }                               /* nextblank */
00652 
00664 int shell_ParseLine(char *in_out_line, char **out_arglist, int *p_argcount)
00665 {
00666 
00667   char *curr_pos = in_out_line;
00668   (*p_argcount) = 0;
00669 
00670   /* While there is something after the Oblivion... */
00671 
00672   while((curr_pos = skipblanks(curr_pos)))
00673     {
00674       out_arglist[(*p_argcount)] = curr_pos;
00675       (*p_argcount)++;
00676       curr_pos = nextblank(curr_pos);
00677 
00678       if(*curr_pos == '\0')
00679         break;
00680       else
00681         *curr_pos = '\0';
00682 
00683       curr_pos++;
00684     }
00685 
00686   return SHELL_SUCCESS;
00687 
00688 }                               /* shell_ParseLine */
00689 
00695 static int unescape(char *str)
00696 {
00697 
00698   char *src = str;
00699   char *tgt = str;
00700 
00701   while(*src != '\0')
00702     {
00703       if(*src == '\\')
00704         {
00705           src++;
00706 
00707           /* escaped null char */
00708           if(*src == '\0')
00709             {
00710 #ifdef _DEBUG_SHELL
00711               printf("UNESCAPE ERROR >>>>>>>>>> [%s][%c][%c]\n", str, *src, *tgt);
00712 #endif
00713               return SHELL_ERROR;
00714             }
00715 
00716         }
00717 
00718       if(tgt != src)
00719         *tgt = *src;
00720 
00721       src++;
00722       tgt++;
00723     }
00724 
00725   /* final zero */
00726   if(tgt != src)
00727     *tgt = *src;
00728 
00729   return SHELL_SUCCESS;
00730 
00731 }
00732 
00738 static int remove_quotes(char quote, char **pstr)
00739 {
00740 
00741   size_t len = strlen(*pstr);
00742 
00743   if(len <= 1)
00744     return SHELL_ERROR;
00745   if((*pstr)[len - 1] != quote)
00746     return SHELL_ERROR;
00747 
00748   (*pstr)[len - 1] = '\0';
00749   (*pstr)[0] = '\0';
00750 
00751   (*pstr)++;
00752 
00753   return SHELL_SUCCESS;
00754 
00755 }
00756 
00768 int shell_SolveArgs(int argc, char **in_out_argv, int *out_allocated)
00769 {
00770 
00771   int i;
00772   int error = 0;
00773   char tracebuff[TRACEBUFFSIZE];
00774 
00775   shell_state_t *context = GetShellContext();
00776 
00777 #ifdef _DEBUG_SHELL
00778   printf("SOLVE:");
00779   for(i = 0; i < argc; i++)
00780     printf("[%s]", in_out_argv[i]);
00781   printf("\n");
00782 #endif
00783 
00784   for(i = 0; i < argc; i++)
00785     {
00786 
00787       out_allocated[i] = FALSE;
00788 
00789       /* double quotes */
00790 
00791       if(in_out_argv[i][0] == '"')
00792         {
00793 
00794           if(remove_quotes('"', &(in_out_argv[i])))
00795             {
00796               shell_PrintError(context, "Syntax error: Missing closing quotes");
00797               error = SHELL_SYNTAX_ERROR;
00798               break;
00799             }
00800 
00801           if(unescape(in_out_argv[i]))
00802             {
00803               shell_PrintError(context, "Syntax error: Invalid escape sequence");
00804               error = SHELL_SYNTAX_ERROR;
00805               break;
00806             }
00807 
00808         }
00809 
00810       /* single quotes */
00811 
00812       else if(in_out_argv[i][0] == '\'')
00813         {
00814 
00815           if(remove_quotes('\'', &(in_out_argv[i])))
00816             {
00817               shell_PrintError(context, "Syntax error: Missing closing quote");
00818               error = SHELL_SYNTAX_ERROR;
00819               break;
00820             }
00821 
00822           if(unescape(in_out_argv[i]))
00823             {
00824               shell_PrintError(context, "Syntax error: Invalid escape sequence");
00825               error = SHELL_SYNTAX_ERROR;
00826               break;
00827             }
00828 
00829         }
00830 
00831       /* var name */
00832 
00833       else if(in_out_argv[i][0] == '$')
00834         {
00835 
00836           char *value = get_var_value(&(in_out_argv[i][1]));
00837 
00838           if(value)
00839             in_out_argv[i] = value;
00840           else
00841             {
00842               snprintf(tracebuff, TRACEBUFFSIZE,
00843                        "Undefined variable \"%s\"", &(in_out_argv[i][1]));
00844               shell_PrintError(context, tracebuff);
00845               error = SHELL_NOT_FOUND;
00846               break;
00847             }
00848 
00849         }
00850 
00851       /* command */
00852 
00853       else if(in_out_argv[i][0] == '`')
00854         {
00855 
00856           char *arglist[MAX_ARGS];
00857           int argcount;
00858           int rc, status;
00859 
00860           /* remove quotes */
00861 
00862           if(remove_quotes('`', &(in_out_argv[i])))
00863             {
00864               shell_PrintError(context, "Syntax error: Missing closing backquote");
00865               error = SHELL_SYNTAX_ERROR;
00866               break;
00867             }
00868 
00869           if(unescape(in_out_argv[i]))
00870             {
00871               shell_PrintError(context, "Syntax error: Invalid escape sequence");
00872               error = SHELL_SYNTAX_ERROR;
00873               break;
00874             }
00875 
00876           /* Parse command line */
00877 
00878           if(shell_ParseLine(in_out_argv[i], arglist, &argcount))
00879             {
00880               error = SHELL_SYNTAX_ERROR;
00881               break;
00882             }
00883 
00884           /* nothing to do if the command is empty. */
00885 
00886           if(argcount == 0)
00887             {
00888 
00889               /* empty output */
00890               in_out_argv[i][0] = '\0';
00891 
00892               /* command status */
00893               shell_SetStatus(context, 0);
00894 
00895             }
00896           else
00897             {
00898 
00899               int fd[2];
00900               FILE *output_stream;
00901               int alloctab[MAX_ARGS];
00902 
00903               char output_string[MAX_OUTPUT_LEN];
00904 
00905               /* Evaluates arguments */
00906 
00907               if(shell_SolveArgs(argcount, arglist, alloctab))
00908                 {
00909                   error = SHELL_SYNTAX_ERROR;
00910                   break;
00911                 }
00912 
00913               /* create pipe for command output */
00914 
00915               if(pipe(fd))
00916                 {
00917 
00918                   snprintf(tracebuff, TRACEBUFFSIZE, "Can't create pipe: %s (%d)",
00919                            strerror(errno), errno);
00920                   shell_PrintError(context, tracebuff);
00921 
00922                   /* clean allocated strings */
00923                   shell_CleanArgs(argcount, arglist, alloctab);
00924 
00925                   error = errno;
00926                   break;
00927 
00928                 }
00929 
00930               /* opening output stream */
00931 
00932               output_stream = fdopen(fd[1], "a");
00933 
00934               if(output_stream == NULL)
00935                 {
00936 
00937                   snprintf(tracebuff, TRACEBUFFSIZE, "Can't open pipe stream: %s (%d)",
00938                            strerror(errno), errno);
00939                   shell_PrintError(context, tracebuff);
00940 
00941                   /* clean allocated strings */
00942                   shell_CleanArgs(argcount, arglist, alloctab);
00943 
00944                   /* close pipe */
00945                   close(fd[1]);
00946                   close(fd[0]);
00947 
00948                   error = errno;
00949                   break;
00950 
00951                 }
00952 
00953               /* @todo : thread for pipe reading */
00954 
00955               /* Execute command */
00956 
00957               status = shell_Execute(argcount, arglist, output_stream);
00958 
00959               /* closing ouput stream. */
00960 
00961               fclose(output_stream);
00962               close(fd[1]);
00963 
00964               /* clean allocated strings */
00965               shell_CleanArgs(argcount, arglist, alloctab);
00966 
00967               /* read the output from pipe */
00968 
00969               rc = read(fd[0], output_string, MAX_OUTPUT_LEN);
00970 
00971               /* close pipe */
00972               close(fd[0]);
00973 
00974               if(rc == -1)
00975                 {
00976                   snprintf(tracebuff, TRACEBUFFSIZE, "Cannot read from pipe: %s (%d)",
00977                            strerror(errno), errno);
00978                   shell_PrintError(context, tracebuff);
00979 
00980                   error = errno;
00981                   break;
00982                 }
00983 
00984               /* allocate and fill output buffer */
00985 
00986               in_out_argv[i] = gsh_malloc(rc + 1);
00987 
00988               if(in_out_argv[i] == NULL)
00989                 {
00990                   shell_PrintError(context, "Malloc error");
00991                   error = -1;
00992                   break;
00993                 }
00994 
00995               memcpy(in_out_argv[i], output_string, rc);
00996 
00997               out_allocated[i] = TRUE;
00998 
00999               in_out_argv[i][rc] = '\0';
01000 
01001               /* set command status */
01002 
01003               shell_SetStatus(context, status);
01004 
01005             }
01006 
01007         }
01008       /*  normal arg  */
01009       else
01010         {
01011           if(unescape(in_out_argv[i]))
01012             {
01013               shell_PrintError(context, "Syntax error: Invalid escape sequence");
01014               error = SHELL_SYNTAX_ERROR;
01015               break;
01016             }
01017 
01018         }                       /* in_out_argv[i][0] */
01019 
01020     }                           /* for */
01021 
01022   /* the case when we exited the for because of an error. */
01023 
01024   if(error)
01025     {
01026       /* free allocated strings */
01027       shell_CleanArgs(i + 1, in_out_argv, out_allocated);
01028       return error;
01029     }
01030 
01031   return SHELL_SUCCESS;
01032 
01033 }                               /* shell_SolveArgs */
01034 
01045 void shell_CleanArgs(int argc, char **in_out_argv, int *in_allocated)
01046 {
01047 
01048   int i;
01049 
01050   for(i = 0; i < argc; i++)
01051     {
01052 
01053       if(in_allocated[i])
01054         {
01055           gsh_free(in_out_argv[i]);
01056           in_out_argv[i] = NULL;
01057           in_allocated[i] = FALSE;
01058         }
01059 
01060     }
01061 
01062   return;
01063 
01064 }
01065 
01076 int shell_Execute(int argc, char **argv, FILE * output)
01077 {
01078 
01079   /* pointer to the command to be launched */
01080   int (*command_func) (int, char **, FILE *) = NULL;
01081 
01082   int i;
01083   int rc;
01084   char tracebuff[TRACEBUFFSIZE];
01085 
01086   shell_state_t *context = GetShellContext();
01087 
01088   /* First, look at shell internal commands */
01089 
01090   for(i = 0; shell_commands[i].command_name; i++)
01091     {
01092       if(!strcmp(argv[0], shell_commands[i].command_name))
01093         {
01094           command_func = shell_commands[i].command_func;
01095           break;
01096         }
01097     }
01098 
01099   /* If not found, look at shell utils commands */
01100 
01101   if(!command_func)
01102     {
01103 
01104       for(i = 0; shell_utils[i].command_name; i++)
01105         {
01106           if(!strcmp(argv[0], shell_utils[i].command_name))
01107             {
01108               command_func = shell_utils[i].command_func;
01109               break;
01110             }
01111         }
01112 
01113     }
01114 
01115   /* If not found, look at layer commands */
01116 
01117   if(!command_func)
01118     {
01119       layer_def_t *current_layer = shell_GetLayer(context);
01120 
01121       if(current_layer)
01122         {
01123 
01124           for(i = 0; current_layer->command_list[i].command_name; i++)
01125             {
01126               if(!strcmp(argv[0], current_layer->command_list[i].command_name))
01127                 {
01128                   command_func = current_layer->command_list[i].command_func;
01129 
01130                   /* set layer's debug level */
01131                   current_layer->setlog_func(shell_GetDbgLvl(context));
01132 
01133                   break;
01134                 }
01135             }                   /* for */
01136 
01137         }
01138       /* if current_layer */
01139     }
01140 
01141   /* if command_func */
01142   /* command not found */
01143   if(!command_func)
01144     {
01145       snprintf(tracebuff, TRACEBUFFSIZE, "%s: command not found", argv[0]);
01146       shell_PrintError(context, tracebuff);
01147       return SHELL_NOT_FOUND;
01148     }
01149 
01150   /* verbose trace */
01151 
01152   if(shell_GetVerbose(context))
01153     {
01154       tracebuff[0] = '\0';
01155       for(i = 0; i < argc; i++)
01156         {
01157           /* + 1 = size of the additional char ( + or space) */
01158           size_t len1 = strlen(tracebuff) + 1;
01159           size_t len2 = strlen(argv[i]);
01160 
01161           if(len1 > TRACEBUFFSIZE - 1)
01162             break;
01163 
01164           if(i != 0)
01165             strcat(tracebuff, " ");
01166           else
01167             strcat(tracebuff, "+");
01168 
01169           if(len1 + len2 > TRACEBUFFSIZE - 1)
01170             {
01171               if(TRACEBUFFSIZE - 6 - len1 > 0)
01172                 strncat(tracebuff, argv[i], TRACEBUFFSIZE - 6 - len1);
01173 
01174               strcat(tracebuff, "[...]");
01175               break;
01176             }
01177           else
01178             {
01179               strcat(tracebuff, argv[i]);
01180             }
01181 
01182         }
01183     }
01184   shell_PrintTrace(context, tracebuff);
01185 
01186   /* execute the command */
01187 
01188   rc = command_func(argc, argv, output);
01189 
01190   /* verbose trace */
01191 
01192   snprintf(tracebuff, TRACEBUFFSIZE, "%s returned %d", argv[0], rc);
01193   shell_PrintTrace(context, tracebuff);
01194 
01195   return rc;
01196 
01197 }                               /* shell_Execute */
01198 
01199 /*------------------------------------------------------------------
01200  *                 Shell ouput routines.
01201  *-----------------------------------------------------------------*/
01202 
01207 void shell_PrintError(shell_state_t * context, char *error_msg)
01208 {
01209 
01210   char *input_name = get_var_value("INPUT");
01211 
01212   fprintf(stderr, "******* ERROR in %s line %d: %s\n",
01213           (input_name ? input_name : "?"), shell_GetLine(context), error_msg);
01214 
01215 }
01216 
01221 void shell_PrintTrace(shell_state_t * context, char *msg)
01222 {
01223 
01224   char *input_name;
01225 
01226   if(shell_GetVerbose(context))
01227     {
01228       input_name = get_var_value("INPUT");
01229 
01230       fprintf(stderr, "%s l.%d: %s\n",
01231               (input_name ? input_name : "?"), shell_GetLine(context), msg);
01232     }
01233 
01234 }
01235 
01236 /*------------------------------------------------------------------
01237  *                 Shell state management routines.
01238  *-----------------------------------------------------------------*/
01239 
01246 int shell_SetLayer(shell_state_t * context, char *layer_name)
01247 {
01248 
01249   layer_def_t *layer = NULL;
01250   int i, rc;
01251   char tracebuff[TRACEBUFFSIZE];
01252 
01253   /* search for layer */
01254 
01255   for(i = 0; layer_list[i].layer_name; i++)
01256     {
01257       if(!strcasecmp(layer_name, layer_list[i].layer_name))
01258         {
01259           layer = &layer_list[i];
01260           break;
01261         }
01262     }
01263 
01264   /* saves current layer */
01265 
01266   if(layer)
01267     {
01268       /* saves layer pointer */
01269 
01270       context->layer = layer;
01271 
01272       /* stores layer name into vars  */
01273 
01274       rc = set_var_value("LAYER", layer->layer_name);
01275 
01276       if(rc != 0)
01277         {
01278           snprintf(tracebuff, TRACEBUFFSIZE,
01279                    "Error %d setting LAYER value to %s", rc, layer->layer_name);
01280           shell_PrintError(context, tracebuff);
01281         }
01282 
01283       snprintf(tracebuff, TRACEBUFFSIZE, "Current layer is now %s", layer->layer_name);
01284       shell_PrintTrace(context, tracebuff);
01285 
01286       return SHELL_SUCCESS;
01287 
01288     }
01289   else
01290     {
01291       snprintf(tracebuff, TRACEBUFFSIZE, "Layer not found: %s", layer_name);
01292       shell_PrintError(context, tracebuff);
01293       return SHELL_NOT_FOUND;
01294     }
01295 
01296 }                               /* shell_SetLayer */
01297 
01302 layer_def_t *shell_GetLayer(shell_state_t * context)
01303 {
01304 
01305   return context->layer;
01306 
01307 }
01308 
01313 int shell_SetStatus(shell_state_t * context, int returned_status)
01314 {
01315 
01316   int rc;
01317   char str_int[64];
01318   char tracebuff[TRACEBUFFSIZE];
01319 
01320   context->status = returned_status;
01321 
01322   snprintf(str_int, 64, "%d", returned_status);
01323 
01324   rc = set_var_value("STATUS", str_int);
01325 
01326   if(rc != 0)
01327     {
01328       snprintf(tracebuff, TRACEBUFFSIZE,
01329                "Error %d setting STATUS value to %s", rc, str_int);
01330       shell_PrintError(context, tracebuff);
01331     }
01332 
01333   rc = set_var_value("?", str_int);
01334 
01335   if(rc != 0)
01336     {
01337       snprintf(tracebuff, TRACEBUFFSIZE, "Error %d setting ? value to %s", rc, str_int);
01338       shell_PrintError(context, tracebuff);
01339     }
01340 
01341   return SHELL_SUCCESS;
01342 
01343 }
01344 
01349 int shell_GetStatus(shell_state_t * context)
01350 {
01351   return context->status;
01352 }
01353 
01358 int shell_SetVerbose(shell_state_t * context, char *str_verbose)
01359 {
01360 
01361   int rc;
01362   char tracebuff[TRACEBUFFSIZE];
01363 
01364   if(!strcasecmp(str_verbose, "ON") ||
01365      !strcasecmp(str_verbose, "TRUE") ||
01366      !strcasecmp(str_verbose, "YES") || !strcmp(str_verbose, "1"))
01367     {
01368       context->verbose = TRUE;
01369 
01370       rc = set_var_value("VERBOSE", "1");
01371 
01372       if(rc != 0)
01373         {
01374           snprintf(tracebuff, TRACEBUFFSIZE,
01375                    "Error %d setting VERBOSE value to %s", rc, "1");
01376           shell_PrintError(context, tracebuff);
01377         }
01378 
01379       return SHELL_SUCCESS;
01380 
01381     }
01382   else if(!strcasecmp(str_verbose, "OFF") ||
01383           !strcasecmp(str_verbose, "FALSE") ||
01384           !strcasecmp(str_verbose, "NO") || !strcmp(str_verbose, "0"))
01385     {
01386       context->verbose = FALSE;
01387 
01388       rc = set_var_value("VERBOSE", "0");
01389 
01390       if(rc != 0)
01391         {
01392           snprintf(tracebuff, TRACEBUFFSIZE,
01393                    "Error %d setting VERBOSE value to %s", rc, "0");
01394           shell_PrintError(context, tracebuff);
01395         }
01396 
01397       return SHELL_SUCCESS;
01398 
01399     }
01400   else
01401     {
01402       snprintf(tracebuff, TRACEBUFFSIZE, "Unexpected value for VERBOSE: %s", str_verbose);
01403       shell_PrintError(context, tracebuff);
01404 
01405       return SHELL_SYNTAX_ERROR;
01406     }
01407 
01408 }
01409 
01414 int shell_GetVerbose(shell_state_t * context)
01415 {
01416   return context->verbose;
01417 }
01418 
01423 int shell_SetDbgLvl(shell_state_t * context, char *str_debug_level)
01424 {
01425   int level_debug;
01426   int rc;
01427   char tracebuff[TRACEBUFFSIZE];
01428 
01429   level_debug = ReturnLevelAscii(str_debug_level);
01430 
01431   if(level_debug != -1)
01432     {
01433       /* set shell state */
01434       context->debug_level = level_debug;
01435 
01436       /* call to logfunctions */
01437       SetLevelDebug(level_debug);
01438 
01439       /* set shell vars */
01440 
01441       rc = set_var_value("DEBUG_LEVEL", str_debug_level);
01442 
01443       if(rc != 0)
01444         {
01445           snprintf(tracebuff, TRACEBUFFSIZE,
01446                    "Error %d setting DEBUG_LEVEL value to %s", rc, str_debug_level);
01447           shell_PrintError(context, tracebuff);
01448         }
01449 
01450       rc = set_var_value("DBG_LVL", str_debug_level);
01451 
01452       if(rc != 0)
01453         {
01454           snprintf(tracebuff, TRACEBUFFSIZE,
01455                    "Error %d setting DBG_LVL value to %s", rc, str_debug_level);
01456           shell_PrintError(context, tracebuff);
01457         }
01458 
01459       return SHELL_SUCCESS;
01460 
01461     }
01462   else
01463     {
01464 
01465       snprintf(tracebuff, TRACEBUFFSIZE,
01466                "Unexpected value for DEBUG_LEVEL: %s", str_debug_level);
01467       shell_PrintError(context, tracebuff);
01468 
01469       return SHELL_SYNTAX_ERROR;
01470     }
01471 
01472 }                               /* shell_SetDbgLvl */
01473 
01478 int shell_GetDbgLvl(shell_state_t * context)
01479 {
01480   return context->debug_level;
01481 }
01482 
01491 int shell_SetInput(shell_state_t * context, char *file_name)
01492 {
01493 
01494   FILE *stream;
01495   int rc;
01496   char tracebuff[TRACEBUFFSIZE];
01497 
01498   if(file_name)
01499     {
01500       if((stream = fopen(file_name, "r")) == NULL)
01501         {
01502           snprintf(tracebuff, TRACEBUFFSIZE, "Can't open \"%s\": %s (%d)",
01503                    file_name, strerror(errno), errno);
01504           shell_PrintError(context, tracebuff);
01505           return errno;
01506         }
01507 
01508       /* close previous filestream and reset line number */
01509       if(context->input_stream != NULL)
01510         {
01511           /* don't close stdin */
01512           if(context->input_stream != stdin)
01513             fclose(context->input_stream);
01514 
01515           shell_SetLine(context, 0);
01516         }
01517 
01518       /* set filestream */
01519       context->input_stream = stream;
01520 
01521       rc = set_var_value("INPUT", file_name);
01522 
01523       if(rc != 0)
01524         {
01525           snprintf(tracebuff, TRACEBUFFSIZE,
01526                    "Error %d setting INPUT value to \"%s\"", rc, file_name);
01527           shell_PrintError(context, tracebuff);
01528         }
01529 
01530       /* set interative mode to FALSE */
01531 
01532       context->interactive = FALSE;
01533 
01534       rc = set_var_value("INTERACTIVE", "0");
01535 
01536       if(rc != 0)
01537         {
01538           snprintf(tracebuff, TRACEBUFFSIZE,
01539                    "Error %d setting INTERACTIVE value to %s", rc, "0");
01540           shell_PrintError(context, tracebuff);
01541         }
01542 
01543       snprintf(tracebuff, TRACEBUFFSIZE, "Using script file \"%s\"", file_name);
01544       shell_PrintTrace(context, tracebuff);
01545 
01546       return SHELL_SUCCESS;
01547 
01548     }
01549   else
01550     {
01551       stream = stdin;
01552 
01553       /* close previous filestream and reset line number */
01554       if(context->input_stream != NULL)
01555         {
01556           /* don't close stdin */
01557           if(context->input_stream != stdin)
01558             fclose(context->input_stream);
01559           shell_SetLine(context, 0);
01560         }
01561 
01562       /* set filestream */
01563       context->input_stream = stream;
01564 
01565       rc = set_var_value("INPUT", "<stdin>");
01566 
01567       if(rc != 0)
01568         {
01569           snprintf(tracebuff, TRACEBUFFSIZE,
01570                    "Error %d setting INPUT value to %s", rc, "<stdin>");
01571           shell_PrintError(context, tracebuff);
01572         }
01573 
01574       /* set interative mode to TRUE */
01575 
01576       context->interactive = TRUE;
01577 
01578       rc = set_var_value("INTERACTIVE", "1");
01579 
01580       if(rc != 0)
01581         {
01582           snprintf(tracebuff, TRACEBUFFSIZE,
01583                    "Error %d setting INTERACTIVE value to %s", rc, "1");
01584           shell_PrintError(context, tracebuff);
01585         }
01586 
01587       snprintf(tracebuff, TRACEBUFFSIZE, "Using standard input");
01588       shell_PrintTrace(context, tracebuff);
01589 
01590       return SHELL_SUCCESS;
01591 
01592     }
01593 
01594 }                               /* shell_SetInput */
01595 
01600 FILE *shell_GetInputStream(shell_state_t * context)
01601 {
01602   if(context->input_stream)
01603     return context->input_stream;
01604   else
01605     return stdin;
01606 }
01607 
01612 int shell_SetPrompt(shell_state_t * context, char *str_prompt)
01613 {
01614   int rc = set_var_value("PROMPT", str_prompt);
01615   char tracebuff[TRACEBUFFSIZE];
01616 
01617   if(rc != 0)
01618     {
01619       snprintf(tracebuff, TRACEBUFFSIZE,
01620                "Error %d setting PROMPT value to \"%s\"", rc, str_prompt);
01621       shell_PrintError(context, tracebuff);
01622     }
01623 
01624   return rc;
01625 }
01626 
01631 char *shell_GetPrompt(shell_state_t * context)
01632 {
01633   return get_var_value("PROMPT");
01634 }
01635 
01640 int shell_SetShellId(shell_state_t * context, int shell_index)
01641 {
01642   int rc;
01643   char str[64];
01644   char tracebuff[TRACEBUFFSIZE];
01645 
01646   snprintf(str, 64, "%d", shell_index);
01647 
01648   rc = set_var_value("SHELLID", str);
01649 
01650   if(rc != 0)
01651     {
01652       snprintf(tracebuff, TRACEBUFFSIZE,
01653                "Error %d setting SHELLID value to \"%s\"", rc, str);
01654       shell_PrintError(context, tracebuff);
01655     }
01656 
01657   return SHELL_SUCCESS;
01658 }
01659 
01664 int shell_SetLine(shell_state_t * context, int lineno)
01665 {
01666   int rc;
01667   char str_line[64];
01668   char tracebuff[TRACEBUFFSIZE];
01669 
01670   context->line = lineno;
01671 
01672   snprintf(str_line, 64, "%d", lineno);
01673 
01674   rc = set_var_value("LINE", str_line);
01675 
01676   if(rc != 0)
01677     {
01678       snprintf(tracebuff, TRACEBUFFSIZE,
01679                "Error %d setting LINE value to \"%s\"", rc, str_line);
01680       shell_PrintError(context, tracebuff);
01681     }
01682 
01683   return SHELL_SUCCESS;
01684 
01685 }
01686 
01691 int shell_GetLine(shell_state_t * context)
01692 {
01693   return context->line;
01694 }
01695 
01696 /*------------------------------------------------------------------
01697  *                      Shell commands.
01698  *-----------------------------------------------------------------*/
01699 
01700 int shellcmd_help(int argc,     /* IN : number of args in argv */
01701                   char **argv,  /* IN : arg list               */
01702                   FILE * output /* IN : output stream          */
01703     )
01704 {
01705 
01706   int i;
01707   char tracebuff[TRACEBUFFSIZE];
01708   layer_def_t *current_layer = shell_GetLayer(GetShellContext());
01709 
01710   /* check args */
01711 
01712   if(argc > 1)
01713     {
01714       for(i = 1; i < argc; i++)
01715         {
01716           snprintf(tracebuff, TRACEBUFFSIZE,
01717                    "%s: Unexpected argument \"%s\"", argv[0], argv[i]);
01718           shell_PrintError(GetShellContext(), tracebuff);
01719         }
01720     }
01721 
01722   /* List shell build-in commands */
01723 
01724   fprintf(output, "Shell built-in commands:\n");
01725 
01726   for(i = 0; shell_commands[i].command_name; i++)
01727     {
01728       fprintf(output, "   %15s: %s\n", shell_commands[i].command_name,
01729               shell_commands[i].command_help);
01730     }
01731 
01732   /* List shell tools commands */
01733 
01734   fprintf(output, "\nShell tools commands:\n");
01735 
01736   for(i = 0; shell_utils[i].command_name; i++)
01737     {
01738       fprintf(output, "   %15s: %s\n", shell_utils[i].command_name,
01739               shell_utils[i].command_help);
01740     }
01741 
01742   /* Layer list */
01743 
01744   fprintf(output, "\nLayers list:\n");
01745 
01746   for(i = 0; layer_list[i].layer_name; i++)
01747     {
01748       fprintf(output, "   %15s: %s\n", layer_list[i].layer_name,
01749               layer_list[i].layer_description);
01750     }
01751 
01752   /* Layer commands */
01753 
01754   if(current_layer)
01755     {
01756 
01757       fprintf(output, "\n%s layer commands:\n", current_layer->layer_name);
01758 
01759       for(i = 0; current_layer->command_list[i].command_name; i++)
01760         {
01761           fprintf(output, "   %15s: %s\n", current_layer->command_list[i].command_name,
01762                   current_layer->command_list[i].command_help);
01763         }
01764 
01765     }
01766 
01767   return SHELL_SUCCESS;
01768 
01769 }                               /* shellcmd_help */
01770 
01771 int shellcmd_if(int argc,       /* IN : number of args in argv */
01772                 char **argv,    /* IN : arg list               */
01773                 FILE * output   /* IN : output stream          */
01774     )
01775 {
01776 
01777   int i, rc;
01778   int index_test = -1;
01779   int longueur_test = -1;
01780   int index_cmd1 = -1;
01781   int longueur_cmd1 = -1;
01782   int index_cmd2 = -1;
01783   int longueur_cmd2 = -1;
01784 
01785   const char *help_if =
01786       "Usage: if command0 ? command1 [: command2]\n"
01787       "   Execute command1 if command0 returns a null status.\n"
01788       "   Else, execute command2 (if any).\n"
01789       "Ex: if eq -n $STATUS 0 ? print \"status=0\" : print \"status<>0\" \n";
01790 
01791   /* first, check that there is a test */
01792   if(argc > 1)
01793     {
01794 
01795       index_test = 1;
01796 
01797       i = index_test + 1;
01798 
01799       /* look for command 1 */
01800 
01801       while((i < argc) && strcmp(argv[i], "?"))
01802         i++;
01803 
01804       if(i + 1 < argc)
01805         {
01806           longueur_test = i - index_test;
01807           index_cmd1 = i + 1;
01808 
01809           i = index_cmd1 + 1;
01810 
01811           /* look for command 2 */
01812 
01813           while((i < argc) && strcmp(argv[i], ":"))
01814             i++;
01815 
01816           if(i + 1 < argc)
01817             {
01818               longueur_cmd1 = i - index_cmd1;
01819               index_cmd2 = i + 1;
01820               longueur_cmd2 = argc - index_cmd2;
01821             }
01822           else
01823             {
01824               longueur_cmd1 = argc - index_cmd1;
01825             }
01826 
01827         }
01828       else
01829         {
01830           longueur_test = argc - index_test;
01831         }
01832 
01833     }
01834 
01835   /* test or cmd1 missing */
01836 
01837   if((longueur_test <= 0) || (longueur_cmd1 <= 0))
01838     {
01839       fprintf(output, help_if, NULL);
01840       return SHELL_SYNTAX_ERROR;
01841     }
01842 
01843   /* executes test */
01844 
01845   rc = shell_Execute(longueur_test, &(argv[index_test]), output);
01846 
01847   /* if rc is not null, executes command 1 */
01848   if(rc)
01849     {
01850       return shell_Execute(longueur_cmd1, &(argv[index_cmd1]), output);
01851     }
01852   else if(longueur_cmd2 > 0)
01853     {
01854       return shell_Execute(longueur_cmd2, &(argv[index_cmd2]), output);
01855     }
01856 
01857   return 0;
01858 
01859 }                               /* shellcmd_if */
01860 
01861 int shellcmd_interactive(int argc,      /* IN : number of args in argv */
01862                          char **argv,   /* IN : arg list               */
01863                          FILE * output  /* IN : output stream          */
01864     )
01865 {
01866   int i;
01867   char tracebuff[TRACEBUFFSIZE];
01868 
01869   /* check args */
01870 
01871   if(argc > 1)
01872     {
01873       for(i = 1; i < argc; i++)
01874         {
01875           snprintf(tracebuff, TRACEBUFFSIZE,
01876                    "%s: Unexpected argument \"%s\"", argv[0], argv[i]);
01877           shell_PrintError(GetShellContext(), tracebuff);
01878         }
01879     }
01880 
01881   /* set input as stdin */
01882 
01883   return shell_SetInput(GetShellContext(), NULL);
01884 
01885 }                               /* shellcmd_interactive */
01886 
01887 int shellcmd_set(int argc,      /* IN : number of args in argv */
01888                  char **argv,   /* IN : arg list               */
01889                  FILE * output  /* IN : output stream          */
01890     )
01891 {
01892 
01893   int i;
01894   char *varname;
01895   char tracebuff[TRACEBUFFSIZE];
01896   char varvalue[MAX_OUTPUT_LEN];
01897 
01898   /* check args */
01899 
01900   if(argc < 3)
01901     {
01902       snprintf(tracebuff, TRACEBUFFSIZE,
01903                "%s: Usage: %s <var_name> <expr1> [<expr2> ...<exprN>]", argv[0], argv[0]);
01904       shell_PrintError(GetShellContext(), tracebuff);
01905 
01906       return SHELL_SYNTAX_ERROR;
01907     }
01908 
01909   varname = argv[1];
01910 
01911   varvalue[0] = '\0';
01912 
01913   /* concatenation of strings */
01914 
01915   for(i = 2; i < argc; i++)
01916     if(concat(varvalue, argv[i], MAX_OUTPUT_LEN) == NULL)
01917       {
01918         shell_PrintError(GetShellContext(), "Output too large.");
01919         return SHELL_ERROR;
01920       }
01921 
01922   /* special variables */
01923 
01924   if(!strcmp(varname, "INPUT"))
01925     {
01926       return shell_SetInput(GetShellContext(), varvalue);
01927     }
01928   else if(!strcmp(varname, "INTERACTIVE"))
01929     {
01930       snprintf(tracebuff, TRACEBUFFSIZE,
01931                "%s: cannot set \"%s\": set the value of \"INPUT\" or use the \"interactive\" command instead.",
01932                argv[0], varname);
01933       shell_PrintError(GetShellContext(), tracebuff);
01934 
01935       return SHELL_ERROR;
01936 
01937     }
01938   else if(!strcmp(varname, "LAYER"))
01939     {
01940       return shell_SetLayer(GetShellContext(), varvalue);
01941     }
01942   else if(!strcmp(varname, "STATUS") || !strcmp(varname, "?"))
01943     {
01944       return shell_SetStatus(GetShellContext(), my_atoi(varvalue));
01945     }
01946   else if(!strcmp(varname, "VERBOSE"))
01947     {
01948       return shell_SetVerbose(GetShellContext(), varvalue);
01949     }
01950   else if(!strcmp(varname, "DEBUG_LEVEL") || !strcmp(varname, "DBG_LVL"))
01951     {
01952       return shell_SetDbgLvl(GetShellContext(), varvalue);
01953     }
01954   else if(!strcmp(varname, "PROMPT"))
01955     {
01956       return shell_SetPrompt(GetShellContext(), varvalue);
01957     }
01958   else if(!strcmp(varname, "LINE"))
01959     {
01960       snprintf(tracebuff, TRACEBUFFSIZE, "%s: cannot set \"%s\".", argv[0], varname);
01961       shell_PrintError(GetShellContext(), tracebuff);
01962       return SHELL_ERROR;
01963     }
01964   else
01965     {
01966 
01967       /* other variables */
01968 
01969       if(!is_authorized_varname(varname))
01970         {
01971           snprintf(tracebuff, TRACEBUFFSIZE, "%s: Invalid variable name \"%s\".", argv[0],
01972                    varname);
01973           shell_PrintError(GetShellContext(), tracebuff);
01974           return SHELL_ERROR;
01975         }
01976 
01977       if(set_var_value(varname, varvalue))
01978         {
01979           snprintf(tracebuff, TRACEBUFFSIZE, "%s: Error setting the value of \"%s\".",
01980                    argv[0], varname);
01981           shell_PrintError(GetShellContext(), tracebuff);
01982           return SHELL_ERROR;
01983         }
01984 
01985       return SHELL_SUCCESS;
01986 
01987     }
01988 
01989   /* should never happen */
01990   return SHELL_ERROR;
01991 
01992 }                               /* shellcmd_set */
01993 
01994 int shellcmd_unset(int argc,    /* IN : number of args in argv */
01995                    char **argv, /* IN : arg list               */
01996                    FILE * output        /* IN : output stream          */
01997     )
01998 {
01999 
02000   int i, arg_idx;
02001   char tracebuff[TRACEBUFFSIZE];
02002   int error = SHELL_SUCCESS;
02003 
02004   if(argc <= 1)
02005     {
02006       snprintf(tracebuff, TRACEBUFFSIZE, "%s: Missing argument: <var name>", argv[0]);
02007       shell_PrintError(GetShellContext(), tracebuff);
02008 
02009       return SHELL_SYNTAX_ERROR;
02010     }
02011 
02012   for(arg_idx = 1; arg_idx < argc; arg_idx++)
02013     {
02014 
02015       /* check if it is not a special var */
02016 
02017       for(i = 0; shell_special_vars[i] != NULL; i++)
02018         {
02019 
02020           if(!strcmp(shell_special_vars[i], argv[arg_idx]))
02021             {
02022 
02023               snprintf(tracebuff, TRACEBUFFSIZE,
02024                        "%s: This special variable cannot be deleted: \"%s\"", argv[0],
02025                        argv[arg_idx]);
02026               shell_PrintError(GetShellContext(), tracebuff);
02027 
02028               return SHELL_ERROR;
02029 
02030             }
02031 
02032         }
02033 
02034       /* unset the variable */
02035 
02036       if(free_var(argv[arg_idx]))
02037         {
02038           snprintf(tracebuff, TRACEBUFFSIZE,
02039                    "%s: Variable not found: \"%s\"", argv[0], argv[arg_idx]);
02040           shell_PrintError(GetShellContext(), tracebuff);
02041 
02042           error = SHELL_NOT_FOUND;
02043           /* however, continue */
02044         }
02045 
02046     }
02047 
02048   return error;
02049 
02050 }                               /* shellcmd_unset */
02051 
02052 int shellcmd_print(int argc,    /* IN : number of args in argv */
02053                    char **argv, /* IN : arg list               */
02054                    FILE * output        /* IN : output stream          */
02055     )
02056 {
02057 
02058   int i;
02059 
02060   /* print args */
02061   for(i = 1; i < argc; i++)
02062     fprintf(output, "%s", argv[i]);
02063 
02064   fprintf(output, "\n");
02065 
02066   return 0;
02067 
02068 }                               /* shellcmd_print */
02069 
02070 int shellcmd_varlist(int argc,  /* IN : number of args in argv */
02071                      char **argv,       /* IN : arg list               */
02072                      FILE * output      /* IN : output stream          */
02073     )
02074 {
02075   int i;
02076   char tracebuff[TRACEBUFFSIZE];
02077 
02078   /* check args */
02079 
02080   if(argc > 1)
02081     {
02082       for(i = 1; i < argc; i++)
02083         {
02084           snprintf(tracebuff, TRACEBUFFSIZE,
02085                    "%s: Unexpected argument \"%s\"", argv[0], argv[i]);
02086           shell_PrintError(GetShellContext(), tracebuff);
02087         }
02088     }
02089 
02090   print_varlist(output, shell_GetVerbose(GetShellContext()));
02091 
02092   return 0;
02093 
02094 }                               /* shellcmd_varlist */
02095 
02096 int shellcmd_time(int argc,     /* IN : number of args in argv */
02097                   char **argv,  /* IN : arg list               */
02098                   FILE * output /* IN : output stream          */
02099     )
02100 {
02101 
02102   const char help_time[] =
02103       "Usage: time command [args ...]\n"
02104       "   Measure the time for executing a command.\n" "Ex: time shell ls\n";
02105 
02106   struct timeval timer_start;
02107   struct timeval timer_stop;
02108   struct timeval timer_tmp;
02109 
02110   int rc;
02111 
02112   /* first, check that there is a test */
02113   if(argc < 2)
02114     {
02115       fprintf(output, help_time);
02116       return SHELL_SYNTAX_ERROR;
02117     }
02118 
02119   if(gettimeofday(&timer_start, NULL) == -1)
02120     {
02121       fprintf(output, "Error retrieving system time.\n");
02122       return SHELL_ERROR;
02123     }
02124 
02125   rc = shell_Execute(argc - 1, &(argv[1]), output);
02126 
02127   if(gettimeofday(&timer_stop, NULL) == -1)
02128     {
02129       fprintf(output, "Error retrieving system time.\n");
02130       return SHELL_ERROR;
02131     }
02132 
02133   timer_tmp = time_diff(timer_start, timer_stop);
02134   fprintf(output, "\nExecution time for command \"%s\": ", argv[1]);
02135   print_timeval(output, timer_tmp);
02136 
02137   return rc;
02138 
02139 }                               /* shellcmd_time */
02140 
02141 int shellcmd_quit(int argc,     /* IN : number of args in argv */
02142                   char **argv,  /* IN : arg list               */
02143                   FILE * output /* IN : output stream          */
02144     )
02145 {
02146   int i;
02147   char tracebuff[TRACEBUFFSIZE];
02148 
02149   /* check args */
02150 
02151   if(argc > 1)
02152     {
02153       for(i = 1; i < argc; i++)
02154         {
02155           snprintf(tracebuff, TRACEBUFFSIZE,
02156                    "%s: Unexpected argument \"%s\"", argv[0], argv[i]);
02157           shell_PrintError(GetShellContext(), tracebuff);
02158         }
02159     }
02160 
02161   exit(0);
02162   return 0;
02163 
02164 }                               /* shellcmd_quit */
02165 
02166 int shellcmd_barrier(int argc,  /* IN : number of args in argv */
02167                      char **argv,       /* IN : arg list               */
02168                      FILE * output      /* IN : output stream          */
02169     )
02170 {
02171   int i;
02172   char tracebuff[TRACEBUFFSIZE];
02173 
02174   /* check args */
02175 
02176   if(argc > 1)
02177     {
02178       for(i = 1; i < argc; i++)
02179         {
02180           snprintf(tracebuff, TRACEBUFFSIZE,
02181                    "%s: Unexpected argument \"%s\"", argv[0], argv[i]);
02182           shell_PrintError(GetShellContext(), tracebuff);
02183         }
02184     }
02185 
02186   /* call shell_BarrierWait */
02187 
02188   if(shell_BarrierWait())
02189     {
02190       snprintf(tracebuff, TRACEBUFFSIZE,
02191                "%s: barrier cannot be used in a single thread/script environment.",
02192                argv[0]);
02193       shell_PrintError(GetShellContext(), tracebuff);
02194       return SHELL_ERROR;
02195     }
02196 
02197   return SHELL_SUCCESS;
02198 
02199 }                               /* shellcmd_quit */