Thamognya
Thamognya

Reputation: 153

Get the shell being used within C

I am trying to get the shell that is being used (where the code is being executed on).

For example if the binary was named tmp

when I execute ./tmp on a bash shell I get an printf of bash, but if I execute it on a zsh shell I get an printf of zsh

I currently tried

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char command[50];
    strcpy( command, "echo $0" );
    system(command);
    return 0;
}

But the only output I get is sh which is not my desired output.

Upvotes: 0

Views: 201

Answers (1)

larsks
larsks

Reputation: 312400

If you are trying to answer the question, "what is the parent of the current command", you'll need to:

  1. Get the process id of the parent process, and then
  2. Figure out the command name for that pid

But if you are trying to answer the question, "what shell is configured as the default shell for the current user", that is a different question. I'm assuming you're asking the first question here.


Getting your parent PID is easy; just use the getppid() function:

pid_t parent_pid;
parent_pid = getppid();

Getting the command associated with that pid is straightforward but requires a few more steps. The simplest solution is probably reading the value from /proc/<pid>/comm, which means:

  • Compute a pathname from the parent_pid variable
  • Open the file
  • Read the contents into a buffer

Maybe something like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#ifndef BUFSIZ
#define BUFSIZ 8192
#endif

int main()
{
    char path[BUFSIZ], comm[BUFSIZ];
    pid_t parent_pid = getppid();
    int fd;

    // compute the pathname
    if (snprintf(path, BUFSIZ, "/proc/%d/comm", parent_pid) > BUFSIZ) {
        fprintf(stderr, "path too long\n");
        exit(1);
    }

    // open the file
    if (-1 == (fd = open(path, O_RDONLY))) {
        fprintf(stderr, "failed to open comm file\n");
        exit(1);
    }

    // read the contents into the `comm` variable
    memset(comm, 0, BUFSIZ);
    if (-1 == read(fd, comm, BUFSIZ-1)) {
        perror("read");
        exit(1);
    }

    printf("launched from: %s\n", comm);

    if (-1 == close(fd)) {
        perror("close");
        exit(1);
    }
    return 0;
}

Launched from a bash shell, we see:

bash$ ./getparent
bash

Launched from tclsh we see:

bash$ tclsh
% ./getparent
launched from: tclsh

Or from Python:

bash$ python
>>> print(subprocess.check_output('./getparent').decode())
launched from: python

So it seems to work as advertised.

Upvotes: 1

Related Questions