how should I use strace to snif the serial port? - c

I am writing an application in linux and need to access the serial port.
For debugging purposes I need to snif what comes and/or goes through the serial port.
I looked around and found out I can use strace to do that. So I tried the following:
-I print the file_descriptor of the serial device that I use.
(after restarting my application a few times, I reassured myself that the file_descriptor number my application gets from kernel is "4"
-if i start my application as strace -e write=4 ./myapp , I would expect to get messages in the terminal, from file_descriptor "4" only. instead I get looots of output:
read(5, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\300Q\254C4\0\0\0"..., 52
fstat64(5, {st_mode=S_IFREG|0644, st_size=1448930, ...}) = 0
mmap2(0x43ab8000, 153816, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0)0
mprotect(0x43ad6000, 28672, PROT_NONE) = 0
mmap2(0x43add000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRI0
close(5) = 0
munmap(0x2ab4c000, 38409) = 0
exit(0)
from several different file_descriptors.
If I run my app with strace -e trace=write -e write=4 ./myapp
I'll get far less message, even though they will still be many, and or file_descriptor "1".
write(1, "GPIO data bank:0x8, data: 0x80 a"..., 52GPIO data bank:0x8, data: 0x81) = 52
write(1, "\n", 1) = 1
write(1, "--> Version: 0677 <--\n", 22--> Version: 0677 <-- ) = 22
serial fd = 4
what you see above are some printf statements.
The extremely weird part is that the line serial fd = 4 is also a printf statement, but for some reason it is not wrapped around write(fd, ....) statement in strace output.
Can someone explain that, too?
thank you for your help.

Try it out with someting simple.
strace -e write=1 echo foo
This will write all syscalls, and in addition to these, the data written to fd 1.
strace -e trace=none -e write=1 echo foo
This will generate no output except for the output from the program itself. It seems you have to trace write if you want to see its data.
strace -e trace=write -e write=1 echo foo
This will print all write syscalls, for any file descriptor. In addition to that, it will print a dump of the data sent to descriptor 1. The output will look like this:
write(1, "foo\n", 4foo
) = 4
| 00000 66 6f 6f 0a foo. |
+++ exited with 0 +++
The syscall starts in the first line. After the list of arguments, the syscall is actually executed, and prints foo followed by a newline. Then the syscall return value is printed by strace. After that, we have the data dump.
I'd suggest using -e trace=write -e write=4 -o write4.txt followed by grep '^ |' write4.txt or something like that. If you want to see data in real time, you can use a bash redirection like this:
strace -e trace=write -e write=4 -o >(grep '^ |') ./myapp
This will send output from strace to grep, where you can strip the write syscalls and concentrate on the data dumps.
The extremely weird part is that the line serial fd = 4 is also a printf statement, but for some reason it is not wrapped around write(fd, ....) statement in strace output. Can someone explain that, too?
I'd say that line is output not from strace, but from some application. That's the reason it is not wrapped. The fact that no wrapped version of this appears in addition to that unwrapped one (like in my foo example output above) suggests that the output might originate in a child process lainced by myapp. Perhaps you want to add -f so you follow child process creation?
Notice that a child might decide to rename its file descriptors, e.g. redirect its standard output to that serial port opened by the parent. If that happens, write=4 won't be appropriate any more. To be on the safe side, I'd write the whole -f -e trace=write output to a file, and look at that to see where the data actually gets written. Then adjust things to home in on that data.

Related

Watch external processes for read/write events in C?

Is it possible to watch external process by its pids for read/write events? In particular I want to write a program which counts bytes an external process has written to stdout, stderr or FILE*. Desired platform is Linux. Note: I cannot change source code of target processes.
To see each write as it occurs:
strace -ewrite -p$PID
To see a sum of bytes written when the process ends:
strace -ewrite -p$PID 2>&1 | { while read; do set $REPLY; n=$_; [ $n -gt 0 ] && let count+=$n; done; echo $count; }
The above assume that process $PID already runs; note that only writes after strace started are counted. To account from the start of $PROCESS, start it with strace -ewrite $PROCESS instead.

Capturing tshark standard output with popen in C

I'm trying to capture the standard output from tshark through a program in C.
For that, I use popen() call to open tshark process and read from the returned FILE stream.
Code sample:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE* pipe_fd = popen("tshark -i eth0 -R icmp -2 -T fields -e icmp.checksum -e icmp.seq", "r");
//FILE* pipe_fd = popen("lsof", "r");
if (!pipe_fd) {
fprintf(stderr, "popen failed.\n");
return EXIT_FAILURE;
}
char buffer[2048];
while (NULL != fgets(buffer, sizeof(buffer), pipe_fd)) {
fprintf(stdout, "SO: %s", buffer);
}
pclose(pipe_fd);
printf("tdr FINISHED!\n");
return 0;
}
When I run it, I get only the packet number count, i.e., I get no packet fields info, just the count of packets, with each number overriding the previous in the same place (no lines scroll happening).
Something like this, I guess for 4 packets:
tomas#ubuntu64:~$ sudo ./main
tshark: Lua: Error during loading:
[string "/usr/share/wireshark/init.lua"]:46: dofile has been disabled due to running Wireshark as superuser. See http://wiki.wireshark.org/CaptureSetup/CapturePrivileges for help in running Wireshark as an unprivileged user.
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
4
But if I change in the C program the 'tshark' command argument by 'lsof', I get the standard output just fine.
tomas#ubuntu64:~$ sudo ./main
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.
SO: COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
SO: init 1 root cwd DIR 8,1 4096 2 /
SO: init 1 root rtd DIR 8,1 4096 2 /
SO: init 1 root txt REG 8,1 265848 791529 /sbin/init
SO: init 1 root mem REG 8,1 47712 824514 /lib/x86_64-linux-gnu/libnss_files-2.19.so
...
With this result, I'm assuming that there is something special with the way tshark sends the info to the standard output. Does anyone know about this behaviour?
I'm gonna check tshark source code, to see if it can clarify it.
Just a final note.
When I run tshark through the shell, I often get missing packet numbers like:
tomas#ubuntu64:~$ sudo tshark -i eth0 -R icmp -2 -T fields -e icmp.checksum -e icmp.seq
tshark: Lua: Error during loading:
[string "/usr/share/wireshark/init.lua"]:46: dofile has been disabled due to running Wireshark as superuser. See http://wiki.wireshark.org/CaptureSetup/CapturePrivileges for help in running Wireshark as an unprivileged user.
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
0x0ee5 63045
1 0x8ae3 63046
2 0xcfdf 63047
3 0xe4d9 63048
4 0x9db7 63049
5 0x6798 63050
6 0x0175 63051
7 0x9e54 63052
0xa654 63052
9 0xe050 63053
0xe850 63053
11 0x8389 63054
0x8b89 63054
13 0x9b81 63055
0xa381 63055
Missing printed packet numbers 8, 10, 12, 14.
And when I redirect stdout to file, it does not send the count numbers:
tomas#ubuntu64:~$ sudo tshark -i eth0 -R icmp -2 -T fields -e icmp.checksum -e icmp.seq > kk
tomas#ubuntu64:~$ cat kk
0x2073 63321
0x2873 63321
0x7c6a 63322
Another clue that tshark is handling printed packet count and info differently.
Regards,
Tom
Well, even if I finally don't use this way of working with tshark, I think I found the option to use in order to popen tshark. From the manual page, option -l:
Flush the standard output after the information for each packet is printed. (This is not, strictly speaking, line-buffered if -V was
specified; however, it is the same as line-buffered if -V wasn't
specified, as only one line is printed for each packet, and, as -l is
normally used when piping a live capture to a program or script, so
that output for a packet shows up as soon as the packet is seen and
dissected, it should work just as well as true line-buffering. We do
this as a workaround for a deficiency in the Microsoft Visual C++ C
library.)
This may be useful when piping the output of TShark to another
program, as it means that the program to which the output is piped
will see the dissected data for a packet as soon as TShark sees the
packet and generates that output, rather than seeing it only when the
standard output buffer containing that data fills up.
I tested it, and it seems to work.
Just in case anyone needs it.

Linux redirect to multiple targets

How could I redirect output to multiple targets, say stdout, file, socket and so?
say, i have a system here and connected to some network. When it fails, the guy supervises it via ssh should be able to notice it, or the GUI client should receive the error info, or, in the worst case, we can still find something in the log.
or even more targets. Atomicity may or may not need to be guaranteed.
so how to do this in bash and/or in C?
I think you are looking for the "tee" command.
You can redirect with tee to any number of files and to any commands too, like:
seq 50 | tee copy1 copy2 >((echo Original linecount: $(grep -c ''))>&2) | grep '9'
what prints:
9
19
29
39
49
Original linecount: 50 #printed to stderr
or
seq 50 | tee copy1 copy2 >((echo Original linecount: $(grep -c ''))>&2) | grep '9' | wc -l
what prints the count of numbers containing digit 9 in first 50 numbers, while make two copyes of the original sequence...
Original linecount: 50 #stderr
5

How to get input file name from Unix terminal in C?

My program gets executed like:
$./sort 1 < test.txt
sort is the program name
1 is the argument (argv[1])
and test.txt is the file I am inputting from
Is it possible to extract the name file from this? if so how?
The problem is I already wrote my whole program as if I could extract the name from the input line, so I need to be able to pass it into arguments.
Any help is appreciated,
Thanks!
You can't. The shell opens (open(2)) that file and sets up the redirect (most likely using dup2).
The only possible way would be for the shell to explicitly export the information in an environment variable that you could read via getenv.
But it doesn't always make sense. For example, what file name would you expect from
$ echo "This is the end" | ./sort 1
Though this can't be done portably, it's possible on Linux by calling readlink on /proc/self/fd/0 (or /proc/some_pid/fd/0).
eg, running:
echo $(readlink /proc/self/fd/0 < /dev/null)
outputs:
/dev/null
No you can't: the shell sends the content of test.txt to the standard input of your program.
Look at this:
sort << _EOF
3
1
2
_EOF
The < > | operators are processed by the shell, they alter standard input,output,error of the programs in the cmd line.
If you happen to run Solaris, you could parse pfiles output to get the file associated, if any, with stdin.
$ /usr/bin/sleep 3600 < /tmp/foo &
[1] 8430
$ pfiles 8430
8430: /usr/bin/sleep 3600
Current rlimit: 65536 file descriptors
0: S_IFREG mode:0600 dev:299,2 ino:36867886 uid:12345 gid:67890 size=123
O_RDONLY|O_LARGEFILE
/tmp/foo
1: S_IFCHR mode:0600 dev:295,0 ino:12569206 uid:12345 gid:67890 rdev:24,2
...
On most Unix platforms, you will also get the same information from lsof -p if this freeware is installed.

system command hanged in C program, but when I run the command on bash it is successfull

I need to send the arp of a IP to get it's mac address which is configured on different machine. I am arping this ip from a C program by "system(arping -c 3 -i eth0 ) but I see that this is hanged in there.
But if I run the same command from bash "arping -c 3 -i eth0 " it get executed successfully.
I could not understand why system command hanged in this case while the command is successfully completed when run from bash.
Thanks,
Since you said it was hanging you can try:
strace -o my_prog.strace -f ./my_prog
and then kill it after it hangs. Then you can view the strace output file my_prog.strace and try to figure out what went wrong.
You may want to look at the strace man page to see other options that you might like use -- of particular use to me are ones that make it show more data in buffer (and string) input/output.
If it's not really hanging you should check the return value from your call to system( ) and then inspect errno.
edit
Something that I just thought of that could cause a hang would be if arping was actually a link to a setuid root program that did sudo on the real arping and it is waiting on a password to be typed in, but the terminal for that program isn't set correctly.
try system("arping -c 3 -I eth0 ip-addr");
something like:
main()
{
system("arping -c 3 -I eth0 192.168.10.1");
}
Are you using any child process to execute above ?
From Definition of system() :
The system() function shall ignore the SIGINT and SIGQUIT signals, and shall block the SIGCHLD signal, while waiting for the command to terminate. The system() function shall not return until the child process has terminated.
Recommendations:
1.check on the return value of system() & take appropriate decision.
Eg: If return value is zero it means command processor is not available.If a child process cannot be created, or if the termination status for the command language interpreter cannot be obtained, system() shall return -1 and set errno to indicate the error.
2.Use complete shell commands to be executed.
Eg: system("arping -c 3 -I eth0 10.203.198.10");

Resources