aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/libssh_scp.c338
1 files changed, 192 insertions, 146 deletions
diff --git a/examples/libssh_scp.c b/examples/libssh_scp.c
index b31c6c65..8a2c3001 100644
--- a/examples/libssh_scp.c
+++ b/examples/libssh_scp.c
@@ -17,22 +17,37 @@ program.
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <sys/stat.h>
#include <libssh/libssh.h>
#include "examples_common.h"
-char *host;
-char *user;
-int sftp;
+char **sources;
+int nsources;
+char *destination;
+int verbosity=0;
+
+struct location {
+ int is_ssh;
+ char *user;
+ char *host;
+ char *path;
+ ssh_session session;
+ ssh_channel channel;
+ FILE *file;
+};
+
+enum {
+ READ,
+ WRITE
+};
static void usage(const char *argv0){
- fprintf(stderr,"Usage : %s [options] [login@]hostname\n"
- "sample scp client - libssh-%s\n"
- "Options :\n"
- " -l user : log in as user\n"
- " -p port : connect to port\n"
- " -d : use DSS to verify host public key\n"
- " -r : use RSA to verify host public key\n",
+ fprintf(stderr,"Usage : %s [options] [[user@]host1:]file1 ... \n"
+ " [[user@]host2:]destination\n"
+ "sample scp client - libssh-%s\n",
+// "Options :\n",
+// " -r : use RSA to verify host public key\n",
argv0,
ssh_version(0));
exit(0);
@@ -40,181 +55,212 @@ static void usage(const char *argv0){
static int opts(int argc, char **argv){
int i;
- if(strstr(argv[0],"sftp"))
- sftp=1;
- // for(i=0;i<argc;i++)
- // printf("%d : %s\n",i,argv[i]);
- /* insert your own arguments here */
- while((i=getopt(argc,argv,""))!=-1){
+ while((i=getopt(argc,argv,"v"))!=-1){
switch(i){
+ case 'v':
+ verbosity++;
+ break;
default:
fprintf(stderr,"unknown option %c\n",optopt);
usage(argv[0]);
+ return -1;
}
}
- if(optind < argc)
- host=argv[optind++];
- if(host==NULL)
+ nsources=argc-optind-1;
+ if(nsources < 1){
usage(argv[0]);
- return 0;
-}
-
-ssh_channel chan;
-
-static void select_loop(SSH_SESSION *session,ssh_channel channel){
- fd_set fds;
- struct timeval timeout;
- char buffer[10];
- ssh_buffer readbuf=buffer_new();
- ssh_channel channels[2];
- int lus;
- int eof=0;
- int maxfd;
- int ret;
- while(channel){
- /* when a signal is caught, ssh_select will return
- * with SSH_EINTR, which means it should be started
- * again. It lets you handle the signal the faster you
- * can, like in this window changed example. Of course, if
- * your signal handler doesn't call libssh at all, you're
- * free to handle signals directly in sighandler.
- */
- do{
- FD_ZERO(&fds);
- if(!eof)
- FD_SET(0,&fds);
- timeout.tv_sec=30;
- timeout.tv_usec=0;
- FD_SET(ssh_get_fd(session),&fds);
- maxfd=ssh_get_fd(session)+1;
- ret=select(maxfd,&fds,NULL,NULL,&timeout);
- if(ret==EINTR)
- continue;
- if(FD_ISSET(0,&fds)){
- lus=read(0,buffer,10);
- if(lus)
- channel_write(channel,buffer,lus);
- else {
- eof=1;
- channel_send_eof(channel);
- }
- }
- if(FD_ISSET(ssh_get_fd(session),&fds)){
- ssh_set_fd_toread(session);
- }
- channels[0]=channel; // set the first channel we want to read from
- channels[1]=NULL;
- ret=channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
- } while (ret==EINTR || ret==SSH_EINTR);
-
- // we already looked for input from stdin. Now, we are looking for input from the channel
-
- if(channel && channel_is_closed(channel)){
- ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
-
- channel_free(channel);
- channel=NULL;
- channels[0]=NULL;
- }
- if(channels[0]){
- while(channel && channel_is_open(channel) && channel_poll(channel,0)){
- lus=channel_read_buffer(channel,readbuf,0,0);
- if(lus==-1){
- fprintf(stderr, "Error reading channel: %s\n",
- ssh_get_error(session));
- return;
- }
- if(lus==0){
- ssh_log(session,SSH_LOG_RARE,"EOF received\n");
- ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
-
- channel_free(channel);
- channel=channels[0]=NULL;
- } else
- write(1,buffer_get(readbuf),lus);
- }
- while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
- lus=channel_read_buffer(channel,readbuf,0,1);
- if(lus==-1){
- fprintf(stderr, "Error reading channel: %s\n",
- ssh_get_error(session));
- return;
- }
- if(lus==0){
- ssh_log(session,SSH_LOG_RARE,"EOF received\n");
- ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
- channel_free(channel);
- channel=channels[0]=NULL;
- } else
- write(2,buffer_get(readbuf),lus);
- }
- }
- if(channel && channel_is_closed(channel)){
- channel_free(channel);
- channel=NULL;
- }
+ return -1;
}
- buffer_free(readbuf);
-}
-
-static void batch_shell(ssh_session session){
- ssh_channel channel;
- char buffer[1024];
- channel=channel_new(session);
- channel_open_session(channel);
- if(channel_request_exec(channel,buffer)){
- printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
- return;
+ sources=malloc((nsources + 1) * sizeof(char *));
+ if(sources == NULL)
+ return -1;
+ for(i=0;i<nsources;++i){
+ sources[i] = argv[optind];
+ optind++;
}
- select_loop(session,channel);
+ sources[i]=NULL;
+ destination=argv[optind];
+ return 0;
}
-int main(int argc, char **argv){
- SSH_SESSION *session;
- SSH_OPTIONS *options;
+static ssh_session connect_ssh(char *host, char *user){
+ ssh_session session;
+ ssh_options options;
int auth=0;
-
options=ssh_options_new();
- if(ssh_options_getopt(options,&argc, argv)){
- fprintf(stderr,"error parsing command line :%s\n",ssh_get_error(options));
- usage(argv[0]);
- }
- opts(argc,argv);
- if (user) {
+ if(user != NULL){
if (ssh_options_set_username(options,user) < 0) {
ssh_options_free(options);
- return 1;
+ return NULL;
}
}
if (ssh_options_set_host(options,host) < 0) {
ssh_options_free(options);
- return 1;
+ return NULL;
}
+ ssh_options_set_log_verbosity(options,verbosity);
session=ssh_new();
ssh_set_options(session,options);
if(ssh_connect(session)){
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
ssh_disconnect(session);
- ssh_finalize();
- return 1;
+ return NULL;
}
if(verify_knownhost(session)<0){
ssh_disconnect(session);
- ssh_finalize();
- return 1;
+ return NULL;
}
auth=authenticate_console(session);
if(auth==SSH_AUTH_SUCCESS){
- batch_shell(session);
+ return session;
} else if(auth==SSH_AUTH_DENIED){
fprintf(stderr,"Authentication failed\n");
} else {
fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session));
}
ssh_disconnect(session);
- ssh_finalize();
+ return NULL;
+}
+
+static struct location *parse_location(char *loc){
+ struct location *location=malloc(sizeof(struct location));
+ char *ptr;
+
+ location->host=location->user=NULL;
+ ptr=strchr(loc,':');
+ if(ptr != NULL){
+ location->is_ssh=1;
+ location->path=strdup(ptr+1);
+ *ptr='\0';
+ ptr=strchr(loc,'@');
+ if(ptr != NULL){
+ location->host=strdup(ptr+1);
+ *ptr='\0';
+ location->user=strdup(loc);
+ } else {
+ location->host=strdup(loc);
+ }
+ } else {
+ location->is_ssh=0;
+ location->path=strdup(loc);
+ }
+ return location;
+}
+static int open_location(struct location *loc, int flag){
+ char buffer[1024];
+
+ if(loc->is_ssh && flag==WRITE){
+ loc->session=connect_ssh(loc->host,loc->user);
+ if(!loc->session){
+ fprintf(stderr,"Couldn't connect to %s\n",loc->host);
+ return -1;
+ }
+ loc->channel=channel_new(loc->session);
+ channel_open_session(loc->channel);
+ channel_request_pty(loc->channel);
+ snprintf(buffer,sizeof(buffer),"scp -vt %s",loc->path);
+ fprintf(stderr,"sending \"%s\"\n",buffer);
+ if(channel_request_exec(loc->channel,buffer) < 0){
+ printf("error executing scp: %s\n",ssh_get_error(loc->session));
+ return -1;
+ }
+ return 0;
+ } else {
+ loc->file=fopen(loc->path,flag==READ ? "r":"w");
+ if(!loc->file){
+ fprintf(stderr,"Error opening %s : %s\n",loc->path,strerror(errno));
+ return -1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+static int do_copy(struct location *src, struct location *dest){
+ int size;
+ socket_t fd;
+ struct stat s;
+ int w,r;
+ char buffer[4196];
+ /*FIXME*/
+ if(dest->is_ssh && !src->is_ssh){
+ fd=fileno(src->file);
+ fstat(fd,&s);
+ size=s.st_size;
+ } else
+ size=0;
+ snprintf(buffer,sizeof(buffer),"C0644 %d %s\n",size,src->path);
+ printf("writing \"%s\"",buffer);
+ if(channel_write(dest->channel,buffer,strlen(buffer))<0){
+ fprintf(stderr,"channel_write : %s\n",ssh_get_error(dest->session));
+ return -1;
+ }
+ r=channel_read(dest->channel,buffer,1,0);
+ write(1,buffer,1);
+ do {
+ r=fread(buffer,1,sizeof(buffer),src->file);
+ if(r==0)
+ break;
+ if(r<0){
+ fprintf(stderr,"Error reading file: %s\n",strerror(errno));
+ return -1;
+ }
+ w=channel_write(dest->channel,buffer,r);
+ if(w<0){
+ fprintf(stderr,"error writing in channel: %s\n",ssh_get_error(dest->session));
+ return -1;
+ }
+ if(w!=r){
+ fprintf(stderr,"coulnd write %d bytes : %d\n",r,w);
+ }
+ if((r=channel_poll(dest->channel,0))>0){
+ r=channel_read(dest->channel,buffer,r,0);
+ write(1,buffer,r);
+ }
+ if((r=channel_poll(dest->channel,1)) > 0){
+ r=channel_read(dest->channel,buffer,r,1);
+ write(1,buffer,r);
+ }
+ } while(1);
+ channel_write(dest->channel,"\0",1);
+ channel_send_eof(dest->channel);
+ do{
+ if((r=channel_poll(dest->channel,0))>0){
+ r=channel_read(dest->channel,buffer,r,0);
+ if(r<=0)
+ break;
+ write(1,buffer,r);
+ }
+ if((r=channel_poll(dest->channel,1)) > 0){
+ r=channel_read(dest->channel,buffer,r,1);
+ if(r<=0)
+ break;
+ write(1,buffer,r);
+ }
+ } while(r>0);
+ return 0;
+}
+
+int main(int argc, char **argv){
+ struct location *dest, *src;
+ int i;
+
+ if(opts(argc,argv)<0)
+ return EXIT_FAILURE;
+ dest=parse_location(destination);
+ if(open_location(dest,WRITE)<0)
+ return EXIT_FAILURE;
+ for(i=0;i<nsources;++i){
+ src=parse_location(sources[i]);
+ if(open_location(src,READ)<0){
+ return EXIT_FAILURE;
+ }
+ if(do_copy(src,dest) < 0)
+ return EXIT_FAILURE;
+ }
+ ssh_finalize();
return 0;
}