Perl program using wrong arguments - linux

I am trying to create simple startup script in perl that will launch various programs on system startup. It is as follows
my #startupPrograms = qw(google-chrome thunderbird skype pidgin );
my #pagesToBeOpenedInChrome = qw(http://www.google.com/ http://stackoverflow.com/ https://mail.google.com/mail/u/0/#inbox);
sub runPrograms() {
print("Starting startup Programs... \n");
foreach (#startupPrograms) {
my $command = $_;
print "Starting Program " . $command . "\n";
if($command == "google-chrome") {
foreach (#pagesToBeOpenedInChrome) {
$command = $command . " " . $_;
}
}
`$command &`;
print "Program " . $command . " started \n";
}
}
But the output I am getting is
[aniket#localhost TestCodes]$ ./startUp.pl
***** Welcome to startup program! *****
Starting startup Programs...
Starting Program google-chrome
Program google-chrome http://www.google.com/ http://stackoverflow.com/ https://mail.google.com/mail/u/0/#inbox started
Starting Program thunderbird
Program thunderbird http://www.google.com/ http://stackoverflow.com/ https://mail.google.com/mail/u/0/#inbox started
Starting Program skype
Program skype http://www.google.com/ http://stackoverflow.com/ https://mail.google.com/mail/u/0/#inbox started
Starting Program pidgin
Program pidgin http://www.google.com/ http://stackoverflow.com/ https://mail.google.com/mail/u/0/#inbox started
Why is taking the pagesToBeOpenedInChrome array contents in each command to be executed? Also it looks like if i put pidgin before other programs it takes forever to start pidgin(other programs are locked). Any help or suggestion is appreciated.

change
if($command == "google-chrome") {
to
if($command eq "google-chrome") {
in perl, you use eq or ne for text comparisons and == for numeric comparisons!
use the == for text basically says if $command is not empty or 0

Related

Why do I get the error "Received usmStatsUnknownUserNames.0 Report-PDU with value 1" when I try to connect to my device using Net::SNMP?

I am trying to write a Perl script to do an SNMP get. It should work like the following command:
snmpget -v 3 -l authNoPriv -a MD5 -u V3User -A V3Password 10.0.1.203 sysUpTime.0
Returns:
SNMPv2-MIB::sysUpTime.0 = Timeticks: (492505406) 57 days, 0:04:14.06
But my Perl script returns the following:
ERROR: Received usmStatsUnknownUserNames.0 Report-PDU with value 1 during synchronization.
Last but not least, here is the Perl script:
use strict;
use warnings;
use Net::SNMP;
my $desc = 'sysUpTime.0';
my ($session, $error) = Net::SNMP->session(
-hostname => '10.0.1.202',
-version => 'snmpv3',
-username => 'V3User',
-authprotocol => 'md5',
-authpassword => 'V3Password'
);
if (!defined($session)) {
printf("ERROR: %s.\n", $error);
exit 1;
}
my $response = $session->get_request($desc);
my %pdesc = %{$response};
my $err = $session->error;
if ($err){
return 1;
}
print %pdesc;
exit 0;
I called the Perl script and snmpget on the same (Linux) machine. What could be causing this and how can I fix it?
As PrgmError points out, you're using a different IP address in your Perl script than in your snmpget command; I would double check that. The particular error you're getting indicates that your username is wrong; if the IP mismatch was simply a typo in your question, I would double check the username next.
A few other points about your Perl script:
Use die
You should use die instead of printf and exit since die will print the line number where it was invoked. This will make debugging your script much easier if there are multiple places it could fail:
die "Error: $error" if not defined $session;
will print something like
Error: foo bar at foo.pl line 17.
Also, using return inside an if statement doesn't make any sense; I think you meant to use
if ($err) {
exit 1;
}
but you should die with the specific error message you get instead of silently failing:
die $err if $err;
Fix arguments to get_request
Your invocation of the get_request method looks wrong. According to the docs, you should be calling it like this:
my $response = $session->get_request(-varbindlist => [ $oid ]);
Note that Net::SNMP only works with numeric OIDs, so you'll have to change sysUpTime.0 to 1.3.6.1.2.1.1.3.0.
Looking at your script I noticed that hostname value has 10.0.1.202
but the snmpget command you're using has 10.0.1.203
wrong IP by any chance?

Setting Binary Transfer mode

My Perl script below is very basic. It goes and copies a .zip file located on one server and transfers it to another server.
#!/usr/bin/perl -w
use strict;
use warnings;
my $remotehost ="XXXXXX";
my $remotepath = "/USA/Fusion_Keyword_Reports";
my $remoteuser = "XXXXXXX";
my $remotepass = "XXXXXXX";
my $inputfile ="/fs/fs01/crmdata/SYWR/AAM/list8.txt";
my $remotefile1;
#my $DIR="/fs/fs01/crmdata/SYWR/AAM";
open (FILEIN, "<", $inputfile) or die "can't open list8 file";
while (my $line =<FILEIN>) {
if ($line =~ m /Keywords-Report(.*?)/i && $line !~ m/Keywords-Report-loopback/i) {
print $line;
$remotefile1 =$line;
last;
}
}
close FILEIN;
print "remotefile $remotefile1\n";
my $DIR1="/fs/fs01/crmdata/SYWR/AAM/$remotefile1";
my $cmd= "ftp -in";
my $ftp_command = "open $remotehost
user $remoteuser $remotepass
cd $remotepath
asc
get $remotefile1
bye
";
open (CMD, "|$cmd");
print CMD $ftp_command;
close (CMD);
exit(0);
When I run the script it does work but I get an error and the file that gets transferred is corrupted as a result.
226 Transfer complete.
WARNING! 40682 bare linefeeds received in ASCII mode.
File may not have transferred correctly.
I did some reading and I think I need to set the transfer mode to binary. However I am really not sure how to do that in my script. Additionally, I am not sure that is the right solution either.
I would really appreciate your thoughts about this error. If setting the transfer mode to Binary will fix this problem can you please show me where I would do that?
my $ftp_command = "open $remotehost
user $remoteuser $remotepass
cd $remotepath
binary
get $remotefile1
bye
";

Perl running two while loop subroutines in parallel

I am looking to run two subroutines in parallel, where both perform the same task on an android handset using ADB commands. With help from SO and other research I have produced the following code below, however I am new to multithreading and I get an error of 'Free to wrong pool' during execution. I am assuming I get this as I am using the $_ variable in both threads, is this correct? I am using Windows7 to run this, but my Perl interpreter crashes on running this script. Any guidance would be greatly appreciated. Thanks.
use strict;
use Win32::OLE;
use EFS_Handle;
use HelperFunctions;
use threads;
#### Various ADB command sequences follow ####
#### Start of multithread to run the same function on different android handsets ####
my #jobs;
push #jobs, threads->create(
sub {
print "\n\t" . curTime() . " :\t DUT Time at start of MPLMN search";
open my $fh1, '>', "output.txt" or die "Cannot open output.txt: $!";
my $pid1 = open my $log1, "-|", "adb -s 42d8d7dd logcat";
system('adb -s 42d8d7dd shell input keyevent KEYCODE_ENTER');
while (<$log1>) {
$fh1->print($_);
last if m/Sorted scan results/;
}
kill "TERM", $pid1;
close $log1;
print "\n\t" . curTime() . " :\t DUT Time at End of MPLMN search\n";
}
);
push #jobs, threads->create(
sub {
print "\n\t" . curTime() . " :\t REF Time at start of MPLMN search";
open my $fh, '>', "output.txt" or die "Cannot open output.txt: $!";
my $pid = open my $log, "-|", "adb -s 0123456789ABCDEF logcat";
system('adb -s 0123456789ABCDEF shell input keyevent KEYCODE_ENTER');
while (<$log>) {
$fh->print($_);
last if m/EVENT_NETWORK_SCAN_COMPLETED/;
}
kill "TERM", $pid;
close $log;
print "\n\t" . curTime() . " :\t REF Time at End of MPLMN search\n";
}
);
$_->join for #jobs;
The Win32::OLE module is famously not thread-safe
If you remove use Win32::OLE (you don't seem to use it) then your code will run fine
If have my doubts about adb cooperating with multiple simultaneous commands, but that is a different matter
I think the problem could be related to the fact you are writing from both threads to the same file "output.txt" with ">". Try opening them with ">>".
Also remember to close that file.
"I am assuming I get this as I am using the $_ variable in both threads..."
If you use strict, and $_ is in separate methods/subroutines, then there should be no global-access problems.

Implementing background processing

UPDATE:
There was an obvious debugging step I forget. What happens if I try a command like ps &
in the regular old bash shell? The answer is that I see the same behavior. For example:
[ahoffer#uw1-320-21 ~/program1]$ ps &
[1] 30166
[ahoffer#uw1-320-21 ~/program1]$ PID TTY TIME CMD
26423 pts/0 00:00:00 bash
30166 pts/0 00:00:00 ps
<no prompt!>
If I then press Enter, the command shell reports the exit status and the console displays the exit status and the prompt:
[ahoffer#uw1-320-21 ~/program1]$ ps&
[1] 30166
[ahoffer#uw1-320-21 ~/program1]$ PID TTY TIME CMD
26423 pts/0 00:00:00 bash
30166 pts/0 00:00:00 ps
[1] Done ps
[ahoffer#uw1-320-21 ~/program1]$
PS: I am using PuttY to access the Linux machine via SSH on port 22.
ORIGINAL QUESTION:
I am working on a homework assignment. The task is to implement part of a command shell interpreter on Linux using functions like fork(), exec(). I have a strange bug that occurs when my code executes a command as a background process.
For example, in the code below, the command ls correctly executes ls and prints its output to the console. When the command is finished, the The event loop in the calling code correctly prints the prompt, "% ", to the console.
However, when ls & is executed, ls executes correctly and its output is printed to the console. However, the prompt, " %", is never printed!
The code is simple. Here is what the pseudo code looks like:
int child_pid;
if ( (child_pid=fork()) == 0 ) {
//child process
...execute the command...
}
else {
//Parent process
if( delim == ';' )
waidpid(child_pid);
}
//end of function.
The parent process blocks if the delimiter is a semicolon. Otherwise the function ends and the code re-enters the event loop. However, if the parent sleeps while the the background command executes, the prompt appears correctly:
...
//Parent process
if( delim == ';' ) {
waidpid(child_pid)
}
else if( delim == '&' ) {
sleep(1);
//The prompt, " %", is correctly printed to the
// console when the parent wakes up.
}
No one in class knows why this happens. The OS is RedHat Enterprise 5 and the compiler is g++.

A way to parse terminal output / input ? (.bashrc ?)

Is there a way to parse input and output from bash commands in an interactive terminal before they reach the screen ? I was thinking maybe something in .bashrc, but I'm new to using bash.
For example:
I type "ls /home/foo/bar/"
That gets passed through a script that replaces all instances of 'bar' with 'eggs'
"ls /home/foo/eggs/" gets executed
The output gets sent back to the replace script
The output of the script is sent to the screen
Yes. Here's something I wrote for my own use, to wrap old command line Fortran programs that ask for file-paths. It allows escaping back to the shell for e.g. running 'ls'. This only works one way, i.e. intercepts user-input and then passes it on to a program, but gets you most of what you want. You can adapt it to your needs.
#!/usr/bin/perl
# shwrap.pl - Wrap any process for convenient escape to the shell.
# ire_and_curses, September 2006
use strict;
use warnings;
# Check args
my $executable = shift || die "Usage: shwrap.pl executable";
my #escape_chars = ('#'); # Escape to shell with these chars
my $exit = 'exit'; # Exit string for quick termination
open my $exe_fh, "|$executable #ARGV" or die "Cannot pipe to program $executable: $!";
# Set magic buffer autoflush on...
select((select($exe_fh), $| = 1)[0]);
# Accept input until the child process terminates or is terminated...
while ( 1 ) {
chomp(my $input = <STDIN>);
# End if we receive the special exit string...
if ( $input =~ m/$exit/ ) {
close $exe_fh;
print "$0: Terminated child process...\n";
exit;
}
foreach my $char ( #escape_chars ) {
# Escape to the shell if the input starts with an escape character...
if ( my ($command) = $input =~ m/^$char(.*)/ ) {
system $command;
}
# Otherwise pass the input on to the executable...
else {
print $exe_fh "$input\n";
}
}
}

Resources