How does the -m switch work in Perl - perl

If you could explain the flow and how/why we can create a module to run with -Mm it will be helpful

-Mfoo simply generates the code use foo; and places it at the beginning of the code to be compiled.
-mfoo generates use foo ();
-Mfoo=bar,baz generates use foo ('bar','baz'); and so does -mfoo=bar,baz -- that is, there stops being a difference between -M and -m when you use the form with an equal sign, but without it, -m generates the "non-import" form of use.
This is all documented in perlrun.

Related

What is $^C in Perl?

I am trying to understand this code in Perl that I have inherited:
sub myfunc($)
{
my ($path) = #_;
unless ($^C)
{
# manipulate path
}
return $path;
}
But I do not understand the $^C test. What does it do?
Perl's -c switch compiles the source and tells you if the syntax is valid. However, Perl doesn't have a strict separation between compile-time and run-time. You can run some code during the compilation (BEGIN blocks), and you can compile code when you are running (eval()).
This means that you might think that you are safe while syntax checking, and that you would be wrong. The second example actually runs some code:
$ perl -c -le 'print "Hello!"'
-e syntax OK
$ perl -c -le 'BEGIN{print "Hello!"}'
Hello!
-e syntax OK
This is more important in IDEs. Many of these will continually run perl -c on your source so it can highlight problems. However, this also means that your IDE is now potentially a trojan horse for executing that code you just copied and pasted from Stackoverflow.
Thus, the $^C guard (see perlvar):
$ perl -c -le 'BEGIN{ print "Hello!" unless $^C }'
-e syntax OK
I'm guessing that the developer who put that there either had a bet to use all the special variables in one program, or was reacting to unwanted behavior from their tools.

What's the meaning of `unless -d`?

Reading the code,I find this:
use File::Path;
mkpath($hinitdir) unless -d $hinitdir;
mkpath($hrestdir) unless -d $hrestdir;
So what's the meaning of the option -d?
Perl has "file test" operators of the form -X, where the letter after the dash tells Perl what you want to test. These are documented in perlfunc collectively under -X.
The -d tests that the target (in this case $hinitdir or $hrestdir) is a directory. The target of a file test operator can be either a named file of a file handle.
Apart from that, recent File::Path versions use make_path over the old mkpath.

Usage of -c in perl with code that modifies #INC

Consider the following script "test.pl".
test.pl
#usr/bin/perl -w
push (#INC,"path_for_abc");
use abc;
#rest of the code ...
Command prompt:
$ perl -c test.pl
I know that I will have to add "use lib" pragma or have to push the path inside #INC in Begin block to make it work.
If the path for the module is not defined in defined in #INC,
Will "perl -c test.pl" push the "path_for_abc" while snytax checking?
No, your sample code won't find the "abc" module when run as perl -c. It won't find it when run without -c either but you appear to know that already. use happens at compile time. The push won't happen until runtime unless it's wrapped in a BEGIN block. If you do that (or use lib) then it will work under perl -c. From perlrun:
-ccauses Perl to check the syntax of the program and then exit
without executing it. Actually, it will execute and BEGIN, UNITCHECK,
or CHECK blocks and any use statements: these are considered as
occurring outside the execution of your program. INIT and END blocks,
however, will be skipped.

What is the significance of -T or -w in #!/usr/bin/perl?

I googled about #!/usr/bin/perl, but I could not find any satisfactory answer. I know it’s a pretty basic thing, but still, could explain me what is the significance of #!/usr/bin/perl in Perl? Moreover, what does -w or -T signify in #!/usr/bin/perl? I am a newbie to Perl, so please be patient.
The #! is commonly called a "shebang" and it tells the computer how to run a script. You'll also see lots of shell-scripts with #!/bin/sh or #!/bin/bash.
So, /usr/bin/perl is your Perl interpreter and it is run and given the file to execute.
The rest of the line are options for Perl. The "-T" is tainting (it means input is marked as "not trusted" until you check it's format). The "-w" turns warnings on.
You can find out more by running perldoc perlrun (perldoc is Perl's documentation reader, might be installed, might be in its own package).
For scripts you write I would recommend starting them with:
#!/usr/bin/perl
use warnings;
use strict;
This turns on lots of warnings and extra checks - especially useful while you are learning (I'm still learning and I've been using Perl for more than 10 years now).
Both -w and -T are sort of "foolproof" flags.
-w is the same as use warning statement in your code, and it's an equivalent of warning option in many compilers. A simplest example would be a warning about using uninitialized variable:
#!/usr/bin/perl -w
print "$A\n";
print "Hello, world!\n";
Will print:
Name "main::A" used only once: possible typo at ./perl-warnings line 3.
Use of uninitialized value $A in concatenation (.) or string at
./perl-warnings line 3.
Hello, world!
The -T flag means that any value that came from the outside world (as opposite to being calculated inside the program) is considered potential threat, and disallows usage of such values in system-related operations, like writing files, executing system command, etc. (That's why Perl would activate the "taint" mode when the script is running under setuid/setgid.)
The "tainted" mode is "enforcing" you to double-check the value inside the script.
E.g., the code:
#!/usr/bin/perl -T
$A = shift;
open FILE, ">$A";
print "$A\n";
close FILE;
Will produce a fatal error (terminating the program):
$ ./perl-tainted jkjk
Insecure dependency in open while running with -T switch at
./perl-tainted line 3.
And that's only because the argument value came from "outside" and was not "double-checked". The "taint" mode is drawing your attention to that fact. Of course, it's easy to fool it, e.g.:
#!/usr/bin/perl -T
$A = shift;
$A = $1 if $A =~ /(^.*$)/;
open FILE, ">$A";
print "$A\n";
close FILE;
In this case everything worked fine. You "fooled" the "taint mode". Well, the assumption is that programer's intentions are to make the program safer, so the programmer wouldn't just work around the error, but would rather take some security measures. One of Perl's nicknames is "the glue and the duct tape of system administrators". It's not unlikely that system administrator would create Perl script for his own needs and would run it with root permissions. Think of this script doing something normal users are not allowed to do... you probably want to double-check things which are not part of the program itself, and you want Perl to remind you about them.
Hope it helps.
about Taint Mode(-T):
require and use statements change when taint mode is turned on.
The path to load libraries/modules no longer contains . (the current directory) from its path.
So if you load any libraries or modules relative to the current working directory without explicitly specifying the path, your script will break under taint mode.
For ex: Consider perl_taint_ex.pl
#!/usr/bin/perl -T
require "abc.pl";
print "Done";
would fail like this
D:\perlex>perl perl_taint_ex.pl
"-T" is on the #! line, it must also be used on the command line
at perl_taint_ex.pl line 1.
D:\perlex>perl -T perl_taint_ex.pl
Can't locate abc.pl in #INC (#INC contains: C:/Perl/site/lib C:/Perl/lib)
at perl_taint_ex.pl line 3.
So when taint mode is on, you must tell the require statement explicitly where to load the library since . is removed during taint mode from the #INC array.
#INC contains a list of valid paths to read library files and modules from.
If taint mode is on, you would simply do the following:
D:\perlex>perl -ID:\perlex -T perl_taint_ex.pl
Done
-ID:\perlex will include directory D:\perlex in #INC.
You can try other ways for adding path to #INC,this is just one example.
It's called a shebang. On Unix based systems (OSX, Linux, etc...) that line indicates the path to the language interpreter when the script is run from the command line. In the case of perl /usr/bin/perl is the path to the perl interpreter. If the hashbang is left out the *nix systems won't know how to parse the script when invoked as an executable. It will instead try to interpret the script in whatever shell the user happens to be running (probably bash) and break the script.
http://en.wikipedia.org/wiki/Hashbang
The -W and -T are arguments that controll the way the perl interpreter operates. They are the same arguments that you could invoke when calling perl interpreter directly from the command line.
-W shows warnings (aka debuging information).
-T turns on taint / security checking.

Is it possible to make 'exec' use '$SHELL -c' instead of '/bin/sh -c' in Perl?

In Perl, is it possible to make 'exec', 'system', and 'qx' use a shell other than /bin/sh (without using a construct like 'exec "$SHELL -c ..."', and without recompiling perl)?
EDIT: The motivation for this question is a bash script that does 'export -f foo' and then uses perl in a subshell to invoke the function directly via 'system "foo"'. I am not sure that this technique will work with all sh, and although 'system "/bin/bash -c foo"' may work in that scenario, I wouldn't expect the exported function to propagate through all variants of /bin/sh. But mostly I was just curious, and am now curious about how to extend the solution to qx. Also, since I know nothing about non-unix platforms, I'd like to avoid hard coding the path to an alternate shell in the solution.
You can override exec and system. See perldoc perlsub for the details, but here is roughly what you want (modulo some quoting bugs I don't feel like trying to fix):
#!/usr/bin/perl
use strict;
use warnings;
use subs qw/system/;
sub system {
#handle one arg version:
if (#_ == 1) {
return CORE::system "$ENV{SHELL} -c $_[0]";
}
#handle the multi argument version
return CORE::system #_;
}
print "normal system:\n";
system "perl", "-e", q{system q/ps -ef | grep $$/};
print "overloaded system:\n";
system 'ps -ef | grep $$';
exec and system will use the shell (which will likely not be /bin/sh on non-UNIX systems) if you only pass one argument to it. (Details are described in perlfunc)
You may want to have a look at IPC::Run3 as an alternative to system
Why don't you want to use 'exec "$SHELL -c ..."'? If you don't want see that code every time you call exec or system, just hide it in a subroutine. That's what they're there for. :)
sub my_exec {
exec $ENV{SHELL}, '-c', #_;
}
If you want to do that, however, I suggest somehow sanitizing $ENV{SHELL} so that people don't do odd things to your script by setting weird values. You might want to ensure that the shell is listed in /etc/shells or whatever way your system lists approved login shells. You also need to do a bit more work to make this taint-clean, which you should probably do if you are going to send data to another process.
exec doesn't use /bin/sh
It just execs the program you specify. No shells.
If you want it to go through a shell you have to do that yourself.