parsing proc/pid/cmdline to get function parameters - c++

I'm trying to extract the parameter with which an app was called by using the data inside cmdline.
If I start an application instance like this:
myapp 1 2
and then cat the cmdline of myapp I will see something like myapp12.
I needed to extract these values and I used this piece of code to do it
pid_t proc_id = getpid();
sprintf(buf,"/proc/%i/cmdline",proc_id);
FILE * pFile;
pFile = fopen (buf,"r");
if (pFile!=NULL)
{
fread(buf,100,100,pFile);
cout << "PID " << proc_id << endl;
string str = buf;
cout << buf << endl;
size_t found=str.find_last_of("/\\");
cout << " file: " << str.substr(found+1) << endl;
fclose (pFile);
}
But what I am getting is only the app name and no parameters...
Update coppied from answer:
well, my question now seems to be how do I read the cmdline file without it stopping at the first NULL character...
fopen(cmdline, "rb")
doesn't do anything else so...

/usr/bin/strings /proc/1337/cmdline usually do the job for me.

All of the command line parameters (what would come through as the argv[] array) are actually null-separated strings in /proc/XXX/cmdline.
abatkin#penguin:~> hexdump -C /proc/28460/cmdline
00000000 70 65 72 6c 00 2d 65 00 31 20 77 68 69 6c 65 20 |perl.-e.1 while |
00000010 74 72 75 65 00 |true.|
This explains why when you cat'ed cmdline they were all "stuck" together (cat ignored the invalid NULL characters) and why your cout stopped after the first command line argument (the process name) since it thought that the process name was a null-terminated string and stopped looking for more characters at that point.
Processing Command Line Arguments
To process the command line arguments, you have a couple options. If you just want the entire command line as one giant string, loop from the 0 to (numRead - 2) (where numRead is the number of characters read) and replace any NULL bytes (curByte == 0) with spaces. Then just make sure to set the last character to be a NULL byte too (in case things got truncated due to the fixed-size buffer).
If you instead want an array with all of the arguments, you need to be more creative. One option would be to loop from 0 to (numRead - 1) and could all of the NULL bytes that you find. Then allocate an array of char*'s of that length. Then loop back through the command line, setting the beginning of every string (i.e. the first byte in the array, plus each byte following a NULL byte) to consecutive elements of the array of char*'s.
Just know that since you read to a fixed-size buffer, anything beyond that buffer would be truncated. So remember that whatever you do, you probably need to manually make sure that the end of the last string ends up being NULL terminated, otherwise most string handling functions won't know where the string ends and will keep on going forever.

Many files supplied in |path| have incorrect size (proc files etc). Hence, the file is read sequentially as opposed to a one-shot read.
std::string cmdline;
char buf[1024];
size_t len;
FILE *fp = fopen("/proc/self/cmdline", "rb");
if (fp) {
while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) {
cmdline.append(buf, len); // note: `len` here is very important
}
}
Then, you get the whole command line also the parameters. But the reason you can only get the app name or the file path and no parameters when you try to print it is the command line you've got is separated with '\0', something like "./exefile_name\0-param1=p1\0-param2=p2". So you can only get the part that ahead the first '\0', because the machine assumes that the string is end at that place. You also need to tokenize it with '\0' first, then try to print it or use it.
std::stringstream tokens(cmdline);
std::string tmp;
while (getline(tokens, tmp, '\0')){
std::cout << tmp << std::endl;
}
fclose(fp);

Related

C++: Trouble reading .BMP files; end of file reached earlier than expected

i am currently trying to read .BMP files using C++, but somehow after reading a few bytes the end of the file is reached (fgetc() returns -1). I've reduced the problem to a minimal example:
#include <iostream>
int main()
{
// Open file
FILE* file = fopen("C:/Path/to/file", "r");
// Get and print file size in bytes
fseek(file, 0L, SEEK_END);
std::cout << ftell(file) << std::endl;
rewind(file);
int byte, i = 0;
do
{
// Get each byte
byte = fgetc(file);
// Print i and value of byte
std::cout << i << ", " << byte << std::endl;
i++;
}
// Stop reading when end of file is reached
while (byte != EOF);
std::cin.get();
return 0;
}
When using this to read .BMP files (problem does not occur on simple formats like .txt files), It reads the file length correctly, but finds the EOF way before reaching the end of the file.
For example, using this file, it reads a file length of 120054, but fgetc() returns -1 at i=253.
What exactly am i doing wrong, and how can i fix this problem?
Reading a file in plain "r" mode on DOS/Windows may treat ASCII 26 (^Z) as "end of file". It may also convert line endings from CR LF (13 10) to LF (10), which you also don't want.
Looking at your sample file, I do indeed see that character (it's 1A in hex):
0000340 0c 1f 15 0e 1f 15 0e 1f 14 10 1f 14 10 21 17 10
0000360 21 17 10 22 18 11 23 19 12 25 19 13 26[1a]14 26
The position is 375 octal, which is 253 decimal. Sound familiar? :)
Use "rb":
FILE* file = fopen("C:/Path/to/file", "rb");
Change
FILE* file = fopen("C:/Path/to/file", "r");
to
FILE* file = fopen("C:/Path/to/file", "rb");
to read the file in binary mode. That usually helps to avoid such strange errors.

how can I get a string from the raspberry UART?

I'm programming the Raspberry Pi to get data from an Android application by bluetooth with a HC-05 module.
I am using the wiringSerial library to accomplish it, because I just need to get some bytes of information (colours, timers, etc)
The problem is that with the serialGetchar function I just get the ASCII codes of the string I send from the Android app and not the whole string. How can I get the string as it was sent?
I have this code for now:
int main () {
connection = serialOpen(/dev/ttyAMA0, 9600);
while (serialDataAvail(connection) > -1) {
std::cout << (char) serialGetchar(connection);
}
}
Edit: the whole code is:
#include <wiringSerial.h>
#include <unistd.h>
#include <wiringPi.h>
#include <iostream>
int main()
{
char opcion;
int conexion;
int dato;
char datos[1024];
int i = 0;
std::cout << "Select option\n";
std::cout << "a --> bluetooth write test\n";
std::cout << "b --> bluetooth read test\n";
opcion = getchar();
conexion = serialOpen("/dev/ttyAMA0", 9600);
while (true){
if (opcion == 'a') {
serialPrintf(conexion, "Hola\n");
} else if (opcion == 'b') {
while (serialDataAvail(conexion) > -1){
dato = serialGetchar(conexion);
printf("%d\n", dato);
datos[i] = dato;
i++;
if (dato == 65){
printf("%d\n",datos);
}
}
}
}
}
I think you are confused by the output? std::cout << (char)<char_code>; is probably displaying the char_code as number (so for the char 65 (ASCII 'A') it will run number formatter and display '6' and '5' ("65") instead of "A")?
You should probably allocate some reasonably huge char buffer like char uartInput[1024];, then read the characters into it till it's either full, or some termination mark is reached. Let's say you will send string "Hello" from android as ASCII bytes terminated by zero, that means that over the wire will go these bytes: 72, 101, 108, 108, 111, 0 (any internal UART protocol bits removed).
So those values will be read by the serialGetchar, stored into uartInput, and then you can show them as ASCII string, for that a mere std::cout << uartInput; should work (as cout can handle ASCII char[] zero terminated string well), or printf("%s", uartInput); is other option with the *printf functions family (I like these a tad more, although they are not C++ like).
Make sure the bytes sent from Android are in expected format (i.e. ASCII encoded, zero terminated, in order you expect them). For more robust application probably add some checksums and error handling, some data structure markers and protocol version numbers can be handy too, etc...
Edit (on new code version):
You look to be still confused what is ASCII, string, character and number in computer. I will try to show it with some code examples.
printf("%d ", 65);
// will output three glyphs from font forming visually "65 "
//first is "6" (ASCII code 0x36 = 54)
//second is "5" (ASCII code 0x35 = 53)
//third is space " " (ASCII code 0x20 = 32)
// (^^ usually a font glyph consisting of zero pixels drawn :))
printf("%c ", 65);
// will output two glyphs from font forming visually "A "
//first is "A" (ASCII code 0x41 = 65)
//second is space " " (ASCII code 0x20 = 32)
char charZeroTerminatedString[] = "Hello";
// will allocate somewhere in memory 6 bytes, with values set to:
// 72, 101, 108, 108, 111, 0
// symbol charZeroTerminatedString itself is an address of byte containing the value 72
// so 'H' == 72 == charZeroTerminatedString[0], 111 == charZeroTerminatedString[4]
// or 72 == *charZeroTerminatedString, 111 == *(charZeroTerminatedString+4)
printf("%s\n", charZeroTerminatedString);
// will output six (five+one control) glyphs from font forming visually "Hello" + newline
// First is "H" (value 0x48 = 72 in memory)
// ...
// Sixth "\n" glyph is not as much as glyph,
// as control character just moving virtual cursor to new line
So finally your loop can look like this:
#include <cstring>
//...
constexpr int UART_INPUT_MAX_SIZE = 1024;
char uartInput[UART_INPUT_MAX_SIZE+1];
//^^ +1 to have zero terminator even for 1024+ chars sent
//...
while (true) {
// clear the buffer for next receiving.
int uartInputIndex = 0;
memset(uartInput, 0, UART_INPUT_MAX_SIZE+1);
// now receive data, till they are available
// Or whole string is received
while (serialDataAvail(conexion) > -1 &&
uartInputIndex < UART_INPUT_MAX_SIZE) {
uartInput[uartInputIndex] = serialGetchar(conexion);
if (0 == uartInput[uartInputIndex]) break; //zero terminator received
++uartInputIndex;
}
if (0 == uartInputIndex) break; //No more strings received
printf("%s\n", uartInput); // some string received
// Either terminated by zero in byte stream
// or by serialDataAvail reporting no more data
}
Please bear in mind, that sending data over serial port takes some time, so exiting your loop while serialDataAvail reports zero available bytes may be too soon, as the rest of the data may be still on it's way trough the wire. So you should have some structural protocol designed to recognize ending of transmission, or have some delays along with time-out mechanism to wait for whole transmission.
The example code works well for me, when I was feeding it with instant fake complete data (in serialDataAvail and serialGetchar), but it will fail on real serial port communication to wait for whole data transmission.

C++ how to create a PNG file with known data?

Just wondering, if I read a PNG file as a binary file, and I know how to write the hex numbers into another plain txt or whatever file, then how can I recreate the PNG file with those hex numbers?
This is the code I use to read from a PNG file and write to another plain txt file:
unsigned char x;
ifile.open("foo.png",ios::binary);
ifile>>noskipws>>hex;
while(ifile>>x){
ofile<<setw(2)<<setfill('0')<<(int)x;
//do some formatting stuff to the ofile, ofile declaration omitted
//some ifs to see if IEND is read in, which is definitely correct
//if IEND, break, so the last four hex numbers in ofile are 49 45 4E 44
}
//read another 4 bytes and write to ofile, which are AE 42 60 82, the check sum
The reason why I am doing this is because I have some PNG files which have some irrelevant messages after IEND chunk, and I want to get rid of them and only keep the chunks related to the actual picture and split them into different files. By "irrelevant messages" I mean they are not the actual part of the picture but I have some other use with them.
It's easy, you just need to read every 2 characters and convert them from hex back to binary.
unsigned char x;
char buf[3] = {0};
ifile.open("foo.hex");
while(ifile>>buf[0]>>buf[1]){
char *end;
x = (unsigned char) strtol(buf, &end, 16);
if (*end == 0) // no conversion error
// output the byte

Writing chars as a byte in C++

I'm writing a Huffman encoding program in C++, and am using this website as a reference:
http://algs4.cs.princeton.edu/55compression/Huffman.java.html
I'm now at the writeTrie method, and here is my version:
// write bitstring-encoded tree to standard output
void writeTree(struct node *tempnode){
if(isLeaf(*tempnode)){
tempfile << "1";
fprintf(stderr, "writing 1 to file\n");
tempfile << tempnode->ch;
//tempfile.write(&tempnode->ch,1);
return;
}
else{
tempfile << "0";
fprintf(stderr, "writing 0 to file\n");
writeTree(tempnode->left);
writeTree(tempnode->right);
}
}
Look at the line commented - let's say I'm writing to a text file, but I want to write the bytes that make up the char at tempnode->ch (which is an unsigned char, btw). Any suggestions for how to go about doing this? The line commented gives an invalid conversion error from unsigned char* to const char*.
Thanks in advance!
EDIT: To clarify: For instance, I'd like my final text file to be in binary -- 1's and 0's only. If you look at the header of the link I provided, they give an example of "ABRACADABRA!" and the resulting compression. I'd like to take the char (such as in the example above 'A'), use it's unsigned int number (A='65'), and write 65 in binary, as a byte.
A char is identical to a byte. The preceding line tempfile << tempnode->ch; already does exactly what you seem to want.
There is no overload of write for unsigned char, but if you want, you can do
tempfile.write(reinterpret_cast< char * >( &tempnode->ch ),1);
This is rather ugly, but it does exactly the same thing as tempfile << tempnode->ch.
EDIT: Oh, you want to write a sequence of 1 and 0 characters for the bits in the byte. C++ has an obscure trick for that:
#include <bitset>
tempfile << std::bitset< 8 >( tempnode->ch );

Using istringstream to process a memory block of variable length

I'm trying to use istringstream to recreate an encoded wstring from some memory. The memory is laid out as follows:
1 byte to indicate the start of the wstring encoding. Arbitrarily this is '!'.
n bytes to store the character length of the string in text format, e.g. 0x31, 0x32, 0x33 would be "123", i.e. a 123-character string
1 byte separator (the space character)
n bytes which are the wchars which make up the string, where wchar_t's are 2-bytes each.
For example, the byte sequence:
21 36 20 66 00 6f 00 6f 00
is "!6 f.o.o." (using dots to represent char 0)
All I've got is a char* pointer (let's call it pData) to the start of the memory block with this encoded data in it. What's the 'best' way to consume the data to reconstruct the wstring ("foo"), and also move the pointer to the next byte past the end of the encoded data?
I was toying with using an istringstream to allow me to consume the prefix byte, the length of the string, and the separator. After that I can calculate how many bytes to read and use the stream's read() function to insert into a suitably-resized wstring. The problem is, how do I get this memory into the istringstream in the first place? I could try constructing a string first and then pass that into the istringstream, e.g.
std::string s((const char*)pData);
but that doesn't work because the string is truncated at the first null byte. Or, I could use the string's other constructor to explicitly state how many bytes to use:
std::string s((const char*)pData, len);
which works, but only if I know what len is beforehand. That's tricky given that the data is variable length.
This seems like a really solvable problem. Does my rookie status with strings and streams mean I'm overlooking an easy solution? Or am I barking up the wrong tree with the whole string approach?
Try setting your stringstream's rdbuf:
char* buffer = something;
std::stringbuf *pbuf;
std::stringstream ss;
std::pbuf=ss.rdbuf();
std::pbuf->sputn(buffer, bufferlength);
// use your ss
Edit: I see that this solution will have a similar problem to your string(char*, len) situation. Can you tell us more about your buffer object? If you don't know the length, and it isn't null terminated, it's going to be very hard to deal with.
Is it possible to modify how you encode the length, and make that a fixed size?
unsigned long size = 6; // known string length
char* buffer = new char[1 + sizeof(unsigned long) + 1 + size];
buffer[0] = '!';
memcpy(buffer+1, &size, sizeof(unsigned long));
buffer should hold the start indicator (1 byte), the actual size (size of unsigned long), the delimiter (1 byte) and the text itself (size).
This way, you could get the size "pretty" easy, then set the pointer to point beyond the overhead, and then use the len variable in the string constructor.
unsigned long len;
memcpy(&len, pData+1, sizeof(unsigned long)); // +1 to avoid the start indicator
// len now contains 6
char* actualData = pData + 1 + sizeof(unsigned long) + 1;
std::string s(actualData, len);
It's low level and error prone :) (for instance if you read anything that isn't encoded the way that you expect it to be, the len can get pretty big), but you avoid dynamically reading the length of the string.
It seems like something on this order should work:
std::wstring make_string(char const *input) {
if (*input != '!')
return "";
char length = *++input;
return std::wstring(++input, length);
}
The difficult part is dealing with the variable length of the size. Without something to specify the length it's hard to guess when to stop treating the data as specifying the length of the string.
As for moving the pointer, if you're going to do it inside a function, you'll need to pass a reference to the pointer, but otherwise it's a simple matter of adding the size you found to the pointer you received.
It's tempting to (ab)use the (deprecated but nevertheless standard) std::istrstream here:
// Maximum size to read is
// 1 for the exclamation mark
// Digits for the character count (digits10() + 1)
// 1 for the space
const std::streamsize max_size = 3 + std::numeric_limits<std::size_t>::digits10;
std::istrstream s(buf, max_size);
if (std::istream::traits_type::to_char_type(s.get()) != '!'){
throw "missing exclamation";
}
std::size_t size;
s >> size;
if (std::istream::traits_type::to_char_type(s.get()) != ' '){
throw "missing space";
}
std::wstring(reinterpret_cast<wchar_t*>(s.rdbuf()->str()), size/sizeof(wchar_t));