I have a perl script that is executed by the Jenkins CI, but when it tries to execute the following code i get a "Inappropriate ioctl for device" error.
$) = $new_group;
if($!){
print STDERR $! . "\n";
print STDERR "Failure to change permissions to: Gid: $new_group \n";
next;
}
$> = $new_user;
if($!){
print STDERR $! . "\n";
print STDERR "Failure to change permissions to: Uid: $new_user \n";
next;
}
But while if a do the same manually like this, i receive no error
perl -e '$) = 99; if($!){print $! ."\n";} $> = 99; if($!){print $!."\n";}print `whoami`;'
Any clues why this error occures, and what i means? I have search the net, but it seems to occur when filehandlers are open, havnt seen any examples on it occuring when changing users.
All scripts are executed as root.
$! is only useful directly after a failed system call. When setting the group or user is successful, you don't really know what will be in $!, and can't rely on it being a false value. You might trying using 'or die ' when setting the user and group, or maybe just comparing $) and $> to $new_group and $new_user again after you attempt to set them.
To debug the code, use this method, and see whats going on. Print out each variable content when you receive an error. Please use strict and warnings, they heelp you a lot!
Please include the output if you cannot solve this problem with this method.
use strict;
use warnings;
use Data::Dumper;
$) = $new_group;
warn "\$), \$new_group: ".Dumper($),$new_group);
...
Related
When starting my http server I don't want to see >> Dancer2 v0.201000 server <pid> listening on http://0.0.0.0:<port> printed on the stderr. Thats why I added the following line before calling start()
get "/pwd" => sub {
my $pwd = cwd;
print STDERR "\n\n[PWD] : $pwd\n"; # this line is not being printed
print "\n\n[STDOUT::PWD] : $pwd\n";
my %responseHash = ( pwd => $pwd );
my $response = encode_json \%responseHash;
return $response;
};
my $dancerStartErr;
sub startServer {
open (local *STDERR, ">", \$dancerStartErr)
or die "Dup err to variable error: $!\n";
start();
}
startServer();
The problem is that later I can't print something on the STERR. How can I reopen STDERR (open(STDERR, ">", \*STDERR); doesn't help)?
If you don't want your application to log anything, you can change the logging engine to use Dancer2::Logger::Null. You do that by editing your config.yml, or in one of your environments. For example, to turn it off in producion, change # appdir/environments/production.yml.
logger: 'null'
The default is the logging engine 'console', which prints stuff to your terminal.
There are other Dancer2::Logger:: classes available bundled with Dancer2 and on CPAN in their own distributions. A better solution to just dumping everything into a black hole might be to log to a file instead. Documentation of how to configure it further can be found in Dancer2::Core::Role::Logger.
Also note that instead of printing to STDERR in your code, you should use the logging keywords with the appropriate log level.
print STDERR "\n\n[PWD] : $pwd\n"; # this line is not being printed
This is not a good idea, because you cannot distinguish if this is an error, or a warning, or just debugging output. That's why there are different log levels built into Dancer2.
core
debug
info
warning
error
All of them are available as keywords. There is documentation on it in Dancer2::Manual.
Since the working directory is probably not relevant in production, but only during development, you'd go with debug.
debug "[PWD] : $pwd";
That's it. It takes care of newlines and such for you automatically.
You could use select before redirecting to save it in a variable
my $oldfh = select(STDERR);
and then use it later
select($oldfh);
Also check out:
Capture::Tiny::Extended
How to redirect and restore STDOUT/STDERR
This code is used to read and write through the pipe, but it seems it is not working well.
use strict;
use IPC::Open2;
my $st1="String1\n";
my $st2="String2\n";
my $st3="String3\n";
my $st4="String4\n";
my $st5="String5\n";
my $joint=$st1.$st2.$st3.$st4.$st5;
my $r;
my $pid = open2(\*CHILD_IN, \*CHILD_OUT, 'java -Dfile.encoding=UTF8 -cp abc.jar:xxx.jar TestCode')
or die "open2() failed $!";
print CHILD_IN $joint;
$r=<CHILD_OUT>;
print "Got $r from child\n";
print "[OUTPUT]: $_" while (<CHILD_OUT>);
This code is only reading first line of the output that too which is stored in $r. Not going inside while loop. Although there is a lot of output by executing the command.
You have a typo.
$r=<CHLD_OUT>;
and
print "[OUTPUT]: $_" while (<CHILD_OUT>);
It's CHLD_OUT versus CHILD_OUT.
It's probably better to always use
use warnings
It'd save you from the trouble, by showing a warning message:
readline() on unopened filehandle CHILD_OUT at x.pl line 19.
novice Perl programmer here!.
I'm using the system() function to get the return code for an external program (in this case - php), however, the command's output is still printed to the screen.
How do I prevent it from doing so?
My code is:
use strict; use warnings;
print 'Return code:', system('php -l wrong.php'), "\n";
This code does print the return code, but it also print the the output of the command executed.
Any help will be appreciated!
EDIT: further testing shown that this happens while only using the php lint command.. using it with other commands doesnt print anything...
What you want is IPC::Open3:
use IPC::Open3;
use Symbol qw(gensym);
my $err = gensym; #work around IPC::Open3's interface
my $pid = open3 my $wtr, my $rdr, $err,
'some cmd', 'arg1', 'arg2', ...;
The separates out stdin into $wtr, stdout into $rdr, and stderr into $err
This also gives you maximum control over communicating with the process
If you are on a UNIX-like OS, you should be able to redirect the output in the command:
Try:
system('php -l wrong.php >> /dev/null') to get rid of what's being sent to stdout.
You could also open the command with a pipe to handle the output directly, which should be more portable.
I want to redirect the die messages to a separate file so that I can compare that file later to determine what went wrong.
But this code gives me errors:
$ cat test.pl
use strict;
use warnings;
my $log = "msglog.log";
die $log "DEAD$!";
$ perl test.pl
Missing comma after first argument to die function at test.pl line 5, near ""DEAD$!";"
Execution of test.pl aborted due to compilation errors.
$
I do not want to do a 2> from the caller. Is there someway to redirect them from within the script?
You can install a $SIG{__DIE__} handler to be run just before the "die" runs. The handler will be called with the error message which you can log:
local $SIG{__DIE__} = sub {
my ($message) = #_;
# log the message
};
See $SIG{expr} in perlvar for details.
Perl's die prints to STDERR so you could redirect STDERR to a file.
#!/usr/bin/env perl
# the path above depends on your system
open(STDERR, ">>", "errlog.log");
die "Hello";
The Log::Log4perl module offers more than a few options.
One can choose to output the error message to both STDERR and the logfile.
my $logger = Log::Log4perl->init ( 'log.conf' );
# Configuration file controls what to output, like time, line number, class...
$logger->get_logger ( 'Hello::World' ); # Define which class logger to use
.
.
.
open my $fh, '<', $file
or $logger->logdie ( "Log the demise: $!" ); # ... and die;
While it requires a little bit more effort in terms of setup, its flexibility unlocks a great deal of potential.
I have currently a DNS Reverse lookup script which works however there is a small little issue of the script being able to output the DNS system errors.
The problems goes like this:
User keys in false/wrong internet address name etc. "www.whyisthednsnothappening.com"
The script would then clear the screen using system(clear)
The script would then print "can't resolve DNS. The error is due to: various System error"
The script re directs the user back to the same menu/script to type in the name address again.
So the main problem is now step 3 which the script only shows me "Can't resolve DNS. The error is due to: BLANK " Which BLANK is suppose to show errors like "Bad arg length for Socket::inet_ntoa, length is 0, should be 4 at ./showdns.pl line 28, <> line 1." and the menu of the DNS script is located below of the error print.
The Codes:
#!/usr/bin/perl
use IO::Socket;
use warnings;
use strict;
use Term::ANSIColor;
use Socket;
use Sys::Hostname;
print "\nYou are now in Show DNS IP Address!\n\n";
print "*************\n";
print "|DNS Address|\n";
print "*************\n";
print "\nPlease enter a hostname that you wish to view\n\n";
print "\n\nEnter the hostname of Choice Here: ";
my $userchoice = <>;
chomp ($userchoice);
my $hostname = $userchoice;
my $i_addr = scalar(gethostbyname($hostname || 'localhost'));
if ( ! defined $i_addr ) {
my $err = $!;
my $herr = int herror(const char *s);
system('clear');
print("Can't resolve $hostname: $herr, try again");
exec("/root/Desktop/showdns.pl");
exit();
}
my $name = inet_ntoa($i_addr);
my $coloredText = colored($name, 'bold underline blue');
print "\n\nThe hostname IP address is: $coloredText\n\n";
print "Press enter to go back to the main menu\n\n";
my $userinput2 = <>;
chomp ($userinput2);
system("clear");
system("/root/Desktop/simpleip.pl");
Can someone please give advice on the codes? Thanks!
Ah, I see what you mean. The system("clear") call is clearing the $! variable before you have a chance to print the error from gethostbyname.
my $i_addr = scalar(gethostbyname($hostname || 'localhost'));
if ( ! defined $i_addr ) {
my $err = $!;
system("clear");
print("Can't resolve $hostname: $err, try again");
system("/root/Desktop/showdns.pl");
exit();
}
Though as far as I can tell, the particular error gethostbyname returns isn't very meaningful.
You may want to look into putting a loop in your script instead of having it start over using system(). You certainly don't want to continue on to inet_ntoa if there was a failure. Note that inet_ntoa doesn't have anything to do with a DNS lookup; that's done by gethostbyname. inet_ntoa just changes a 4-byte string into the normal 123.123.123.123
printable form of an ipaddress. sprintf("%vd", $i_addr) does the same thing.
Two additional questions:
If you remove the call to
system('clear') Does the error
from gethostbyname get displayed
then?
Why do you use
system('/root/Desktop/showdns.pl')
To call the same script recursively?
Wouldn't it be better to use exec
instead of system? exec terminates
the current process. while system
forks of an entire new process and
waits for that process to exit. So
if your users enter, for example, 20
invalid hostnames, you'll end up
with 20 processes just waiting for
the one that was most recently
created.
Gr,
ldx
Please check the following to resolve the above "dns" issues in perl script.
As DNS server is not running, perl will not resolve the address. so it returns an empty string and inet_ntoa will throw error for that empty string.
If you are using a linux system please verify the following:
a) Check the internet address in the file /etc/resolv.conf
nameserver 172.19.1.11 (IP address of your internet or survice provider)
b) Add "dns" in the /etc/nsswitch.conf file as follows:
hosts: files dns