LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 11-21-2015, 08:58 AM   #1
AntoineCompagnie
LQ Newbie
 
Registered: Nov 2015
Posts: 2

Rep: Reputation: Disabled
Lightbulb Creating one's own shell! segmentation error...


hello there!

I'm studying Linux since September and I have an project to submit, we have to recreate one's own shell.

I already developed the main, command and parsing (which I should not change). I'm not able to place simple commands in the arrays I created to execute my functions, according to the terminal it is a segmentation error: an "Erreur de segmentation (core dumped)" (sorry, excuse my French). I 'm maybe exploding the array I'm using, maybe I should not declare them at the beginning, I tought using their adress "*" should help me, but nothing changed...

From my error file which I called imp, I know I'm not even entering the case 10.

Here is my code, take a big breath...

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>

int resCommande =0;
int resp=0;
char *resP[];
int status;
char *com[];
int pid;
int status;
char *delimiteurs=";&<>|";
char mot[50];
char c;
char param;
int symboleP;
int execute;
int lettre=0;

int parsing(){
    //int c;
    int i=0;
    int cmot=0;
    fprintf(stderr,"debut parsing\n");
    //if(eof == 1){printf("DAUPHINE> ");fflush(stdout);eof=0;}
    while(1){
        c = getchar();
  	fprintf(stderr,"debut while\n");
        //if(xc == c && c == 10){eof=1;fprintf(stderr,"car double\n");return;}
        fprintf(stderr,"cartographie-lu d %c\n",c,c);
        if      (c == '\n') {symboleP = 0;return 0;}
        else if (c == ';')  {symboleP = 1;return 1;}
        else if (c == '&')  {symboleP = 2;return 2;}
        else if (c == '<')  {symboleP = 3;return 3;}
        else if (c == '>')  {symboleP = 4;return 4;}
        else if (c == '|')  {symboleP = 5;return 5;}
        //else if (c == ' ')  {symboleP = 6;return;}
        else if (c == EOF)  {symboleP = 7;return 7;}
        else if (c != ' ') {
            // on rentre ds une seq.
            symboleP = 10;
            //fprintf(stderr,"car-lu 10\n");
            while(c != '\n' && !strchr(delimiteurs,c)){
                i=0;
		   fprintf(stderr,"debut second while\n");
                
                while(c != 32 ){
		   fprintf(stderr,"debut troisime while\n");
                    if((c != '\n') && !strchr(delimiteurs,c)){
			   fprintf(stderr,"debut if\n");
                    //fprintf(stderr,"boucle\n");
                    mot[i]=c;i++;
                    c=getchar();/*fprintf(stderr,"val carac %d\n",c);*/
                    }
                    //fprintf(stderr,"fin de mot\n");
                    else {/*fprintf(stderr,"break\n");*/break;}
                        
                }
                break;

                    
            }
            while(c == ' '){c=getchar();}com[
            ungetc(c,stdin);
            mot[i]='\0';
            resP[cmot++]=strdup(mot);
            fprintf(stderr,"element comm lue %s %s\n",resP[0],resP[1]);
            if(c == '\n' || strchr(delimiteurs,c)){resP[cmot]=0;if(c!='\n')ungetc(c,stdin);return 10;}
        }

    }// attention on a consomm le delimiteur
        fprintf(stderr,"elt comm lue %s %s\n",resP[0],resP[1]);

    
}

int commande(int fin,int fout,char * com, char * param, int *bg){// c'est qui param? Il est pas dclar param l?
        int s;
       parsing();
        fprintf(stderr,"rsultat parsing %d\n",s);

    switch(symboleP){
        case 0: // NL
            // excution commande ?com[

            pid=fork();//obligation de faire un fork sion le programme s'arrte
                if(pid==0){

        
                    resCommande = 2;
                    execvp(resP[0],resp);
                }else{
                    if(bg==0){                //pas de bg on attend le fils
                        waitpid(pid, NULL, 0);
                }            
                    execute=1;
                    
		}

		break;

                // excution commande ? res= ?
        case 1: // ;
        case 2: // &
        case 3: // <
        case 4: // >
        case 5: // |
        case 7: // EOF
        case 10: 
            /*eltsCommande[cmot++]=strdup(mot);
			
/*execvp(mot[]);      // mot
execvp(mot)?*/

           	default:
                printf(" ");

        }
    
    return 0 ;
}








int main(int argc, char* argv[]) {
// creation d'un fichier recuperant les impressions intermediaires (deboggage)
        int fmess = open("imp", O_WRONLY|O_TRUNC|O_CREAT, 0640);
        close(2);
        dup(fmess);
        close(fmess);
        char *com[20];
        int status;
        int bg;
        //int eof= 0;
        printf("DAUPHINE> ");
        fflush(stdout);

        while(1){
        if(resCommande ==2){
            resCommande = 0;
            //eof = 0;
            printf("DAUPHINE> ");
            fflush(stdout);
            }
        else{
            commande(0,1,&com,&param,&bg);// c'est ou param?
            }
        return 0;
}

}

Last edited by AntoineCompagnie; 11-21-2015 at 09:00 AM. Reason: shown my reaserch
 
Old 11-21-2015, 09:33 AM   #2
berndbausch
LQ Addict
 
Registered: Nov 2013
Location: Tokyo
Distribution: Mostly Ubuntu and Centos
Posts: 6,316

Rep: Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002
Where I am it's too late in the night to analyse or run a program I don't know, so just a suggestion.

Quote:
Originally Posted by AntoineCompagnie View Post
"Erreur de segmentation (core dumped)"
Funny mix of English and French. But you know what this means, right? The program accesses an address which it had no right to access, or which didn't exist. Typical causes are stepping beyond array bounds or using a pointer before initializing it.

If you don't know how to use a debugger, liberally sprinkle your code with printf's so that you can find out where the error occurs.

By the way, you should get English error messages by setting the shell variable LANG to, for example, "en_US.utf-8".
 
Old 11-21-2015, 01:07 PM   #3
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
well... one error I see is in "commande(0,1,&com,&param,&bg)"

com is an array of pointers ... so you are passing the address of an address.... I would think the & there is incorrect.
 
Old 11-23-2015, 08:35 AM   #4
AntoineCompagnie
LQ Newbie
 
Registered: Nov 2015
Posts: 2

Original Poster
Rep: Reputation: Disabled
Okay, I'm tried but still, command is:

int commande(int fin,int fout,char * com, char * param, int *bg).

And I have still this core dumped error error, besides.

Last edited by AntoineCompagnie; 11-23-2015 at 08:38 AM.
 
Old 11-23-2015, 09:06 AM   #5
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
Your declaration for com (as far as I can see) is "char *com[];" as a global.

Your function definition is "int commande(int fin,int fout,char * com, char * param, int *bg)", which gives a pointer to character.

Yet your invocation is "commande(0,1,&com,&param,&bg)"

where com appears to be an array of pointers to strings - and you are passing the address of the address... Even passing com alone is passing a pointer to an array of pointers. Not a pointer to an array of characters.

Not a specific string. Assuming "com" is initialized, the invocation would be "commande(0,1,com[<some index here>],&param,&bg)

Another thing is that your use of "resP" seems off. It is declared as a pointer to an array of pointers to characters... but... the array itself doesn't seem to be allocated anywhere, so using "resP[cmot++]" appears to be assigning a string pointer to an element of a nonexistent array.

Last edited by jpollard; 11-23-2015 at 09:14 AM.
 
Old 11-24-2015, 01:20 AM   #6
psionl0
Member
 
Registered: Jan 2011
Distribution: slackware_64 14.1
Posts: 722
Blog Entries: 2

Rep: Reputation: 124Reputation: 124
Quote:
Originally Posted by jpollard View Post
Another thing is that your use of "resP" seems off. It is declared as a pointer to an array of pointers to characters... but... the array itself doesn't seem to be allocated anywhere, so using "resP[cmot++]" appears to be assigning a string pointer to an element of a nonexistent array.
That's the first thing I noticed.

Whenever you have pointers (and especially pointers to pointers) you should always double check that they point to something valid or you will get a seg fault at best and mysterious bugs at worst.
 
Old 11-24-2015, 05:45 AM   #7
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
Personally, I think this needs to be simplified... The "commande" function only needs to execute the command... not also try to interpret shell options. All it really needs to do is handle the parameters to the command, output error messages for the possible failures.

There is also a dearth of comments - the declarations need to have something to explain why it is present. It would also be useful to know what the purpose of the functions are (though at this point, that is less of a problem).

A shell interpreter is not intrinsically complex - it doesn't need fancy programming (pipes, background processing, even environment handling) to start with. Once the basic "interpret commands" allows it to execute various utilities those features can be added.

Keep the initial interpreter as simple as possible.
 
Old 11-30-2015, 09:56 AM   #8
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,882
Blog Entries: 13

Rep: Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930
You should be using the debugger to diagnose this segmentation violation.

When you compile, I'm assuming you're using GCC, you need to add the flag: -ggdb to add symbols for GDB debugging.

Further, adding extra compilation flags such as -Wall and other flags will be helpful in showing you warnings as well as errors. I don't recommend you ignore warnings. And as posted, there are errors in the code you posted, it will not compile. Here are some suggested flags to use to compile your file:
Code:
-ggdb -Wformat=2 -Werror -Wall -Wextra -Wswitch-default -Wswitch-enum -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wmissing-noreturn
I recommend you strive to attain warning free code as you do your experimentations with C programming.

As far as how to debug a segment violation. The -ggdb flag is important. Also when you run your program from a terminal, setting your user limit for core file is important:
Code:
ulimit -c unlimited
Issue that statement in the terminal you're using to ensure that it will cause a core file dump when you encounter the segment violation. This appears to already be set given the output that a core file was created. Next, providing you compiled using the -ggdb flag, you can use GDB to debug the core file, for example say your executable file name was "myshell" you would then do something like the following:
Code:
gdb myshell core
And once within GDB, you could then issue the backtrace command, "bt" and see a report on where the problem occurred. You can also examine variables, pointers, and their locations, and use this information to diagnose where you did something wrong, such as not properly initializing a pointer.
 
Old 12-11-2015, 01:37 PM   #9
joel2001k
Member
 
Registered: Mar 2007
Distribution: GNU/Linux debian unstable main
Posts: 95

Rep: Reputation: 17
Might be helpful

Code:
#include <string.h>

static const char **my_text = {
  "This is some sample string.\0",
  "It shows you a static const char array[][]\0",
  "The array is terminated by NULL\0",
  "Do further reading on alternate ways.\0",
  NULL
};
// You might want to do dynamic memory allocation

Code:
#include "nv_terminal_emulator.h"
 
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <term.h>
#include <termios.h>
 
void nv_terminal_emulator_class_init(NvTerminalEmulatorClass *emulator);
void nv_terminal_emulator_init(NvTerminalEmulator *emulator);
void nv_terminal_emulator_finalize(GObject *gobject);
 
gchar* nv_terminal_emulator_readline(NvTerminalEmulator *emulator);
gchar* nv_terminal_emulator_unescape(NvTerminalEmulator *emulator,
                     gchar *str);
const gchar* nv_terminal_emulator_lookup(NvTerminalEmulator *emulator,
                     gchar *str,
                     gboolean suid_path);
 
static gpointer nv_terminal_emulator_parent_class = NULL;
 
GType
nv_terminal_emulator_get_type()
{
  static GType nv_type_terminal_emulator = 0;
 
  if(!nv_type_terminal_emulator){
    static const GTypeInfo nv_terminal_emulator_info = {
      sizeof (NvTerminalEmulatorClass),
      NULL, /* base_init */
      NULL, /* base_finalize */
      (GClassInitFunc) nv_terminal_emulator_class_init,
      NULL, /* class_finalize */
      NULL, /* class_data */
      sizeof (NvTerminalEmulator),
      0,    /* n_preallocs */
      (GInstanceInitFunc) nv_terminal_emulator_init,
    };
 
    nv_type_terminal_emulator = g_type_register_static(G_TYPE_OBJECT,
                               "NvTerminalEmulator\0", &nv_terminal_emulator_info,
                               0);
  }
 
  return(nv_type_terminal_emulator);
}
 
void
nv_terminal_emulator_class_init(NvTerminalEmulatorClass *emulator)
{
  GObjectClass *gobject;
 
  nv_terminal_emulator_parent_class = g_type_class_peek_parent(emulator);
 
  /* GObjectClass */
  gobject = (GObjectClass *) emulator;
 
  gobject->finalize = nv_terminal_emulator_finalize;
}
 
void
nv_terminal_emulator_init(NvTerminalEmulator *emulator)
{
}
 
void
nv_terminal_emulator_finalize(GObject *gobject)
{
  G_OBJECT_CLASS(nv_terminal_emulator_parent_class)->finalize(gobject);
}
 
gchar*
nv_terminal_emulator_readline(NvTerminalEmulator *emulator)
{
  gchar *str;
  gchar *buffer, *iter;
  gchar c;
  unsigned int escapes;
  gboolean control_sequence;
 
  static const unsigned int buffer_size = 256;
 
  str = NULL;
  buffer = (gchar *) malloc(buffer_size * sizeof(gchar));
  memset(buffer, 0, buffer_size * sizeof(gchar));
 
  iter = buffer;
  escapes = 0;
 
 nv_terminal_emulator_readlineREPEAT:
 
  while((c = getchar()) != '\n'){
    control_sequence = FALSE;
 
    if(control_sequence){
      continue;
    }
 
    *iter = c;
     
    if(c == '\\'){
      escapes++;
    }else{
      escapes = 0;
    }
 
    iter++;
 
    if(iter == &(buffer[buffer_size - 1])){
      *iter = '\0';
     
      if(str == NULL){
    str = g_strdup(buffer);
      }else{
    str = g_strconcat(str,
              buffer,
              NULL);
      }
 
      iter = buffer;
      memset(buffer, 0, buffer_size * sizeof(gchar));
    }
  }
 
  if(iter != buffer){
    *iter = '\0';
 
    if(str == NULL){
      str = g_strdup(buffer);
    }else{
      str = g_strconcat(str,
            buffer,
            NULL);
    }
  }
 
  if(escapes  2 == 1){
    escapes = 0;
 
    if(str == NULL){
      str = g_strdup("\n\0");
    }else{
      str = g_strconcat(str,
            "\n\0",
            NULL);
    }
 
    iter = buffer;
    memset(buffer, 0, buffer_size * sizeof(gchar));
 
    goto nv_terminal_emulator_readlineREPEAT;
  }
 
  return(str);
}
 
gchar*
nv_terminal_emulator_unescape(NvTerminalEmulator *emulator,
                  gchar *str)
{
  str = g_strcompress(str);
 
  return(str);
}
 
const gchar*
nv_terminal_emulator_lookup(NvTerminalEmulator *emulator,
                gchar *str,
                gboolean suid_path)
{
  gchar **path;
 
  auto gboolean nv_terminal_emulator_lookup_path(gchar *path);
 
  static const gchar *search_path[] = {
    "/bin\0",
    "/usr/bin\0",
    "/usr/X11/bin\0",
    "/opt/local/bin\0",
    NULL,
  };
  static const gchar *suid_search_path[] = {
    "/sbin\0",
    "/usr/sbin\0",
    NULL,
  };
 
  gboolean nv_terminal_emulator_lookup_path(gchar *path){
    DIR *directory;
    struct dirent *entry;
 
    directory = opendir(path);
 
    while((entry = readdir(directory)) != NULL){
      switch(entry->d_type){
      case DT_REG:
    {
      if(!g_strcmp0(str, entry->d_name)){
        closedir(directory);
        return(TRUE);
      }
 
      break;
    }
      }
    }
 
    closedir(directory);
 
    return(FALSE);
  }
 
  if(suid_path){
    path = suid_search_path;
     
    for(; *path != NULL; path++){
      if(nv_terminal_emulator_lookup_path(*path)){
    return(*path);
      }
    }
  }
 
  path = search_path;
 
  for(; *path != NULL; path++){
    if(nv_terminal_emulator_lookup_path(*path)){
      return(*path);
    }
  }
 
  return(NULL);
}
 
void
nv_terminal_emulator_poll(NvTerminalEmulator *emulator)
{
  struct passwd *pw;
  uid_t uid;
  gchar *username;
  gchar *hostname;
  gchar *path;
  gchar *str;
  gchar **tokens;
  gboolean running;
 
  uid = getuid();
  pw = getpwuid(uid);
 
  username = pw->pw_name;
  hostname = (gchar *) malloc(256 * sizeof(gchar));
  gethostname(hostname, 256);
 
  path = (gchar *) malloc(256 * sizeof(gchar));
 
  running = TRUE;
 
  while(running){
    getcwd(path, 256);
 
    printf("%s@%s $ \0",
       username,
       hostname);
 
    str = nv_terminal_emulator_readline(emulator);
 
    if(str != NULL){
      gchar *filename;
      gchar *tmp;
 
      str = nv_terminal_emulator_unescape(emulator,
                      str);
 
      tokens = g_strsplit_set(str,
                  " \t\n\0",
                  0);
      g_free(str);
 
      if(!g_str_has_prefix(tokens[0],
               "./\0")){
    tmp = nv_terminal_emulator_lookup(emulator,
                      tokens[0],
                      ((uid == 0) ? TRUE: FALSE));
      }else{
    tmp = g_strdup(tokens[0]);
      }
 
      if(tmp != NULL){
    filename = g_strconcat(tmp,
                   "/\0",
                   tokens[0],
                   NULL);
 
    if(filename != NULL){
      pid_t pid;
 
      pid = fork();
 
      if(pid == 0){
        execvp(filename,
           tokens);
        _exit(0);
      }else if(pid > 0){
        waitpid(pid,
            WEXITED,
            0);
      }
 
      g_free(filename);
    }
      }
 
 
      g_strfreev(tokens);
    }
  }
}

Last edited by joel2001k; 12-11-2015 at 01:40 PM.
 
Old 12-12-2015, 12:49 AM   #10
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
You did know that C strings all have a null byte added? So what is with all the "...\0"?

What is the "nv_terminal_emulator..." stuff. A shell has no business with a terminal emulator. Handling escape sequences is what the terminfo/ncurses database is - but reads/write go through a standard file handle- stdin/stdout/stderr.

A basic shell is very simple. Read from stdin, parse into tokens, fork new process/exec new executable passing the array of tokens and the environment, wait for process to terminate... repeat. Adding internal commands is secondary.

No terminal emulation. No escape sequences.
 
Old 12-13-2015, 02:10 AM   #11
joel2001k
Member
 
Registered: Mar 2007
Distribution: GNU/Linux debian unstable main
Posts: 95

Rep: Reputation: 17
the Nul-byte style

Just trying to do old BSD style it was one of the first in C. Here that's for you ... One of my secrets

https://github.com/joelkraehemann/nv_terminal

getchar() does read from stdin and the launched programs should write to stdout or stderr.

Further the only escape you can do is for line-break.

Last edited by joel2001k; 12-13-2015 at 02:15 AM. Reason: more information
 
Old 12-13-2015, 07:08 AM   #12
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,912

Rep: Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513Reputation: 1513
No need for line-break - that is up to the terminal itself. If you must, then use a get command line, not getchar (too slow). To tokenize use strtok that is what it was designed for. Much simpler.

Trying to make a "scriptable" interpreter also doesn't need a line break continuation, though useful for readability. There is always getnstr that will get an entire line... if the last byte is a continuation, use getnstr again - adjusting the starting point and length for what has already been read (be sure to overwrite the continuation). MUCH simpler.

Now that the entire command has been loaded you can tokenize it, building the argv list as you go... (including quote handling...) No need to dynamically allocate anything - if a string (or argv list) get too full, report an error and start over.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Segmentation fault in C Shell Kslkgh Programming 4 08-13-2015 09:08 AM
I am getting segmentation error while creating db on linux 3.6 and oracle 9.2.0.7 sandeep.mehta Linux - Desktop 1 09-30-2012 04:27 AM
[SOLVED] Apache2 Segmentation Faults Not Creating Core Dumps Subject16 Linux - Server 3 04-25-2011 12:18 PM
Getting segmentation fault after creating 500 threads naveenisback Programming 5 11-10-2009 09:30 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:25 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration