× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



We have an existing program that utilizes Scott Klement's FTPAPI service
program to send a text files to an IIS FTP server.
We now have a requirement to send those same files but between a
client's iSeries server and our Windows server in an ASP environment so
we don't want to do an "in the clear" transmission of this data over the
Internet.

We set up OpenSSH on the client iSeries and on our Windows server (under
cgywin).

I have worked up a new subprocedure within our FTP program that follows
Scott's examples of using spawn() and pipe() APIs to communicate between
jobs.
I references these System i Network articles.

Suppress PASE Output Messages:
http://www.systeminetwork.com/artarchive/newsletter/w/1001/a/51527/index
.html
Don't Submit, Spawn!:
http://www.systeminetwork.com/artarchive/19025/Don_t_Submit__Spawn_.html
Communicating Through a Pipe:
http://www.systeminetwork.com/artarchive/19095/Communicating_Through_a_P
ipe.html
Communicating Through a Pipe, Part 2:
http://www.systeminetwork.com/artarchive/19255/Club_Tech_iSeries_Program
ming_Tips_Newsletter.html

Here is the sftp() subprocedure code:

*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* SFTP(): Handles sending of ProgressBook export files to
* an SSH server using the SFTP.
* (Communication to SFTP program is via pipes.)
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P SFTP B
D SFTP PI

D cmdtext S 100a varying

/free

// ********************************************************
// create pipes for the PASE standard input,
// standard output & standard error
// ********************************************************

// ********************************************************
// report any errors created pipes and
// close all previously created pipes when an error occurs.
// ********************************************************

if ( pipe(stdin) < 0 );
ReportError();
endif;

if ( pipe(stdout) < 0 );
callp close(stdin(OUTPUT_END));
callp close(stdin(INPUT_END));
ReportError();
endif;

if ( pipe(stderr) < 0 );
callp close(stdin(OUTPUT_END));
callp close(stdin(INPUT_END));
callp close(stdout(OUTPUT_END));
callp close(stdout(INPUT_END));
ReportError();
endif;

// ********************************************************
// tell the spawned job to use file descriptors for
// standard input & output.
// ********************************************************

envvar = 'QIBM_USE_DESCRIPTOR_STDIO=Y' + x'00';
envp(1) = %addr(envvar(1));
envp(2) = *NULL;

// ********************************************************
// map the "output" end of the stdin pipe to descriptor
// 0 in the spawned job. This allows us to write to the
// input end of the pipe, and have it be received by the
// QShell/PASE job.
//
// Likewise, map the "input" end of the stdput and stderr
// pipes to the QShell/PASE job's descriptors 1 & 2.
// ********************************************************

fdmap(1) = stdin(OUTPUT_END);
fdmap(2) = stdout(INPUT_END);
fdmap(3) = stderr(INPUT_END);

// ********************************************************
// Set up spawn() so that it'll run the QP2SHELL program
// which, in turn, will run the CP command in PASE
//
// The PASE command run here is:
// "/QOpenSys/usr/sbin/sftp uname@server <mailto:uname@server>
"
// ********************************************************

parm(1) = '/QSYS.LIB/QP2SHELL.PGM' + x'00';
parm(2) = '/QOpenSys/usr/bin/sftp' + x'00';
parm(3) = %trimr(uname) + '@' <mailto:'@'> + %trimr(server) +
x'00';

argv(1) = %addr(parm(1));
argv(2) = %addr(parm(2));
argv(3) = %addr(parm(3));
argv(4) = *NULL;


// ********************************************************
// Spawn the job
// ********************************************************

inh = *Allx'00';
pid = spawn( argv(1)
: 3
: fdmap
: inh
: argv
: envp
);

if ( pid < 0 );
callp close(stdin(OUTPUT_END));
callp close(stdin(INPUT_END));
callp close(stdout(OUTPUT_END));
callp close(stdout(INPUT_END));
callp close(stderr(OUTPUT_END));
callp close(stderr(INPUT_END));
ReportError();
endif;

// ********************************************************
// Pipes have two ends, one for input, one for output.
// The spawned job will use one end of each pipe, and
// this job will use the other. Consequently, we no
// longer need both ends of the pipes.
// ********************************************************

callp close(stdin(OUTPUT_END));
callp close(stdout(INPUT_END));
callp close(stderr(INPUT_END));

// ********************************************************
// Write commands to SFTP
// ********************************************************

// Change directory to import
// FTP equivalent: cmdtext = 'cd ' + FTPDir + EOL;

// SFTP log-on is putting us into top-level directory already
// (This is different than our FTP setups.)
cmdtext = 'cd import' + EOL;
callp write(stdin(INPUT_END): %addr(cmdtext): %len(cmdtext));

// Change local directory (iSeries server)
cmdtext = 'lcd ' + IFSDir + EOL;
callp write(stdin(INPUT_END): %addr(cmdtext): %len(cmdtext));

// Put all *.txt files
cmdtext = 'put *.txt' + EOL;
callp write(stdin(INPUT_END): %addr(cmdtext): %len(cmdtext));

// Put PbCSVFileImport.log
cmdtext = 'put PbCSVFileImport.log' + EOL;
callp write(stdin(INPUT_END): %addr(cmdtext): %len(cmdtext));

// Allow *ALL access to files
cmdtext = 'chmod 777 *.*' + EOL;
callp write(stdin(INPUT_END): %addr(cmdtext): %len(cmdtext));

// List the files
cmdtext = 'ls -l' + EOL;
callp write(stdin(INPUT_END): %addr(cmdtext): %len(cmdtext));

// Quit
cmdtext = 'bye' + EOL;
callp write(stdin(INPUT_END): %addr(cmdtext): %len(cmdtext));

// ********************************************************
// Close the stdin pipe. It'll understand that this
// means that we have nothing more to say.
// ********************************************************

callp close(stdin(INPUT_END));

// ********************************************************
// upgrade the output pipes to use ILE C buffered i/o
// ********************************************************

cout = fdopen(stdout(OUTPUT_END): 'r');
cerr = fdopen(stderr(OUTPUT_END): 'r');

// ********************************************************
// print any output from the QShell/PASE command
// ********************************************************

if (FirstTime);
except Heading;
FirstTime = *Off;
endif;

p_buffer = fgets( %addr(buffer): %size(buffer): cout);
dow (p_buffer <> *NULL);

if (*INOF);
except Heading;
endif;

line = %str(p_buffer);
except PrintData;

p_buffer = fgets( %addr(buffer): %size(buffer): cout);
enddo;

// ********************************************************
// Print any errors from the QShell command
// ********************************************************

//p_buffer = fgets( %addr(buffer): %size(buffer): cerr);
//dow (p_buffer <> *NULL);

// if (FirstTimeErr or *INOF);
// except HeadingErr;
// FirstTimeErr = *Off;
// endif;

// line = %str(p_buffer);
// except PrintData;

// p_buffer = fgets( %addr(buffer): %size(buffer): cerr);
//enddo;

fclose(cout);
fclose(cerr);

*inlr = *on;

/end-free

P E

What I am trying to accomplish under SFTP like I did with FTPAPI is to
send it a series of commands which I thought I could do by writing to
the input end of the stdin pipe I created and whose output end I had
assigned to SFTP when I spawned it.

The "callp write" lines execute but SFTP does not execute any of the
commands I am trying to send it.

Also, if I don't close the input side of the stdin pipe after sending
all my commands, the program will just hang at the fgets line for cout.

Here is the stdout output that I print (modeled after the PRINTPIPE
programs from Scott's articles referenced above):

SFTP to ProgressBook server: Standard Output
sftp> sftp>

I was able to get SFTP to transfer the files and run other commands if I
prepare a batch command file first and then spawn the SFTP program with
the -b argument and the command file name.

Using PASE, spawn() and pipe() are new to me and I'm certainly no Unix
expert so I'm not sure if the program isn't working because of a flaw in
my code or in my understanding of how the stdin pipe works in
communicating with the spawned SFTP job.

Any guidance/help would be appreciated.

Thanks, Scott



As an Amazon Associate we earn from qualifying purchases.

This thread ...

Follow-Ups:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.