I'm attempting to write a single bpftrace script which grab the strings passing from a postfix process and a saslauthd for the authentication part. The goal is detect compromise account of my company. The strace command give me some good results:
strace -p PID -s 100 -e 'read'
read(7, "\0\20", 2) = 2
read(7, "xxxxxxxxxx", 10) = 10
read(7, "\0\t", 2) = 2
read(7, "YYYYYYYYY", 9) = 9
read(7, "\0\4", 2) = 2
read(7, "smtp", 4) = 4
I can recover login/password and detect if there is a bruteforce running.
but I try to have the same results with bpftrace with:
$ bpftrace -e 'kprobe:sys_read /comm=="saslauthd"/ {printf("%<%s>\n",str(arg1,arg2));}'
<>
<login>
<>
<>
<>
<smtp>
In this case, I can read some sys_read syscall strings but not all. I don't understand why my bpftrace doesn't have the same result.
I also think about the null character and that why i use str(arg1,arg2) to force the size of the array. I'v also tried to use tracepoint and this is the same result.
Maybe someone can help me to understand where is my error ? So any input will be appreciated
TL;DR. That's actually the expected behavior of str(buf, len). It retrieves the string pointed to by buf, with a limit to len characters including the NULL character. Thus, since in your case some strings start with a NULL character, str() will copy an empty string.
Sources. bpftrace translates str() into a call to the BPF_FUNC_probe_read_str BPF helper. In the kernel, that helper itself calls strncpy_from_unsafe.
I don't think bpftrace already has a function implementing what you're looking for. If you want your described semantics, you could ask for a copy() function in bpftrace. Though, looking at the commit that introduced str(), it shouldn't be too hard to write a patch for that. Don't hesitate to send a pull request!
I have a c program that reads a rfid tag. I am trying to get output from that c program (it uses sudo and args) and compare it to a string
Here is my code as well as some debugging information.
import subprocess
#args - the c program and its args
args = ["sudo", "./rc522", "-r", "-b", "1"]
process = subprocess.Popen(args,stdout=subprocess.PIPE,stderr=None)
rfidRead=process.communicate()[0]
rfidRead=rfidRead.decode('utf-8')
print (len(rfidRead))
rfidRead = rfidRead[14:440]
print (len(rfidRead))
print (rfidRead)
if "49.4f.09.0a.0c.0f.00.00.00.00.00.00.00.00.00.00" in rfidRead:
print("unlocked")
else:
print("Not unlocked")
here is the output...
446
426
49.4f.09.0a.0c.0f.00.00.00.00.00.00.00.00.00.00
Not unlocked
I just cant find the hidden characters and things from the pipe output
Can you help please?
This is the rfidRead output using repr:
'\x1b[1;93m4\x1b[00m\x1b[1;93m9\x1b[00m.\x1b[1;93m4\x1b[00m\x1b[1;93mf\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m9\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93ma\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93mc\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93mf\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0\x1b[00m.\x1b[1;93m0\x1b[00m\x1b[1;93m0'
I worked out the answer with the help of jasonharper.
After doing the repr(...) I decided to google \x1b and found a stackoverflow article about vt100 and that this is vt100 code, so I did another google search to decode vt100, and I got a regular expression to remove the escape codes... here is the article I found. How can I remove the ANSI escape sequences from a string in python
I really like to use system shell commands in iPython. But I was wondering if it is possible to loop over the returned values from a call to e.g. !ls. This works:
files = !ls ./*_subcell_cooc.txt
for f in files:
print f
But this does not:
for f in ( !ls ./*_subcell_cooc.txt):
print f
Error is:
File "<ipython-input-1-df2bc72907d7>", line 5
for f in ( !ls $ROOT/*_subcell_cooc.txt):
^
SyntaxError: invalid syntax
No it is not possible, the syntax var = !something is special cased in IPython. It is not valid python syntax, and we will not extend for loops and so on to work with it.
You can do assignment as you show in your first example, but using glob,os and other real python module to do that will be more robust, not much harder, and also work outside of IPython...
For the anecdote Guido was really not happy with IPython half-shell syntax when he saw it last time at SciPy2013.
(Also it uppercase I in IPython please.)
I'm trying to do this in my Makefile:
VAL=
TARGET1:
VAL= ... #compute value of VAL
#run some command that uses the value of VAL
TARGET2:
$(MAKE) TARGET1
#run other command that uses the value of VAL
But it turns out that value of VAL is reset when TARGET! completes in TARGET2. Thus the computed value of VAL is not available when I try to run the other command in TARGET2. Is there any way to keep the value computed in TARGET1? Thanks.
You have a fundamental misconception. The variable VAL that is set in the TARGET1 recipe is not a make variable at all: it's a shell variable. You can tell because if you change the syntax of the assignment to be something else that is still a valid make variable assignment but is not a valid shell variable assignment, like:
TARGET1:
VAL := foo
it will give you a syntax error. Basically in make, any recipe line (lines after a target that begin with a TAB character) are not interpreted by make at all: they're passed to a shell that make invokes. Nothing that happens in that shell can have any effect on the value of make variables, etc. of course.
You don't give us much detail. You don't say whether the command uses the variable from the environment or via the command line. You don't say what version of make you're using. If it's GNU make, you have a number of options. The simplest one is to set the value always; if it requires shell syntax you can use the shell function:
VAL := $(shell #compute value of VAL)
TARGET1:
#run some command that uses $(VAL)
TARGET2:
#run another command that uses $(vAL)
Before we give you more possibilities we need to understand the requirements: if you HAVE to have the value set in TARGET1 we need to know why, before we can offer possible solutions.
GCC version 4.6
The Problem: To find a way to feed in parameters to the executable, say a.out, from the command line - more specifically feed in an array of double precision numbers.
Attempt: Using the READ(*,*) command, which is older in the standard:
Program test.f -
PROGRAM MAIN
REAL(8) :: A,B
READ(*,*) A,B
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
The execution -
$ gfortran test.f
$ ./a.out 3.D0 1.D0
This did not work. On a bit of soul-searching, found that
$./a.out
3.d0,1.d0
4.0000000000000000 0
does work, but the second line is an input prompt, and the objective of getting this done in one-line is not achieved. Also the COMMAND_ARGUMENT_COUNT() shows that the numbers fed into the input prompt don't really count as 'command line arguments', unlike PERL.
If you want to get the arguments fed to your program on the command line, use the (since Fortran 2003) standard intrinsic subroutine GET_COMMAND_ARGUMENT. Something like this might work
PROGRAM MAIN
REAL(8) :: A,B
integer :: num_args, ix
character(len=12), dimension(:), allocatable :: args
num_args = command_argument_count()
allocate(args(num_args)) ! I've omitted checking the return status of the allocation
do ix = 1, num_args
call get_command_argument(ix,args(ix))
! now parse the argument as you wish
end do
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
Note:
The second argument to the subroutine get_command_argument is a character variable which you'll have to parse to turn into a real (or whatever). Note also that I've allowed only 12 characters in each element of the args array, you may want to fiddle around with that.
As you've already figured out read isn't used for reading command line arguments in Fortran programs.
Since you want to read an array of real numbers, you might be better off using the approach you've already figured out, that is reading them from the terminal after the program has started, it's up to you.
The easiest way is to use a library. There is FLAP or f90getopt available. Both are open source and licensed under free licenses.
The latter is written by Mark Gates and me, just one module and can be learned in minutes but contains all what is needed to parse GNU- and POSIX-like command-line options. The first is more sophisticated and can be used even in closed-source projects. Check them out.
Furthermore libraries at https://fortranwiki.org/fortran/show/Command-line+arguments
What READ (*,*) does is that it reads from the standard input. For example, the characters entered using the keyboard.
As the question shows COMMAND_ARGUMENT_COUNT() can be used to get the number of the command line arguments.
The accepted answer by High Performance Mark show how to retrieve the individual command line arguments separated by blanks as individual character strings using GET_COMMAND_ARGUMENT(). One can also get the whole command line using GET_COMMAND(). One then has to somehow parse that character-based information into the data in your program.
I very simple cases you just need the program requires, for example, two numbers, so you read one number from arg 1 and another form arg 2. That is simple. Or you can read a triplet of numbers from a single argument if they are comma-separated like 1,2,3 using a simple read(arg,*) nums(1:3).
For general complicated command line parsing one uses libraries such as those mentioned in the answer by Hani. You have set them up so that the library knows the expected syntax of the command line arguments and the data it should fill with the values.
There is a middle ground, that is still relatively simple, but one already have multiple arguments, that correspond to Fortran variables in the program, that may or may not be present. In that case one can use the namelist for the syntax and for the parsing.
Here is an example, the man point is the namelist /cmd/ name, point, flag:
implicit none
real :: point(3)
logical :: flag
character(256) :: name
character(1024) :: command_line
call read_command_line
call parse_command_line
print *, point
print *, "'",trim(name),"'"
print *, flag
contains
subroutine read_command_line
integer :: exenamelength
integer :: io, io2
command_line = ""
call get_command(command = command_line,status = io)
if (io==0) then
call get_command_argument(0,length = exenamelength,status = io2)
if (io2==0) then
command_line = "&cmd "//adjustl(trim(command_line(exenamelength+1:)))//" /"
else
command_line = "&cmd "//adjustl(trim(command_line))//" /"
end if
else
write(*,*) io,"Error getting command line."
end if
end subroutine
subroutine parse_command_line
character(256) :: msg
namelist /cmd/ name, point, flag
integer :: io
if (len_trim(command_line)>0) then
msg = ''
read(command_line,nml = cmd,iostat = io,iomsg = msg)
if (io/=0) then
error stop "Error parsing the command line or cmd.conf " // msg
end if
end if
end subroutine
end
Usage in bash:
> ./command flag=T name=\"data.txt\" point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
or
> ./command flag=T name='"data.txt"' point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
Escaping the quotes for the string is unfortunately necessary, because bash eats the first quotes.