In C/C++ you can use __FILE__ and __LINE__ to get access to the current file and line number.
Does Go provide something similar?
Indeed it does:
http://golang.org/pkg/runtime/#Caller
runtime.Caller can also be used to get the file name/line number of calling functions, too.
I'm trying to load a C shared library within Ruby using Fiddle.
Here is a minimal example:
require 'fiddle'
require 'fiddle/import'
module Era
extend Fiddle::Importer
dlload './ServerApi.so'
extern 'int era_init_lib()'
extern 'void era_deinit_lib()'
extern 'int era_process_request(const char* request, char** response)'
extern 'void era_free(char* response)'
end
Era.era_init_lib
begin
# ...
ensure
Era.era_deinit_lib
end
The shared library loads without issues. However when I call Era.era_init_lib it tries to load additional libraries (Network.so and Protobuf.so). I have these file located in the current working directory (in the same directory as ServerApi.so).
However when I try to execute the code above I receive the following error:
! Failed to load library: /home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so, error: /home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so: cannot open shared object file: No such file or directory
If I place the file at the location the error describes everything works fine.
My guess is that the C working directory of fiddle is different from the Ruby working directory. I would like to keep the project files within the project and not in the Ruby installation directory.
How can I use Network.so from my project folder?
All the *.so files are provided by a third-party. I do not have the source and as a result cannot change these files. The function signatures are provided by the documentation.
Searching for Network.so in the strace gives me these results:
readlink("/proc/self/exe", "/home/username/.rvm/rubies/ruby-2."..., 4096) = 44
openat(AT_FDCWD, "/home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
futex(0x7fcc16666d90, FUTEX_WAKE_PRIVATE, 2147483647) = 0
futex(0x7fcc16b44520, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(2, "! Failed to load library: ", 26! Failed to load library: ) = 26
write(2, "/home/username/.rvm/rubies/ruby-2."..., 50/home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so) = 50
write(2, ", error: ", 9, error: ) = 9
write(2, "/home/username/.rvm/rubies/ruby-2."..., 109/home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so: cannot open shared object file: No such file or directory) = 109
write(2, "\n", 1) = 1
I've also written a C script which does the same thing which works perfectly fine when the files are dropped into the same directory. So it might be the fault of the library, which I assume checks the location of the current running program, then tries to load the library from that folder. This would explain the behavior when ran as a Ruby script (since it runs as part of the Ruby program), whereas a C binary runs standalone.
For those that want to re-create the (Linux) issue. You can download the necessary files from here. Which gives you the server-linux-x86_64.sh file.
Supported distros are: Suse, Ubuntu, Debian, Red Hat and CentOS but others may also work fine.
You can either run the installer, which should place the files in /opt/eset/RemoteAdministrator/Server. Or, assuming most of you don't want to install the full application you can run the following command:
sed '1,/^# Start of TAR\.GZ file #$/d' server-linux-x86_64.sh | sed '1d' > server-linux-x86_64.tar.gz
Which removes all the installer instructions from the .sh file and only leaves the binary .tar.gz data, writing it to server-linux-x86_64.tar.gz.
Copy the files ServerApi.so, Protobuf.so and Network.so into a directory of your liking. Create a Ruby script (with the question code) in the same directory and run the script.
Because ServerApi.so checks /proc/self/exe for the location of all subsequent files to load, and it is very difficult to modify this target by normal means, it is easier to just modify ServerApi.so itself so that it uses something else besides proc for the source.
If we run strings ServerApi.so, we can verify that the location to check is stored inside a string in ServerApi.so:
strings ServerApi.so | grep 'proc/self/exe'
B/proc/self/exe
So now all we need to do is modify this string to something else that works for us.
The easiest way to modify the string is to replace it with something that is exactly the same length as the original. This way we do not have to worry about changing the end-of-string zero padding or accidentally changing the total size of ServerApi.so.
Here we can see a suitable candidate could be /tmp/scriptexe:
/proc/self/exe
/tmp/scriptexe <- same length
So let's do that:
sed -e 's/proc\/self\/exe/tmp\/scriptexe/' ServerApi.so > ServerApi_Mod.so
Now we can verify the change:
strings ServerApi_Mod.so | grep scriptexe
B/tmp/scriptexe
Next we need to create /tmp/scriptexe to actually point to our Ruby script:
ln -s /the/full/path/to/our/ruby/script.rb /tmp/scriptexe
Then we modify our script:
dlload './ServerApi_Mod.so
Now we can run it as normal:
ruby script.rb
And everything should work.
If we read the strace output we see that the library obtains the current executable location from /proc/self/exe, and then searches subsequent libraries from there.
/proc/self/exe is not easily modifiable, but by using a hard link to a Ruby executable in the current directory we can trick it to point to a new folder.
Problem is making a hard link requires root.
In any case, here is a self-contained solution (note that it will ask for root password the first time you run it, in order to create the hard link).
Put this at the top of your script:
# Obtain path to current executable
exe = File.readlink("/proc/self/exe")
# Check if we are running the hard-liked version
if !exe.match /localruby/
if !File.exist?('localruby')
# Create a hard link to the current Ruby exe using sudo
system("sudo ln #{exe} localruby")
end
puts "Restarting..."
# In order to prevent infinite busy loop in case of some mishap
sleep 1
# Rerun self using the hard-linked Ruby executable.
# This will make /proc/self/exe point to the hard-link, which then
# allows the ESET library to search for .so files in current folder.
exec('./localruby', File.expand_path(__FILE__))
end
require 'fiddle'
require 'fiddle/import'
# ...rest of your script goes here...
A simple solution without any extra Ruby code is to just create the hard link manually, and then always run the script with ./localruby myscript.rb, instead of using the normal ruby myscript.rb.
I was running AutoPhrase and after running it's auto_phrase.sh shell script, I am getting the following error:
After backtracing it's source, I found this line (line 32) which is causing the above mentioned error.
All I know is it is doing something like:
file < FILE > FILE.extension
However, I failed to understand what is happening in this line.
Can someone could explain it to me ? And how may I resolve this issue ?
The problem here seems to be that ./bin/tree-tagger does not exist. Note that ./bin is not the same as /bin.
That being said, the answer to your question of what file < FILE > FILE.extension does is unrelated, but these are redirects in bash. FILE is piped < into the $STDIN of file and the output is directed > to the file FILE.extension.
Locate ./bin/tree-tagger by installing it or redirecting its path appropriately to resolve the error.
As for the actual question in the title, the command means
./cmd/tree-tagger-english run this command ...
< ... with standard input from ...
$f ... an (incorrectly unquoted) variable which should contain a file name ...
> ... with standard output redirected to ...
$f.tagged ... a file named by the (still incorrectly unquoted) value of $f with the string .tagged appended at the end ...
& ... as a background job.
Apparently ./cmd/tree-tagger-english in turn attempts to execute a command which doesn't exist, many times.
Probably the instructions tell you to run the thing in a different directory than where you are actually running this; but this is obviously merely a speculation. Another fairly common scenario is that something failed during installation, but you failed to notice (and so some files which should exist in these locations do not actually exist ... disk full? Wrong permissions?)
The fact that the code contains quoting bugs suggests that it's also quite possible that the code is simply buggy.
I am using 2 set of scripts for soap communication, inside they are identical classes and variables therefore when using the main script I need to put condition.
if A
require A.rb
if B
require B.rb
The problem is that the ruby2exe does not include these script when compiling the main script.
If have put the 2 require on the top of the file it does not work but then the main script confuse between the classes in the two files.
Idea how to solve it ?
Thanks
Eran
Try to include both at the beginning so the compiler picks them up, later at line +520 you do the include again, i presume the last included file will be what is used.
Also try the ocra compiler which is more recent then ruby2exe.
I face the error when I try to move one file from another.
I'm sure that path is correct. The platform is windows. Permission is correct.
My code is below:
unless File.exists?(f2)
FileUtils.move(f1,f2)
end
Note I don't face problem with every file.
FileUtils.move(f1,f2) rescue do
not File.exists?(f1) and raise "source file does not exist"
File.exists?(f2) and raise "destination file already exists"
end
question should be closable now