Link to home
Start Free TrialLog in
Avatar of itnifl
itniflFlag for Norway

asked on

Need bundled ATFTP tool for use with ESXi

VMWare OVF tool is bundled so that if I install it on a ESXi, it finds its libraries in the local folder. I would like a atftp tool that is bundled in the same way so I can install and use it on a ESXi server. If I install atftp in for instance Ubuntu and copy it over to the ESXi, then I get the error:
atftp: error while loading shared libraries: libreadline.so.6: cannot open shared object file: No such file or directory

Tried to copy in the missing file, but that doesn't change anything.
ASKER CERTIFIED SOLUTION
Avatar of Andrew Hancock (VMware vExpert PRO / EE Fellow/British Beekeeper)
Andrew Hancock (VMware vExpert PRO / EE Fellow/British Beekeeper)
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of itnifl

ASKER

Those explain how to create modules that are used as divers that are loaded by vmkload_mod. I want a executeable binary. I will try for this guide:
http://www.virtuallyghetto.com/2011/02/how-to-compile-statically-linked-rsync.html

Centos 3 is oudated, and yum does not work any more when using that tool inside Centos 3. So I will take my chances with Centos 6.7 - 32 bit. The guy in the article also used 32 bit when he used Centos 3.
Avatar of itnifl

ASKER

I used the guide in the link that I pasted in my last reply and compiled this tftp client in Centos 6.7:
https://github.com/lanrat/tftp

It works fine on ESXi when it is compiled as statitically linked:
make CFLAGS="-static" EXEEXT="-static"

Just make sure the firewall on the ESXi is disabled:
esxcli network firewall set --enabled no

I wouldn't think it would be a problem, but it was. Maybe because I enabled it this way some time?
esxcli network firewall set --default-action false --enabled yes

The code that lanrat at github has for his tftp client uses a constant for the host address to connect to. This means you will have to change the constant and recompile the code to use it with another server. This is too cumbersome for any later on IT staff member to handle, so I rewrote the tftpclient.c source file. It is not perfect, but now I can pass in a argument to the compiled program that overrides the defined constant if I feel like it.

#include "tftp.h"

//returns a struct for the server information
//Original code from https://github.com/lanrat/tftp - thank you lanrat!
//Function is rewritten to avoid use of hard coded hostnames or addresses
struct sockaddr_in getServerStruct(char *host, int port)
{
  struct sockaddr_in serv_addr;

  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;

  serv_addr.sin_addr.s_addr = inet_addr(host);
  serv_addr.sin_port = htons(port);

  return serv_addr;
}


//called when we retrieve a file from the server
//Original code from https://github.com/lanrat/tftp - thank you lanrat!
//Function is slightly rewritten to avoid use of hard coded hostnames or addresses
void getFile(char *host, int port, char *filename)
{
  int sockfd;
  struct sockaddr_in serv_addr;
  FILE * file;

  if (strchr(filename,'/') != NULL )
  {
    printf("We do not support file transfer out of the current working directory\n");
    return;
  }

  file = fopen(filename, "wb");

  if(file == NULL)
  {
    perror(filename);
    return;
  }

  sockfd = createUDPSocketAndBind(0);
  serv_addr = getServerStruct(host, port);

  if(sockfd < 0)
  {
    printf("Couldn't open socket\n");
    return;
  }

  if(!send_RRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
  {
    printf("Error: couldn't send RRQ\n");
    return;
  }
  if(!recvFile(sockfd, (struct sockaddr *) &serv_addr, file,filename))
  {
    printf("Error: didn't receive file\n");
    return;
  }
  fclose(file);
  return;
}


//used to upload files to the server
//Original code from https://github.com/lanrat/tftp - thank you lanrat!
//Function is slightly rewritten to avoid use of hard coded hostnames or addresses.
void putFile(char *host, int port, char *filename)
{
  int sockfd;
  struct sockaddr_in serv_addr;
  PACKET packet;
  int result;
  FILE * fileh;
  int timeout_counter = 0;
  
  if (strchr(filename,'/') != NULL )
  {
    printf("We do not support file transfer out of the current working directory\n");
    return;
  }

  
  fileh = fopen(filename, "rb");

  if(fileh == NULL)
  {
    perror(filename);
    return;
  }

  sockfd = createUDPSocketAndBind(0);
  serv_addr = getServerStruct(host, port);

  if(sockfd < 0)
  {
    printf("Couldn't open socket\n");
    return;
  }

  if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
  {
    printf("Error: couldn't send WRQ to server\n");
    return;
  }
  while (timeout_counter < MAX_TFTP_TIMEOUTS)
  {
    result = waitForPacket(sockfd, (struct sockaddr *) &serv_addr, TFTP_OPTCODE_ACK, &packet);
    if (result < 0)
    {
      printf("Error: Timeout sending packet to server\n");
      if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
      {
        printf("Error: couldn't send WRQ to server\n");
        return;
      }
      timeout_counter++;
    }else
    {
      break;
    }
  }
  if (result < 0)
  {
    //we still timed out
    printf("Timed out after %d tries, is the server running\n",MAX_TFTP_TIMEOUTS);
    fclose(fileh);
    return;
  }
  if (packet.optcode == TFTP_OPTCODE_ERR)
  {
    //we recieved an error, print it
    printError(&packet);
  }else
  {
    if (!sendFile(sockfd, (struct sockaddr *) &serv_addr, fileh))
    {
      printf("Unable to send file to server\n");
    }
  }
  fclose(fileh);
  return;
}


//main client, checks for args and starts an operation if no errors detected
//Original code from https://github.com/lanrat/tftp - thank you lanrat!
//Function is rewritten to avoid use of hard coded hostnames or addresses.
int main(int argc, char *argv[])
{
  int port = SERV_UDP_PORT;
  char *host = SERV_HOST_ADDR;
  bool writeFile = false;
  bool readFile = false;
  int argOffset = 1;
  char* filename;
  int x = 1;

  while (x < argc) {	  
	  if (argv[x][0] == '-') {
		  //printf("Entered at Checking: %c\n", argv[x][1]);
		  //printf("Variable is: %s\n", argv[x + 1]);
		  switch (argv[x][1]) {
		  case 'p':
			  port = atoi(argv[x + 1]);
			  break;
		  case 'h':
			  host = argv[x + 1];
			  break;
		  case 'w':
			  writeFile = true;
			  filename = argv[x + 1];
			  break;
		  case 'r':
			  readFile = true;
			  filename = argv[x + 1];
			  break;
		  default:
			  break;
		  }
	  }	  
	  x++;
  }
  //printf("After loop\n");
  //printf("Host: %s\n", host);
  //printf("Port: %i\n", port);
  //printf("Filename: %s\n", filename);
  if (writeFile == true) {
	  putFile(host, port, filename);
  }
  if (readFile == true) {
	  getFile(host, port, filename);
  }
  if (writeFile == false && readFile == false) {
	  printf("Usage: %s [-h host] [-p port]  (-w putfile || -r getFile)\n", argv[0]);	  
  }
}

Open in new window


Now I can use this client in a kickstart script at a ESXi installation to automatically fetch the setup of the ESXi host from a tftp server.
Avatar of itnifl

ASKER

Your (Andrew Hancock) reply was a inspiration to the solution. I don't remember how I found the first link, but it somehow led to it via the links you posted.