Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to leave netcat running and close the ssh session (even stop the ssh daemon). But it then exits before all of the data is written. I'm testing in a non-ssh (local) console:

nohup nc -l -p 4000  | dd of=/home/myname/test.txt 2>/run/user/myname/stderr  1>/run/user/myname/stdout &

To test it, I close the console and in another console I dump a file:

dd if=/var/log/Xorg.0.log  |  nc localhost 4000

Nothing gets written in /home/myname/test.txt. But if I remove the nohup command, test.txt contains all data dumped. How to get netcat working and detached from the console ?

share|improve this question

3 Answers 3

You have to run the command in its own shell instance.

nohup sh -c 'nc -l -p 4000  | dd of=/home/myname/test.txt 2>/run/user/myname/stderr  1>/run/user/myname/stdout' &
share|improve this answer
    
I did a test with your suggestion. It doesn't work also. - If I don't close the console, only first 2KB are written; if I close it - nothing gets written. If I execute it w/o nohup and do not close the console - it works as expected. –  Angel Genchev Aug 13 '13 at 19:59
up vote 1 down vote accepted

OK, I dug it down: nohup runs the program with standard input redirected from /dev/null. So the dd command won't get anything from nc and nc probably will fail to write & close itself on first write tried. So first we need to create a named pipe to route the I/O via:

mkfifo my.pipe

then run dd with input file from the pipe:

nohup dd if=./my.pipe of=./test.txt 2>/run/user/myname/stderr  1>/run/user/myname/stdout &

Now we can feed the pipe with data from the network. Unfortunately netcat won't do it, because it writes to stdout and this isn't available under nohup. I have to modify the source of netcat. To be easier (w/o C compiler), I'll take a perl loose port to netcat, called also "Poor man's Netcat"...O.K... I rewrote it, adding a file I/O feature with -f parameter. So here's the source:

#! /usr/bin/perl
# Poor man's Netcat, the famous "TCP/IP swiss army knife"
# Only the basic functions are replicated : 
# - TCP only
# - only : "hostname port" or "-l" with "-p port" 
# but with *extended* functionality for direct file I/O by "-f file"

use strict;
use warnings;

use IO::Socket;
use Getopt::Long;

my $help='';
my $verbose;

my $local_port;
my $listen='';
$main::file_io='';

$SIG{CHLD} = 'IGNORE';

my $result = GetOptions(
        "help|h" => \$help,
        "verbose|v" => \$verbose,
    "local-port|p=i" => \$local_port,
    "listen|l" => \$listen,
        "file-io|f=s" => \$main::file_io,
       );
if ($help eq '' && $listen eq '' && (scalar @ARGV < 2) ) {$help = 1;}
if ($help) {
        print STDERR "Perl loose port of netcat(1)\n";
        print STDERR "usage : $0 [-p local_port] hostname port [-f file-for-input] (client)\n";
        print STDERR "   or : $0 -l -p local_port [-f file-for-output] (server)\n";
        exit(1);
}

# No need to close the socks as they are closed 
# when going out-of-scope
if ($listen) 
  { if (! $local_port) { die "You must specify the port to listen to in server mode\n";}
    # server mode
    my $l_sock = IO::Socket::INET->new(
        Proto => "tcp",
        LocalPort => $local_port,
        Listen => 1,
        Reuse => 1,
    ) or die "Could not create socket: $!";

    my $a_sock = $l_sock->accept(); 
    $l_sock->shutdown(SHUT_RDWR);
    read_from_network($a_sock); #server mode - calling read_data 
  } else 
     { #client mode
    if (scalar @ARGV < 2) { die "You must specify where to connect in client mode\n";}
    my ($remote_host, $remote_port) = @ARGV;
    my $c_sock = IO::Socket::INET->new(
        Proto => "tcp",
        LocalPort => $local_port,
        PeerAddr => $remote_host,
        PeerPort => $remote_port,
    ) or die "Could not create socket, reason: $!";
    write_to_network($c_sock);
    }

sub read_from_network 
 {
    my ($socket) = @_;  my $output_fh;
        if($main::file_io ne '') 
       {
             open($output_fh, ">", $main::file_io) or die "Can't open $main::file_io : $!";
           } else { $output_fh = *STDOUT;}
    close(STDIN);
    copy_data_mono($socket, $output_fh);# *STDOUT
        $socket->shutdown(SHUT_RD); 
        close($output_fh); close(STDOUT);
 }


sub write_to_network 
 {
    my ($socket) = @_;
        my $input_fh;
        if($main::file_io ne '') 
       {
             open($input_fh, "<", $main::file_io) or die "Can't open $main::file_io : $!";
           } else { $input_fh = *STDIN;}
    close(STDOUT);
    copy_data_mono($input_fh,$socket);
        $socket->shutdown(SHUT_WR); 
        close($input_fh);close(STDIN);
 }

sub copy_data_mono {
    my ($src, $dst) = @_;
    my $buf;
        print STDERR "copy_data_mono: output: $dst \n";
    while (my $read_len = sysread($src, $buf, 4096)) 
        {
        my $write_len = $read_len;
        while ($write_len) 
                {
         my $written_len = syswrite($dst, $buf);
         return unless $written_len; # $dst is closed
         $write_len -= $written_len;
        }
    }
}

Of course the dd and the named pipe now can be skipped, but I didn't check if this code works well when writing to physical partitions... Now all commands are (assuming the code is saved into netcat_g.pl):

mkfifo my.pipe #create a fifo, @ writable FS
nohup dd if=./my.pipe of=./test.txt & 
nohup ./netcat_g.pl -l -p 4000 -f ./my.pipe  &

and one can close the console. The main drawback is that another commands can't be chained unless they support file I/O and new named pipes are created.

share|improve this answer

Try adding an extra '-d' option to netcat (so it doesn't try to read from stdin). Using that and extending the separate shell solution worked for me even after closing the console and copying over a MB of data:

nohup sh -c 'nc -d -l 4000 | dd of=/home/user/dir/test.txt 
    2>/home/user/dir/stderr  
    1>/home/user/dir/stdout' &
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.