|
Packit |
6c0a39 |
/*
|
|
Packit |
6c0a39 |
Copyright 2003-2009 Aris Adamantiadis
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
This file is part of the SSH Library
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
You are free to copy this file, modify it in any way, consider it being public
|
|
Packit |
6c0a39 |
domain. This does not apply to the rest of the library though, but it is
|
|
Packit |
6c0a39 |
allowed to cut-and-paste working code from this file to any license of
|
|
Packit |
6c0a39 |
program.
|
|
Packit |
6c0a39 |
The goal is to show the API in action. It's not a reference on how terminal
|
|
Packit |
6c0a39 |
clients must be made or how a client should react.
|
|
Packit |
6c0a39 |
*/
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
#include "config.h"
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
#include <sys/statvfs.h>
|
|
Packit |
6c0a39 |
#include <stdio.h>
|
|
Packit |
6c0a39 |
#include <errno.h>
|
|
Packit |
6c0a39 |
#include <fcntl.h>
|
|
Packit |
6c0a39 |
#include <stdlib.h>
|
|
Packit |
6c0a39 |
#include <string.h>
|
|
Packit |
6c0a39 |
#ifdef HAVE_UNISTD_H
|
|
Packit |
6c0a39 |
#include <unistd.h>
|
|
Packit |
6c0a39 |
#endif
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
#include <libssh/libssh.h>
|
|
Packit |
6c0a39 |
#include <libssh/sftp.h>
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
#include "examples_common.h"
|
|
Packit |
6c0a39 |
#ifdef WITH_SFTP
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
static int verbosity;
|
|
Packit |
6c0a39 |
static char *destination;
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
#define DATALEN 65536
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
static void do_sftp(ssh_session session) {
|
|
Packit |
6c0a39 |
sftp_session sftp = sftp_new(session);
|
|
Packit |
6c0a39 |
sftp_dir dir;
|
|
Packit |
6c0a39 |
sftp_attributes file;
|
|
Packit |
6c0a39 |
sftp_statvfs_t sftpstatvfs;
|
|
Packit |
6c0a39 |
struct statvfs sysstatvfs;
|
|
Packit |
6c0a39 |
sftp_file fichier;
|
|
Packit |
6c0a39 |
sftp_file to;
|
|
Packit |
6c0a39 |
int len = 1;
|
|
Packit |
6c0a39 |
unsigned int i;
|
|
Packit |
6c0a39 |
char data[DATALEN] = {0};
|
|
Packit |
6c0a39 |
char *lnk;
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
unsigned int count;
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
if (!sftp) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "sftp error initialising channel: %s\n",
|
|
Packit |
6c0a39 |
ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
if (sftp_init(sftp)) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "error initialising sftp: %s\n",
|
|
Packit |
6c0a39 |
ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
printf("Additional SFTP extensions provided by the server:\n");
|
|
Packit |
6c0a39 |
count = sftp_extensions_get_count(sftp);
|
|
Packit |
6c0a39 |
for (i = 0; i < count; i++) {
|
|
Packit |
6c0a39 |
printf("\t%s, version: %s\n",
|
|
Packit |
6c0a39 |
sftp_extensions_get_name(sftp, i),
|
|
Packit |
6c0a39 |
sftp_extensions_get_data(sftp, i));
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
/* test symlink and readlink */
|
|
Packit |
6c0a39 |
if (sftp_symlink(sftp, "/tmp/this_is_the_link",
|
|
Packit |
6c0a39 |
"/tmp/sftp_symlink_test") < 0)
|
|
Packit |
6c0a39 |
{
|
|
Packit |
6c0a39 |
fprintf(stderr, "Could not create link (%s)\n",
|
|
Packit |
6c0a39 |
ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
lnk = sftp_readlink(sftp, "/tmp/sftp_symlink_test");
|
|
Packit |
6c0a39 |
if (lnk == NULL) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Could not read link (%s)\n", ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
printf("readlink /tmp/sftp_symlink_test: %s\n", lnk);
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
sftp_unlink(sftp, "/tmp/sftp_symlink_test");
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
if (sftp_extension_supported(sftp, "statvfs@openssh.com", "2")) {
|
|
Packit |
6c0a39 |
sftpstatvfs = sftp_statvfs(sftp, "/tmp");
|
|
Packit |
6c0a39 |
if (sftpstatvfs == NULL) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "statvfs failed (%s)\n", ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
printf("sftp statvfs:\n"
|
|
Packit |
6c0a39 |
"\tfile system block size: %llu\n"
|
|
Packit |
6c0a39 |
"\tfundamental fs block size: %llu\n"
|
|
Packit |
6c0a39 |
"\tnumber of blocks (unit f_frsize): %llu\n"
|
|
Packit |
6c0a39 |
"\tfree blocks in file system: %llu\n"
|
|
Packit |
6c0a39 |
"\tfree blocks for non-root: %llu\n"
|
|
Packit |
6c0a39 |
"\ttotal file inodes: %llu\n"
|
|
Packit |
6c0a39 |
"\tfree file inodes: %llu\n"
|
|
Packit |
6c0a39 |
"\tfree file inodes for to non-root: %llu\n"
|
|
Packit |
6c0a39 |
"\tfile system id: %llu\n"
|
|
Packit |
6c0a39 |
"\tbit mask of f_flag values: %llu\n"
|
|
Packit |
6c0a39 |
"\tmaximum filename length: %llu\n",
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_bsize,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_frsize,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_blocks,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_bfree,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_bavail,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_files,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_ffree,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_favail,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_fsid,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_flag,
|
|
Packit |
6c0a39 |
(unsigned long long) sftpstatvfs->f_namemax);
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
sftp_statvfs_free(sftpstatvfs);
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
if (statvfs("/tmp", &sysstatvfs) < 0) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "statvfs failed (%s)\n", strerror(errno));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
printf("sys statvfs:\n"
|
|
Packit |
6c0a39 |
"\tfile system block size: %llu\n"
|
|
Packit |
6c0a39 |
"\tfundamental fs block size: %llu\n"
|
|
Packit |
6c0a39 |
"\tnumber of blocks (unit f_frsize): %llu\n"
|
|
Packit |
6c0a39 |
"\tfree blocks in file system: %llu\n"
|
|
Packit |
6c0a39 |
"\tfree blocks for non-root: %llu\n"
|
|
Packit |
6c0a39 |
"\ttotal file inodes: %llu\n"
|
|
Packit |
6c0a39 |
"\tfree file inodes: %llu\n"
|
|
Packit |
6c0a39 |
"\tfree file inodes for to non-root: %llu\n"
|
|
Packit |
6c0a39 |
"\tfile system id: %llu\n"
|
|
Packit |
6c0a39 |
"\tbit mask of f_flag values: %llu\n"
|
|
Packit |
6c0a39 |
"\tmaximum filename length: %llu\n",
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_bsize,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_frsize,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_blocks,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_bfree,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_bavail,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_files,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_ffree,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_favail,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_fsid,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_flag,
|
|
Packit |
6c0a39 |
(unsigned long long) sysstatvfs.f_namemax);
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
/* the connection is made */
|
|
Packit |
6c0a39 |
/* opening a directory */
|
|
Packit |
6c0a39 |
dir = sftp_opendir(sftp, "./");
|
|
Packit |
6c0a39 |
if (!dir) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Directory not opened(%s)\n", ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
/* reading the whole directory, file by file */
|
|
Packit |
6c0a39 |
while ((file = sftp_readdir(sftp, dir))) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "%30s(%.8o) : %s(%.5d) %s(%.5d) : %.10llu bytes\n",
|
|
Packit |
6c0a39 |
file->name,
|
|
Packit |
6c0a39 |
file->permissions,
|
|
Packit |
6c0a39 |
file->owner,
|
|
Packit |
6c0a39 |
file->uid,
|
|
Packit |
6c0a39 |
file->group,
|
|
Packit |
6c0a39 |
file->gid,
|
|
Packit |
6c0a39 |
(long long unsigned int) file->size);
|
|
Packit |
6c0a39 |
sftp_attributes_free(file);
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
/* when file = NULL, an error has occured OR the directory listing is end of
|
|
Packit |
6c0a39 |
* file */
|
|
Packit |
6c0a39 |
if (!sftp_dir_eof(dir)) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
if (sftp_closedir(dir)) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
/* this will open a file and copy it into your /home directory */
|
|
Packit |
6c0a39 |
/* the small buffer size was intended to stress the library. of course, you
|
|
Packit |
6c0a39 |
* can use a buffer till 20kbytes without problem */
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
fichier = sftp_open(sftp, "/usr/bin/ssh", O_RDONLY, 0);
|
|
Packit |
6c0a39 |
if (!fichier) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
|
|
Packit |
6c0a39 |
ssh_get_error(session));
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
/* open a file for writing... */
|
|
Packit |
6c0a39 |
to = sftp_open(sftp, "ssh-copy", O_WRONLY | O_CREAT, 0700);
|
|
Packit |
6c0a39 |
if (!to) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
|
|
Packit |
6c0a39 |
ssh_get_error(session));
|
|
Packit |
6c0a39 |
sftp_close(fichier);
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
while ((len = sftp_read(fichier, data, 4096)) > 0) {
|
|
Packit |
6c0a39 |
if (sftp_write(to, data, len) != len) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Error writing %d bytes: %s\n",
|
|
Packit |
6c0a39 |
len, ssh_get_error(session));
|
|
Packit |
6c0a39 |
sftp_close(to);
|
|
Packit |
6c0a39 |
sftp_close(fichier);
|
|
Packit |
6c0a39 |
goto end;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
printf("finished\n");
|
|
Packit |
6c0a39 |
if (len < 0) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
sftp_close(fichier);
|
|
Packit |
6c0a39 |
sftp_close(to);
|
|
Packit |
6c0a39 |
printf("fichiers ferm\n");
|
|
Packit |
6c0a39 |
to = sftp_open(sftp, "/tmp/grosfichier", O_WRONLY|O_CREAT, 0644);
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
for (i = 0; i < 1000; ++i) {
|
|
Packit |
6c0a39 |
len = sftp_write(to, data, DATALEN);
|
|
Packit |
6c0a39 |
printf("wrote %d bytes\n", len);
|
|
Packit |
6c0a39 |
if (len != DATALEN) {
|
|
Packit |
6c0a39 |
printf("chunk %d : %d (%s)\n", i, len, ssh_get_error(session));
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
sftp_close(to);
|
|
Packit |
6c0a39 |
end:
|
|
Packit |
6c0a39 |
/* close the sftp session */
|
|
Packit |
6c0a39 |
sftp_free(sftp);
|
|
Packit |
6c0a39 |
printf("sftp session terminated\n");
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
static void usage(const char *argv0) {
|
|
Packit |
6c0a39 |
fprintf(stderr, "Usage : %s [-v] remotehost\n"
|
|
Packit |
6c0a39 |
"sample sftp test client - libssh-%s\n"
|
|
Packit |
6c0a39 |
"Options :\n"
|
|
Packit |
6c0a39 |
" -v : increase log verbosity\n",
|
|
Packit |
6c0a39 |
argv0,
|
|
Packit |
6c0a39 |
ssh_version(0));
|
|
Packit |
6c0a39 |
exit(0);
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
static int opts(int argc, char **argv) {
|
|
Packit |
6c0a39 |
int i;
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
while ((i = getopt(argc, argv, "v")) != -1) {
|
|
Packit |
6c0a39 |
switch(i) {
|
|
Packit |
6c0a39 |
case 'v':
|
|
Packit |
6c0a39 |
verbosity++;
|
|
Packit |
6c0a39 |
break;
|
|
Packit |
6c0a39 |
default:
|
|
Packit |
6c0a39 |
fprintf(stderr, "unknown option %c\n", optopt);
|
|
Packit |
6c0a39 |
usage(argv[0]);
|
|
Packit |
6c0a39 |
return -1;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
destination = argv[optind];
|
|
Packit |
6c0a39 |
if (destination == NULL) {
|
|
Packit |
6c0a39 |
usage(argv[0]);
|
|
Packit |
6c0a39 |
return -1;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
return 0;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
int main(int argc, char **argv) {
|
|
Packit |
6c0a39 |
ssh_session session;
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
if (opts(argc, argv) < 0) {
|
|
Packit |
6c0a39 |
return EXIT_FAILURE;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
session = connect_ssh(destination, NULL, verbosity);
|
|
Packit |
6c0a39 |
if (session == NULL) {
|
|
Packit |
6c0a39 |
return EXIT_FAILURE;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
do_sftp(session);
|
|
Packit |
6c0a39 |
ssh_disconnect(session);
|
|
Packit |
6c0a39 |
ssh_free(session);
|
|
Packit |
6c0a39 |
return 0;
|
|
Packit |
6c0a39 |
}
|
|
Packit |
6c0a39 |
|
|
Packit |
6c0a39 |
#endif
|