C


C/C++: Get the size of a file in bytes

The following function accepts the name of a file as a string and returns the size of the file in bytes. If for any reason it cannot get the file information, it will return the value -1.

[download id=”2417″]

In our header file, we used the following pre-processor directives around our declarations

#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

to allow c++ code to call our c function.

The usage example code makes three tests:

  1. Getting the size of the currently executing binary, as it will have a non-zero size
  2. Getting the size of a non-existing file, to check that it will properly return -1
  3. Getting the size of an empty file, to be sure it is empty we create it right before the test

[download id=”2417″]

Source file (file_helpers.c)

#include <sys/stat.h>
#include "file_helpers.h"

//It will return the size of the file in bytes OR -1 in case that it cannot get any status information for it
off_t get_file_size(const char *filename) {
  //Specialised struct that can hold status attributes of files.
  struct stat st;

  //Gets file attributes for filename and puts them in the stat buffer.
  // Upon successful completion, it returns 0, otherwise and errno will be set to indicate the error.
  if (stat(filename, &st) == 0) {
    //Size of file, in bytes.
    return st.st_size;
  }

  return -1;
}

Header file (file_helpers.h)


#ifndef GM_S_LITTLE_HELPERS_FILE_HELPERS_H
#define GM_S_LITTLE_HELPERS_FILE_HELPERS_H

#ifdef __cplusplus
extern "C" {
#endif

off_t get_file_size(const char *filename);

#ifdef __cplusplus
}
#endif

#endif //GM_S_LITTLE_HELPERS_FILE_HELPERS_H

Usage example (main.cpp)

#include <iostream>
#include "file_helpers.h"

void print_file_size(const char *filename) {
  const off_t size_of_file = get_file_size(filename);
  if (size_of_file > 0) {
    printf("The size of '%s' is %zd bytes\n", filename, size_of_file);
  }
  else if (size_of_file == 0) {
    printf("The file '%s' is empty\n", filename);
  }
  else {
    printf("Could not get the status information for file '%s'\n", filename);
  }
}

int main(int argc, char *argv[]) {

  //Testing a non-zero sized file
  print_file_size(argv[0]);
  //Testing for a non-existing file
  print_file_size("some file that does not exist...");
  const char * filename = "/tmp/some_empty_file";
  //Creating an empty file
  FILE * fout = fopen(filename, "w");
  fclose(fout);
  //Testing for an empty file
  print_file_size(filename);

  return 0;
}

[download id=”2417″]


C/C++: Perform safe sprintf 1

The following function accepts the address of a char * buffer, the formatting string for printf along with all the parameters needed to fill the formatting string and updates the location of the buffer to point at the final formatted string.

[download id=”2418″]

This code does not require the user to perform malloc before filling in the buffer. Using vsnprintf (variation of snprintf for variable arguments) it will automatically find the correct size that the buffer should have, allocate the space, switch the pointer of the buffer and prepare the final string using the formatting arguments.

In our header file, we used the following pre-processor directives around our declarations

#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

to allow c++ code to call our function.

[download id=”2418″]

Source file (string_helpers.c)


#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "string_helpers.h"

int safe_sprintf(char ** buffer, const char *format, ...) {

  va_list arguments;
  //The va_start(va_list arguments, last) macro initializes and must be called first.
  //The argument last is the name of the last argument before the variable argument list, that is, the last argument of which the calling function knows the type.
  va_start (arguments, format);

  //Upon successful return, vsnprintf returns the number of characters printed (excluding the null byte used to end output to strings).
  //For that reason we add one at the end of the length.
  const int length = vsnprintf(NULL, 0, format, arguments) + 1;

  //Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function.
  // After the call va_end(arguments) the variable arguments is undefined.
  // Multiple traversals of the list, each bracketed by va_start() and va_end() are possible. va_end() may be a macro or a function.
  va_end (arguments);

  if (*buffer) {
    free(*buffer);
  }
  if (!(*buffer = malloc(length * sizeof(char)))) {
    return EXIT_FAILURE;
  }

  va_start(arguments, format);
  vsnprintf(*buffer, (size_t) length, format, arguments);
  va_end (arguments);

  return EXIT_SUCCESS;
}

Header file (string_helpers.h)


#ifndef GM_S_LITTLE_HELPERS_STRING_HELPERS_H
#define GM_S_LITTLE_HELPERS_STRING_HELPERS_H

#ifdef __cplusplus
extern "C" {
#endif

int safe_sprintf(char ** buffer, const char *format, ...);

#ifdef __cplusplus
}
#endif

#endif //GM_S_LITTLE_HELPERS_STRING_HELPERS_H

Usage example (main.cpp)


#include <iostream>
#include "string_helpers.h"

int main() {

  char * buffer;
  safe_sprintf(&buffer, "Hello, World!\nFrom Line %d in function %s of the file %s.", __LINE__, __func__, __FILE__);
  printf("%s", buffer);
  return 0;
}

[download id=”2418″]


C/C++: Set Affinity to process thread – Example Code 3

The following code sets the affinity of the process thread to a specific CPU core.
In this example, we define the CPU core id using the variable core_id.

Full source code available here [download id=”2363″]


#include <stdio.h>
#include <stdlib.h>
#define __USE_GNU
#include <sched.h>
#include <errno.h>
#include <unistd.h>

// The <errno.h> header file defines the integer variable errno, which is set by system calls and some library functions in the event of an error to indicate what went wrong.
#define print_error_then_terminate(en, msg) \
  do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)


int main(int argc, char *argv[]) {

  // We want to camp on the 2nd CPU. The ID of that core is #1.
  const int core_id = 1;
  const pid_t pid = getpid();

  // cpu_set_t: This data set is a bitset where each bit represents a CPU.
  cpu_set_t cpuset;
  // CPU_ZERO: This macro initializes the CPU set set to be the empty set.
  CPU_ZERO(&cpuset);
  // CPU_SET: This macro adds cpu to the CPU set set.
  CPU_SET(core_id, &cpuset);

  // sched_setaffinity: This function installs the cpusetsize bytes long affinity mask pointed to by cpuset for the process or thread with the ID pid. If successful the function returns zero and the scheduler will in future take the affinity information into account. 
  const int set_result = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset);
  if (set_result != 0) {

    print_error_then_terminate(set_result, "sched_setaffinity");
  }

  // Check what is the actual affinity mask that was assigned to the thread.
  // sched_getaffinity: This functions stores the CPU affinity mask for the process or thread with the ID pid in the cpusetsize bytes long bitmap pointed to by cpuset. If successful, the function always initializes all bits in the cpu_set_t object and returns zero.
  const int get_affinity = sched_getaffinity(pid, sizeof(cpu_set_t), &cpuset);
  if (get_affinity != 0) {

    print_error_then_terminate(get_affinity, "sched_getaffinity");
  }

  // CPU_ISSET: This macro returns a nonzero value (true) if cpu is a member of the CPU set set, and zero (false) otherwise. 
  if (CPU_ISSET(core_id, &cpuset)) {

    fprintf(stdout, "Successfully set thread %d to affinity to CPU %d\n", pid, core_id);
  } else {

    fprintf(stderr, "Failed to set thread %d to affinity to CPU %d\n", pid, core_id);
  }

  return 0;
}

To compile we used the following command

gcc -Wall affinity.c -o affinity;

Full source code available here [download id=”2363″]

For a full pthread example please visit this link.


Fedora 24: Solution to gcrypt.h: No such file or directory

Recently we tried to compile cisco-decrypt.c* on Fedora 24 (64bit).
We got the full source code from the website of Maurice Massar.
Download full source code here: [download id=”2078″]

We needed this tool to configure the Gnome 3 native network client to connect to a specific Cisco VPN network.
During the configuration we setup a “Cisco Compatible VPN (vpnc)” VPN.

* Please note that this tool is NOT a hacking nor cracking tool. In order for you to make any use of it, you need to have a valid PCF file given to you by your system administrator. It is only useful when you need to get the group password to configure a system that does not accept the PCF file with the encrypted password.

To compile the code you can use one of the following two methods:

Compilation method 1

gcc -Wall -o cisco-decrypt cisco-decrypt.c $(libgcrypt-config --libs --cflags)

If the package libgcrypt-devel is not installed you will get a prompt message as follows, which will instruct you to install the missing package.
You need to type y to both questions so that the installation will proceed. Once the installation is done, execute once more the compilation command.

As you can see below, you might get a whole bunch of errors, ignore them and try to compile once more. It seems to be a bug that will not affect the end result (at least in this scenario).

gcc -Wall -o cisco-decrypt cisco-decrypt.c $(libgcrypt-config --libs --cflags)
bash: libgcrypt-config: command not found...
Install package 'libgcrypt-devel' to provide command 'libgcrypt-config'? [N/y] y

Proceed with changes? [N/y] y

gcc: error: Waiting: No such file or directory
gcc: error: in: No such file or directory
gcc: error: queue...: No such file or directory
gcc: error: Loading: No such file or directory
gcc: error: list: No such file or directory
gcc: error: of: No such file or directory
gcc: error: packages....: No such file or directory
gcc: error: The: No such file or directory
gcc: error: following: No such file or directory
gcc: error: packages: No such file or directory
gcc: error: have: No such file or directory
gcc: error: to: No such file or directory
gcc: error: be: No such file or directory
gcc: error: installed:: No such file or directory
gcc: error: libgcrypt-devel-1.6.6-1.fc24.x86_64: No such file or directory
gcc: error: Development: No such file or directory
gcc: error: files: No such file or directory
gcc: error: for: No such file or directory
gcc: error: the: No such file or directory
gcc: error: libgcrypt: No such file or directory
gcc: error: package: No such file or directory
gcc: error: libgpg-error-devel-1.24-1.fc24.x86_64: No such file or directory
gcc: error: Development: No such file or directory
gcc: error: files: No such file or directory
gcc: error: for: No such file or directory
gcc: error: the: No such file or directory
gcc: error: libgpg-error: No such file or directory
gcc: error: package: No such file or directory
gcc: error: Waiting: No such file or directory
gcc: error: in: No such file or directory
gcc: error: queue...: No such file or directory
gcc: error: Waiting: No such file or directory
gcc: error: for: No such file or directory
gcc: error: authentication...: No such file or directory
gcc: error: Waiting: No such file or directory
gcc: error: in: No such file or directory
gcc: error: queue...: No such file or directory
gcc: error: Downloading: No such file or directory
gcc: error: packages...: No such file or directory
gcc: error: Requesting: No such file or directory
gcc: error: data...: No such file or directory
gcc: error: Testing: No such file or directory
gcc: error: changes...: No such file or directory
gcc: error: Installing: No such file or directory
gcc: error: packages...: No such file or directory

Compilation method 2

In case the above method does not work for you for some reason, you can try the following.

gcc -Wall -o cisco-decrypt cisco-decrypt.c -lgcrypt

If the package libgcrypt-devel is not installed you will get an error as follows.

gcc -Wall -o cisco-decrypt cisco-decrypt.c -lgcrypt
cisco-decrypt.c:30:20: fatal error: gcrypt.h: No such file or directory
 #include <gcrypt.h>
                    ^
compilation terminated.

In this case use

sudo dnf install libgcrypt-devel

to install the missing library and try again to compile.

To use

Open your PCF file with a text editor. Find the line that starts with enc_GroupPwd= and copy the characters after that.

Paste the characters as the first command line argument to the newly compiled application. The password will be the line returned right after.


./cisco-decrypt 886E2FC74BFCD8B6FAF47784C386A50D0C1A5D0528D1E682B7EBAB6B2E91E792E389914767193F9114FA26C1E192034754F85FC97ED36509
Th!sIsMyK3y#

Other notes

In the case you get these errors:

/tmp/ccHrH1kZ.o: In function `c_decrypt':
cisco-decrypt.c:(.text+0x243): undefined reference to `gcry_md_hash_buffer'
cisco-decrypt.c:(.text+0x267): undefined reference to `gcry_md_hash_buffer'
cisco-decrypt.c:(.text+0x2b4): undefined reference to `gcry_md_hash_buffer'
cisco-decrypt.c:(.text+0x31d): undefined reference to `gcry_cipher_open'
cisco-decrypt.c:(.text+0x33b): undefined reference to `gcry_cipher_setkey'
cisco-decrypt.c:(.text+0x356): undefined reference to `gcry_cipher_setiv'
cisco-decrypt.c:(.text+0x382): undefined reference to `gcry_cipher_decrypt'
cisco-decrypt.c:(.text+0x391): undefined reference to `gcry_cipher_close'
/tmp/ccHrH1kZ.o: In function `main':
cisco-decrypt.c:(.text+0x41e): undefined reference to `gcry_check_version'
collect2: error: ld returned 1 exit status

It most probably means that you did not add on your compilation command one of the following two parameters

  1. $(libgcrypt-config –libs –cflags)
  2. -lgcrypt

You need one of these two options to be on the command line to compile.