Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

parsing command-line arguments from proc/pid/cmdline

Tags:

c++

I'm trying to parse the command-line arguments of another program (which is an emulator) inside my program using system() command and the emulator's pid. Unfortunately using both file read and cat, the output is not well-formatted, so I can not really get the data. cat on command line shows the file contents with spaces removed, the whole string sticked together, and using ifstream, it only shows the name of the program (the first argument I guess). Anyone has got any ideas?

The format of the arguments is like this:

sudo ./src/yse6 -w -f tracefiles/capacity.3Mbps_400RTT_PER_0.0001.txt -at=eth1 -an=eth0

and eventually I need to show the same string as formatted above.

Here is what I've done so far: (ExecCommand() gets a command, runs it in command-line and returns the result as string. Secondary() tries to get the file contents using file reader.)

std::string ExeCommand(const char* cmd) {
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return "ERROR";
    char buffer[128];
    std::string result = "";
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
            result += buffer;
    }
    pclose(pipe);
    return result;
}

void secondary(string addr){

        ifstream file(addr.c_str(),ios::in);
        if (file.good())
        {
            string str;
            while(getline(file, str))
            {
                istringstream ss(str);
                cout<<str<<endl;
                char num[50];
                while(ss >> num)
                {
                    cout<<num;
                }
            }
        }else{
            cout<<"no file exists."<<endl;
        }
}

int main (int argc, char* argv[])
{
    if ((string) argv[1] == "-q") {
        string pid=ExeCommand("ps -A | grep 'yse6' | awk '{print $1}'");
        if(pid==""){
            cout<<"No YSE emulator is running."<<endl;
        }else{
            pid=pid.substr(0,pid.size()-1);
            cout<<pid<<endl;
            string addr="cat /usr/bin/strings /proc/"+pid+"/cmdline";

            cout<<addr<<endl;
//          secondary(addr);

            const char * c = addr.c_str();
            string config=ExeCommand(c);
            //get the config
            cout << config<<endl;
        }//end of else
    }
}
like image 390
Tina J Avatar asked Jun 09 '14 19:06

Tina J


Video Answer


1 Answers

Something like this, but with more error checking, should be a good start (this is more C than C++, aside from the cout bit):

const int BUFSIZE = 4096; // should really get PAGESIZE or something instead...
unsigned char buffer[BUFSIZE]; // dynamic allocation rather than stack/global would be better

int fd = open("/proc/self/cmdline", O_RDONLY);
int nbytesread = read(fd, buffer, BUFSIZE);
unsigned char *end = buffer + nbytesread;
for (unsigned char *p = buffer; p < end; /**/)
{ cout << p << endl;
  while (*p++); // skip until start of next 0-terminated section
}
close(fd);

In particular, open() and read() should be checked for error conditions, but I haven't shown that part... This may also fail in extreme cases where your command line is > 4096 characters long, or if for some other reason, read() doesn't read the file in one call, which shouldn't happen in current /proc implementations, but is not always guaranteed...

like image 150
twalberg Avatar answered Sep 18 '22 14:09

twalberg