Getting undefined references for C functions while making ESP8266 project - c

I followed this tutorial for installing a Kaa application into an ESP8266, and it worked after a few modifications: https://kaaproject.github.io/kaa/docs/v0.10.0/Programming-guide/Using-Kaa-endpoint-SDKs/C/SDK-ESP8266/
One of the modifications I had to make was to move a line of code in eagle.app.v6.ld because of byte overflow (arrow points to change I made):
...
.irom0.text : ALIGN(4)
{
_irom0_text_start = ABSOLUTE(.);
*(.literal.* .text.*) --> moved from ".text : ALIGN(4){...}"
...
}
...
After I did this I still had some byte overflow, so I modified the original cmake command from the documentation to disable cmake extensions that were taking up space:
cmake \
-DCMAKE_TOOLCHAIN_FILE=../kaa/toolchains/esp8266.cmake \
-DKAA_PLATFORM=esp8266 \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DWITH_EXTENSION_CONFIGURATION=OFF \
-DWITH_EXTENSION_EVENT=OFF \
-DWITH_EXTENSION_LOGGING=OFF \
-DWITH_EXTENSION_NOTIFICATION=OFF \
-DWITH_EXTENSION_USER=OFF \
-DWITH_ENCRYPTION=OFF \
-DKAA_MAX_LOG_LEVEL=3 ..
Finally, when I ran the make command. it worked. I then created and flashed the binaries into my ESP. Then I reset my ESP with GPIO0 high (so it can boot from flash) and the ESP sent "Hello, Kaa!" into the serial port I was connected to.
Now, however. I am trying to make it so that my ESP8266 connects to my Kaa server and generates an Endpoint Profile, so I need the code to create a transport channel to communicate to both the Bootstrap server and Operations server.
To do this, I tried using the code from Your First Kaa Application that generates fake temp readings and receives the configuration schema and pushes data to my Cassandra server via log appender:
https://kaaproject.github.io/kaa/docs/v0.10.0/Programming-guide/Your-first-Kaa-application/
So in my attempt to do this, I left my directory the same:
CMakeLists.txt
driver/
uart.h
uart.c
ld/
eagle.app.v6.ld
eagle.rom.addr.v6.ld
kaa/
<put Kaa SDK here> --> replaced with new SDK with log and configuration schema
user/
user_main.c
src/
kaa_demo.c --> replaced with new code from "Your First Kaa Application"
I then replaced this code into my kaa_demo.c file:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <kaa/kaa.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/kaa_error.h>
#include <extensions/configuration/kaa_configuration_manager.h>
#include <extensions/logging/kaa_logging.h>
#include <kaa/gen/kaa_logging_gen.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/utilities/kaa_log.h>
#include <kaa/platform-impl/common/ext_log_upload_strategies.h>
static int32_t sample_period;
static time_t last_sample_time;
extern kaa_error_t ext_unlimited_log_storage_create(void **log_storage_context_p, kaa_logger_t *logger);
/* Retrieves current temperature. */
static int32_t get_temperature_sample(void)
{
/* For the sake of example, random data is used */
return rand() % 10 + 25;
}
/* Periodically called by Kaa SDK. */
static void example_callback(void *context)
{
time_t current_time = time(NULL);
/* Respect sample period */
if (difftime(current_time, last_sample_time) >= sample_period) {
int32_t temperature = get_temperature_sample();
printf("Sampled temperature: %i\n", temperature);
last_sample_time = current_time;
kaa_user_log_record_t *log_record = kaa_logging_data_collection_create();
log_record->temperature = temperature;
kaa_logging_add_record(kaa_client_get_context(context)->log_collector, log_record, NULL);
}
}
/* Receives new configuration data. */
static kaa_error_t on_configuration_updated(void *context, const kaa_root_configuration_t *conf)
{
(void) context;
printf("Received configuration data. New sample period: %i seconds\n", conf->sample_period);
sample_period = conf->sample_period;
return KAA_ERR_NONE;
}
int main(void)
{
/* Init random generator used to generate temperature */
srand(time(NULL));
/* Prepare Kaa client. */
kaa_client_t *kaa_client = NULL;
kaa_error_t error = kaa_client_create(&kaa_client, NULL);
if (error) {
return EXIT_FAILURE;
}
/* Configure notification manager. */
kaa_configuration_root_receiver_t receiver = {
.context = NULL,
.on_configuration_updated = on_configuration_updated
};
error = kaa_configuration_manager_set_root_receiver(
kaa_client_get_context(kaa_client)->configuration_manager,
&receiver);
if (error) {
return EXIT_FAILURE;
}
/* Obtain default configuration shipped within SDK. */
const kaa_root_configuration_t *dflt = kaa_configuration_manager_get_configuration(
kaa_client_get_context(kaa_client)->configuration_manager);
printf("Default sample period: %i seconds\n", dflt->sample_period);
sample_period = dflt->sample_period;
/* Configure data collection. */
void *log_storage_context = NULL;
void *log_upload_strategy_context = NULL;
/* The internal memory log storage distributed with Kaa SDK. */
error = ext_unlimited_log_storage_create(&log_storage_context,
kaa_client_get_context(kaa_client)->logger);
if (error) {
return EXIT_FAILURE;
}
/* Create a strategy based on timeout. */
error = ext_log_upload_strategy_create(
kaa_client_get_context(kaa_client), &log_upload_strategy_context,
KAA_LOG_UPLOAD_BY_TIMEOUT_STRATEGY);
if (error) {
return EXIT_FAILURE;
}
/* Strategy will upload logs every 5 seconds. */
error = ext_log_upload_strategy_set_upload_timeout(log_upload_strategy_context, 5);
if (error) {
return EXIT_FAILURE;
}
/* Specify log bucket size constraints. */
kaa_log_bucket_constraints_t bucket_sizes = {
.max_bucket_size = 32, /* Bucket size in bytes. */
.max_bucket_log_count = 2, /* Maximum log count in one bucket. */
};
/* Initialize the log storage and strategy (by default, they are not set). */
error = kaa_logging_init(kaa_client_get_context(kaa_client)->log_collector,
log_storage_context, log_upload_strategy_context, &bucket_sizes);
if (error) {
return EXIT_FAILURE;
}
/* Start Kaa SDK's main loop. example_callback is called once per second. */
error = kaa_client_start(kaa_client, example_callback, kaa_client, 1);
/* Should get here only after Kaa stops. */
kaa_client_destroy(kaa_client);
if (error) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I left the CMakeLists.txt file the same:
cmake_minimum_required(VERSION 3.0.2)
project(kaa_demo C)
# Add Kaa SDK directory
add_subdirectory(kaa)
# Add source files
add_library(kaa_demo_s STATIC user/user_main.c driver/uart.c src/kaa_demo.c)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
if(NOT DEFINED ESP_RTOS_SDK)
set(ESP_RTOS_SDK /opt/Espressif/esp-rtos-sdk)
endif()
# specify include directories
target_include_directories(kaa_demo_s PUBLIC driver)
target_include_directories(kaa_demo_s PUBLIC .)
target_include_directories(kaa_demo_s PUBLIC
${ESP_RTOS_SDK}/extra_include
${ESP_RTOS_SDK}/include
${ESP_RTOS_SDK}/include/lwip
${ESP_RTOS_SDK}/include/lwip/ipv4
${ESP_RTOS_SDK}/include/lwip/ipv6
${ESP_RTOS_SDK}/include/espressif/
)
exec_program(xtensa-lx106-elf-gcc .
ARGS -print-libgcc-file-name
OUTPUT_VARIABLE ESP8266_LIBGCC
)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/ld)
target_link_libraries(kaa_demo_s PUBLIC
kaac
${ESP_RTOS_SDK}/lib/libfreertos.a
${ESP_RTOS_SDK}/lib/libhal.a
${ESP_RTOS_SDK}/lib/libpp.a
${ESP_RTOS_SDK}/lib/libphy.a
${ESP_RTOS_SDK}/lib/libnet80211.a
${ESP_RTOS_SDK}/lib/libwpa.a
${ESP_RTOS_SDK}/lib/liblwip.a
${ESP_RTOS_SDK}/lib/libmain.a
${ESP_RTOS_SDK}/lib/libssl.a
${ESP_RTOS_SDK}/lib/libhal.a
${ESP8266_LIBGCC}
-Teagle.app.v6.ld
)
file(WRITE ${CMAKE_BINARY_DIR}/blank.c "")
add_executable(kaa_demo ${CMAKE_BINARY_DIR}/blank.c)
target_link_libraries(kaa_demo kaa_demo_s)
I left the user_main.c file the same:
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "uart.h"
extern int main(void);
static void main_task(void *pvParameters)
{
(void)pvParameters;
main();
for (;;);
}
void user_init(void)
{
uart_init_new();
UART_SetBaudrate(UART0, 115200);
UART_SetPrintPort(UART0);
portBASE_TYPE error = xTaskCreate(main_task, "main_task", 512, NULL, 2, NULL );
if (error < 0) {
printf("Error creating main_task! Error code: %ld\r\n", error);
}
}
I left eagle.app.v6.ld (except for the modification described in the beginning) and eagle.rom.addr.ld, uart.h, and uart.c the same (obtained from github)
So when I change to the build directory and run this cmake command:
cmake \
-DCMAKE_TOOLCHAIN_FILE=../kaa/toolchains/esp8266.cmake \
-DKAA_PLATFORM=esp8266 \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DWITH_EXTENSION_CONFIGURATION=OFF \
-DWITH_EXTENSION_EVENT=OFF \
-DWITH_EXTENSION_LOGGING=OFF \
-DWITH_EXTENSION_NOTIFICATION=OFF \
-DWITH_EXTENSION_USER=OFF \
-DWITH_ENCRYPTION=OFF \
-DKAA_MAX_LOG_LEVEL=3 ..
I get this: (esp8266 is my username, kaa-app is the main directory that contains: CMakeLists.txt, build, drivers, etc.)
-- Default SDK location will be used: /opt/Espressif/esp-rtos-sdk
-- Toolchain path: /opt/Espressif/crosstool-NG/builds/xtensa-lx106-elf
-- ESP8266 SDK path: /opt/Espressif/esp-rtos-sdk
==================================
BUILD_TYPE = MinSizeRel
KAA_PLATFORM = esp8266
KAA_MAX_LOG_LEVEL = 3
==================================
BOOTSTRAP ENABLED
PROFILE ENABLED
KAA WILL BE INSTALLED TO /usr/local
-- Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/esp8266/Documents/kaa-app/build
So then I run make, and I get this error:
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.example_callback+0x8): undefined reference to `time'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.example_callback+0xc): undefined reference to `difftime'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.example_callback+0x20): undefined reference to `kaa_logging_add_record'
libkaa_demo_s.a(kaa_demo2.c.obj): In function `example_callback':
kaa_demo2.c:(.text.example_callback+0x35): undefined reference to `time'
kaa_demo2.c:(.text.example_callback+0x42): undefined reference to `difftime'
kaa_demo2.c:(.text.example_callback+0x9e): undefined reference to `kaa_logging_add_record'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x10): undefined reference to `srand'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x14): undefined reference to `kaa_configuration_manager_set_root_receiver'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x18): undefined reference to `kaa_configuration_manager_get_configuration'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x1c): undefined reference to `ext_unlimited_log_storage_create'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x20): undefined reference to `ext_log_upload_strategy_create'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x24): undefined reference to `ext_log_upload_strategy_set_upload_timeout'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x28): undefined reference to `kaa_logging_init'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x3a): undefined reference to `time'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x40): undefined reference to `srand'
libkaa_demo_s.a(kaa_demo2.c.obj): In function `main':
kaa_demo2.c:(.text.startup.main+0x69): undefined reference to `kaa_configuration_manager_set_root_receiver'
kaa_demo2.c:(.text.startup.main+0x7b): undefined reference to `kaa_configuration_manager_get_configuration'
kaa_demo2.c:(.text.startup.main+0xa5): undefined reference to `ext_unlimited_log_storage_create'
kaa_demo2.c:(.text.startup.main+0xb8): undefined reference to `ext_log_upload_strategy_create'
kaa_demo2.c:(.text.startup.main+0xc5): undefined reference to `ext_log_upload_strategy_set_upload_timeout'
kaa_demo2.c:(.text.startup.main+0xe6): undefined reference to `kaa_logging_init'
collect2: error: ld returned 1 exit status
CMakeFiles/kaa_demo.dir/build.make:120: recipe for target 'kaa_demo' failed
make[2]: *** [kaa_demo] Error 1
CMakeFiles/Makefile2:107: recipe for target 'CMakeFiles/kaa_demo.dir/all' failed
make[1]: *** [CMakeFiles/kaa_demo.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2
So it seems that when it tries linking the files it cannot find the new headers I included:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <kaa/kaa.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/kaa_error.h>
#include <extensions/configuration/kaa_configuration_manager.h>
#include <extensions/logging/kaa_logging.h>
#include <kaa/gen/kaa_logging_gen.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/utilities/kaa_log.h>
#include <kaa/platform-impl/common/ext_log_upload_strategies.h>
However, the target directory that is included in CMakeLists.txt contains the header files that I need (for the C headers):
${ESP_RTOS_SDK}/extra_include
So I really do not know what I need to add or modify, I am completely stuck. Any help would be much appreciated! Thanks!

For data_collection you have to set -DWITH_EXTENSION_LOGGING=ON .
For esp8266 you have a different "time.h" library /kaa/src/kaa/platform-impl/esp8266/platform that doesn't support the function time(NULL), but support
kaa_time_t kaa_esp8266_get_time(void);

Related

Raspberry Pi serdev driver never reaches probe function

I want to write a minimal serdev Linux driver on a Raspberry Pi. Therefore I have to enable the kernel option SERIAL_DEV_CTRL_TTYPORT, but I don't know how. I have tried various options, but my Kernel Module never reaches the Probe function...
Here is what I got already:
I tried to enable the option by changing the /boot/cmdline.txt to:
SERIAL_DEV_CTRL_TTYPORT SERIAL_DEV_CTRL_TTYPORT=y SERIAL_DEV_CTRL_TTYPORT=yes root=PARTUUID=8d696e29-02 rootfstype=ext4 fsck.repair=yes rootwait modules-load=dwc2,g_ether
The device tree overlay:
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2835";
fragment#0 {
target = <&uart0>;
status = "okay";
__overlay__ {
my_device {
compatible = "brightlight,echodev";
status = "okay";
};
};
};
};
The Kernel Module:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/serdev.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
/* Meta Information */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Johannes 4 GNU/Linux");
MODULE_DESCRIPTION("A simple serdev example");
/* Declate the probe and remove functions */
static int dt_probe(struct serdev_device *serdev);
static void dt_remove(struct serdev_device *serdev);
static struct of_device_id my_driver_ids[] = {
{
.compatible = "brightlight,echodev",
}, { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_driver_ids);
static struct serdev_device_driver my_driver = {
.probe = dt_probe,
.remove = dt_remove,
.driver = {
.name = "echodev",
.of_match_table = my_driver_ids,
},
};
/**
* #brief This function is called on loading the driver
*/
static int dt_probe(struct serdev_device *serdev) {
printk("my_serdev - Now I am in the probe function!");
return 0;
}
/**
* #brief This function is called on unloading the driver
*/
static void dt_remove(struct serdev_device *serdev) {
printk("my_serdev - Now I am in the remove function\n");
}
module_serdev_device_driver(my_driver);
Do you have any tips?
UPDATE 1:
I checked my Kernel .config file and found out, that CONFIG_SERIAL_DEV_CTRL_TTYPORT is already set and enabled. I double checked it with
pi#raspberrypi:~ $ sudo modprobe configs
pi#raspberrypi:~ $ gzip -d /proc/config.gz --stdout | grep SERIAL_DEV
CONFIG_SERIAL_DEV_BUS=y
CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
But then, why does my module never reaches the probe function???
Best regards,
Johannes
Ok, I got it, but I don't know exactly why it is working know.
When posting this example, I used dtoverlay to load the device tree overlay:
sudo dtoverlay testoverlay.dtbo
When doing so, I couldn't reach the probe function. Then I copied my overlay to /boot/overlays and added it to /boot/config.txt:
dtoverlay=testoverlay
And after a reboot, I inserted my kernel module and it reached the probe function. Does anyone know why this works now but not before?

error function declared but never defined

I have added a library to my c project in codeVision AVR. when I want to use it's functions receive this error:
function 'function name' is declared but never defined.
here is my code:
#include "pid.h"
#include <mega32.h>
PidType _pid;
void main(void)
{
//some uC hardware initializing codes which are removed here to simplify code
PID_Compute(&_pid);
while (1)
{
// Place your code here
}
}
in pid.h:
.
.
bool PID_Compute(PidType* pid);
.
.
and pid.c:
#include "pid.h"
.
.
bool PID_Compute(PidType* pid) {
if (!pid->inAuto) {
return false;
}
FloatType input = pid->myInput;
FloatType error = pid->mySetpoint - input;
pid->ITerm += (pid->ki * error);
if (pid->ITerm > pid->outMax)
pid->ITerm = pid->outMax;
else if (pid->ITerm < pid->outMin)
pid->ITerm = pid->outMin;
FloatType dInput = (input - pid->lastInput);
FloatType output = pid->kp * error + pid->ITerm - pid->kd * dInput;
if (output > pid->outMax)
output = pid->outMax;
else if (output < pid->outMin)
output = pid->outMin;
pid->myOutput = output;
pid->lastInput = input;
return true;
}
the ERROR:
function 'PID_Compute' declared, but never defined.
Where is the problem?
EDIT:
to add the library to my project I placed the .c and .h library files in the same folder that my main project file is:
and then #include "pid.h" in my main file:
#include "pid.h"
#include <mega32.h>
// Declare your global variables here
PidType _pid;
void main(void)
{
.
.
my error and warnings:
EDIT2:
I simplified the code and now can show you the entire code:
main code:
#include "pid.h"
PidType _pid;
void main(void)
{
PID_Compute(&_pid);
while (1)
{
}
}
pid.h:
#ifndef PID_H
#define PID_H
#include <stdbool.h>
typedef struct {
int i;
} PidType;
bool PID_Compute(PidType* pid);
#endif
pid.c:
#include "pid.h"
bool PID_Compute(PidType* pid) {
pid->i = 2;
return true;
}
thank you every body.
As you said, the pid.c was not added to the project.
for those who may face the same problem:
in codeVision AVR we have to add .c file to project from project->configure->files->input files->add
I addec .c file to project and the error went away.
From the screenshot with the tree view of your files it is clear that the file "pid.c" is not part of the project.
Move it into your project. Then it should build without that linker error.
This does not mean the location in the file system. I reference the "virtual" view of the IDE on your project.

How can I get the 'root' boot arg in kernel space?

I am writing a driver and I need to know what disk/partition contains the root filesystem. This can be viewed from userspace using:
cat /proc/cmdline
root=/dev/mmcblk0p1
How can I get the value of root in kernel space?
In order to get the dev_t for the device where your filesystem root is mounted, you can use a strategy similar to what the stat() syscall does. The only exception is that you are not working with __user buffers, so you'll need to use slightly different APIs.
In short, you want to:
Call kern_path() to get a struct path for the path "/".
Call vfs_getattr() passing that path to get a struct kstat.
Check the ->dev member of the struct kstat, which is the root device (dev_t).
If you want, you can also use bdget() to find the block device corresponding to the obtained dev_t, then use bdevname() to get its name (e.g. sda1).
This translates to the following:
struct path root_path;
struct kstat root_stat;
struct block_device *root_device;
char root_device_name[BDEVNAME_SIZE];
kern_path("/", 0, &root_path);
// KERNEL > 4.10
// vfs_getattr(&root_path, &root_stat, STATX_BASIC_STATS, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
// KERNEL <= 4.10
vfs_getattr(&root_path, &root_stat);
pr_info("root device number is 0x%08x; major = %d, minor = %d\n", root_stat.dev, MAJOR(root_stat.dev), MINOR(root_stat.dev));
root_device = bdget(root_stat.dev);
bdevname(root_device, root_device_name);
pr_info("root device name: %s, path: /dev/%s\n", root_device_name, root_device_name);
bdput(root_device);
path_put(&root_path);
Some notes:
I did not do any kind of error checking in the above example, but you most definitely should! See the complete example below.
kern_path() seems to take LOOKUP_* flags defined in linux/namei.h as
second argument, but passing a default value of 0 is also ok.
Likewise, vfs_getattr() takes STATX_* flags defined in linux/stat.h as
third arg. The stat() syscall passes STATX_BASIC_STATS, but passing 0
should be fine too here since we do not need to know anything other
than the device (->dev field), which seems to get populated
regardless of flags. I could not test this though since my kernel is <= 4.10, and these flags are necessary only for kernel > 4.10.
Working example
Here's a complete example of a working kernel module which does the above also applying proper error checking.
// SPDX-License-Identifier: GPL-3.0
#include <linux/kernel.h> // printk(), pr_*()
#include <linux/module.h> // THIS_MODULE, MODULE_VERSION, ...
#include <linux/init.h> // module_{init,exit}
#include <linux/types.h> // dev_t
#include <linux/kdev_t.h> // MAJOR(), MINOR(), MKDEV()
#include <linux/path.h> // struct path
#include <linux/namei.h> // kern_path(), path_put()
#include <linux/stat.h> // struct kstat, STATX_*
#include <linux/fs.h> // vfs_getattr(), struct block_device, bdget(),...
#include <uapi/linux/fcntl.h> // AT_*
#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
static int __init findrootdev_init(void)
{
struct path root_path;
struct kstat root_stat;
struct block_device *root_device;
char root_device_name[BDEVNAME_SIZE];
int err = 0;
pr_info("init\n");
err = kern_path("/", 0, &root_path);
if (err) {
pr_err("kern_path error %d\n", err);
goto kern_path_fail;
}
// KERNEL > 4.10
// err = vfs_getattr(&root_path, &root_stat, STATX_BASIC_STATS,
// AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
// KERNEL <= 4.10
err = vfs_getattr(&root_path, &root_stat);
if (err) {
pr_err("vfs_getattr error %d\n", err);
goto vfs_getattr_fail;
}
pr_info("root device number is 0x%08x; major = %d, minor = %d\n",
root_stat.dev, MAJOR(root_stat.dev), MINOR(root_stat.dev));
root_device = bdget(root_stat.dev);
if (!root_device) {
pr_err("bdget failed\n");
err = -1;
goto bdget_fail;
}
if (!bdevname(root_device, root_device_name)) {
pr_err("bdevname failed\n");
err = -1;
goto bdevname_fail;
}
pr_info("root device name: %s, path: /dev/%s\n",
root_device_name, root_device_name);
bdevname_fail:
bdput(root_device);
bdget_fail:
vfs_getattr_fail:
path_put(&root_path);
kern_path_fail:
return err;
}
static void __exit findrootdev_exit(void)
{
// This function is only needed to be able to unload the module.
pr_info("exit\n");
}
module_init(findrootdev_init);
module_exit(findrootdev_exit);
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Silly test module to find the root device and its name.");
MODULE_AUTHOR("Marco Bonelli");
MODULE_LICENSE("GPL");
Compiling and loading the above module with insmod generates this output in dmesg:
[12664.685699] findrootdev: init
[12664.685703] findrootdev: root device number is 0x00800003; major = 8, minor = 3
[12664.685706] findrootdev: root device name: sda3, path: /dev/sda3
[12671.671038] findrootdev: exit

Calling OpenSSL's PEM_write_PUBKEY || PEM_write_PrivateKey API makes the program to exit abruptly with message "no OPENSSL_Applink"

I am trying to use EVP_* APIs from OpenSSL, but I have encountered a weird strange behavior when trying to dump the Public/Private key from the EVP_PKEY struct.
Issue:: After populating the EVP_PKEY struct, on calling PEM_write_PUBKEY API (see TRIAL1), the program exits. The same happens on calling of PEM_write_PrivateKey API (see TRIAL2).
Output: I am left with a temp.pem 0 bytes file and a message on cmd prompt saying OPENSSL_Uplink(5D8C7000,08): no OPENSSL_Applink
#define TRIAL1
void InitOpenSSLLib(void)
{
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
}
int main(int argc, char** argv)
{
EVP_PKEY_CTX* ctx = NULL;
EVP_PKEY* pKeyPair = EVP_PKEY_new();
BIO *mem = BIO_new(BIO_s_mem());
FILE* fp = fopen("temp.pem", "wb");
InitOpenSSLLib();
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, 0);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048);
EVP_PKEY_keygen(ctx, &pKeyPair);
// Succeeds till here... all of the above called APIs return value greater than 0
#ifdef TRIAL1
// Program exits even before printing any error
if (PEM_write_PUBKEY(fp, pKeyPair) <= 0)
printf("PEM_write_PUBKEY failed\n");
#elif TRIAL2
// same behavior with this API too
PEM_write_PrivateKey(fp, pKeyPair, NULL, NULL, 0, 0, NULL);
#endif
// Tried this too.... but the control never reaches here
fflush(fp);
// Tried this too... most of the mem struct members are NULL.
EVP_PKEY_print_private(mem, pKeyPair, 0, 0);
//.... Cleanup codes
fclose(fp);
BIO_free_all(mem);
return 0;
}
Any pointers? Am I doing anything wrong here? Is there any other way to dump private/public key or the pair PEM format to a file?
I am using VC++ 2015. Also, on hitting Ctrl+F5, the prompt shows the message:: OPENSSL_Uplink(5D8C7000,08): no OPENSSL_Applink
Answering my own question for future devs
The key question here is the error (read, message) thrown by OpenSSL, i.e., no OPENSSL_Applink.
As documented here,
As per 0.9.8 the above limitation is eliminated for .DLLs. OpenSSL
.DLLs compiled with some specific run-time option [we insist on the
default /MD] can be deployed with application compiled with different
option or even different compiler. But there is a catch! Instead of
re-compiling OpenSSL toolkit, as you would have to with prior
versions, you have to compile small C snippet with compiler and/or
options of your choice. The snippet gets installed as
/include/openssl/applink.c and should be either added to
your application project or simply #include-d in one [and only one] of
your application source files. Failure to link this shim module into
your application manifests itself as fatal "no OPENSSL_Applink"
run-time error. An explicit reminder is due that in this situation
[mixing compiler options] it is as important to add CRYPTO_malloc_init
prior first call to OpenSSL.
you should check your compiling options for /MD (assuming you know the Code Generation options under VC++ Project Properties).
I did the same, but still my issue didn't get resolved. The answer to this is the second paragraph to the link given [https://www.openssl.org/docs/faq.html#PROG2], where it instructs us to include <install-root>/include/openssl/applink.c
Where to get this applink.c file if not found in openssl's
dir?
In my case, I installed OpenSSL using exe binary and I couldn't find this specific applink.c file anywhere in my <install-root>, so I started looking and found it here on GitHub.
All you have to do is, include this file as source file in your project or better save it in openssl install-root dir, so that you can include it from the same location for other projects too.
// applink.c from https://github.com/openssl/openssl/blob/master/ms/applink.c
/*
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#define APPLINK_STDIN 1
#define APPLINK_STDOUT 2
#define APPLINK_STDERR 3
#define APPLINK_FPRINTF 4
#define APPLINK_FGETS 5
#define APPLINK_FREAD 6
#define APPLINK_FWRITE 7
#define APPLINK_FSETMOD 8
#define APPLINK_FEOF 9
#define APPLINK_FCLOSE 10 /* should not be used */
#define APPLINK_FOPEN 11 /* solely for completeness */
#define APPLINK_FSEEK 12
#define APPLINK_FTELL 13
#define APPLINK_FFLUSH 14
#define APPLINK_FERROR 15
#define APPLINK_CLEARERR 16
#define APPLINK_FILENO 17 /* to be used with below */
#define APPLINK_OPEN 18 /* formally can't be used, as flags can vary */
#define APPLINK_READ 19
#define APPLINK_WRITE 20
#define APPLINK_LSEEK 21
#define APPLINK_CLOSE 22
#define APPLINK_MAX 22 /* always same as last macro */
#ifndef APPMACROS_ONLY
# include <stdio.h>
# include <io.h>
# include <fcntl.h>
static void *app_stdin(void)
{
return stdin;
}
static void *app_stdout(void)
{
return stdout;
}
static void *app_stderr(void)
{
return stderr;
}
static int app_feof(FILE *fp)
{
return feof(fp);
}
static int app_ferror(FILE *fp)
{
return ferror(fp);
}
static void app_clearerr(FILE *fp)
{
clearerr(fp);
}
static int app_fileno(FILE *fp)
{
return _fileno(fp);
}
static int app_fsetmod(FILE *fp, char mod)
{
return _setmode(_fileno(fp), mod == 'b' ? _O_BINARY : _O_TEXT);
}
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport)
void **
# if defined(__BORLANDC__)
/*
* __stdcall appears to be the only way to get the name
* decoration right with Borland C. Otherwise it works
* purely incidentally, as we pass no parameters.
*/
__stdcall
# else
__cdecl
# endif
OPENSSL_Applink(void)
{
static int once = 1;
static void *OPENSSL_ApplinkTable[APPLINK_MAX + 1] =
{ (void *)APPLINK_MAX };
if (once) {
OPENSSL_ApplinkTable[APPLINK_STDIN] = app_stdin;
OPENSSL_ApplinkTable[APPLINK_STDOUT] = app_stdout;
OPENSSL_ApplinkTable[APPLINK_STDERR] = app_stderr;
OPENSSL_ApplinkTable[APPLINK_FPRINTF] = fprintf;
OPENSSL_ApplinkTable[APPLINK_FGETS] = fgets;
OPENSSL_ApplinkTable[APPLINK_FREAD] = fread;
OPENSSL_ApplinkTable[APPLINK_FWRITE] = fwrite;
OPENSSL_ApplinkTable[APPLINK_FSETMOD] = app_fsetmod;
OPENSSL_ApplinkTable[APPLINK_FEOF] = app_feof;
OPENSSL_ApplinkTable[APPLINK_FCLOSE] = fclose;
OPENSSL_ApplinkTable[APPLINK_FOPEN] = fopen;
OPENSSL_ApplinkTable[APPLINK_FSEEK] = fseek;
OPENSSL_ApplinkTable[APPLINK_FTELL] = ftell;
OPENSSL_ApplinkTable[APPLINK_FFLUSH] = fflush;
OPENSSL_ApplinkTable[APPLINK_FERROR] = app_ferror;
OPENSSL_ApplinkTable[APPLINK_CLEARERR] = app_clearerr;
OPENSSL_ApplinkTable[APPLINK_FILENO] = app_fileno;
OPENSSL_ApplinkTable[APPLINK_OPEN] = _open;
OPENSSL_ApplinkTable[APPLINK_READ] = _read;
OPENSSL_ApplinkTable[APPLINK_WRITE] = _write;
OPENSSL_ApplinkTable[APPLINK_LSEEK] = _lseek;
OPENSSL_ApplinkTable[APPLINK_CLOSE] = _close;
once = 0;
}
return OPENSSL_ApplinkTable;
}
#ifdef __cplusplus
}
#endif
#endif
That's it, this will eliminate the strange behavior of program exit.

connection gwan with aerospike db in C

Hello.
First I'm sorry for my ita-english.
I want use gwan with aerospike but when run the servlet...problem.
I start with this example.c of aerospike. In file example.c I put gwan.h and this is the output ./gwan:
loading
hello.cs: to use .cs scripts, install C#..
hello.lua: to use .lua scripts, install Lua
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Linking example.c: undefined symbol: g_namespace
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To run G-WAN, you must fix the error(s) or remove this Servlet.
Inside example.c:
#include "gwan.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <aerospike/aerospike.h>
#include <aerospike/aerospike_key.h>
#include <aerospike/aerospike_query.h>
#include <aerospike/as_error.h>
#include <aerospike/as_key.h>
#include <aerospike/as_query.h>
#include <aerospike/as_record.h>
#include <aerospike/as_status.h>
#include <aerospike/as_val.h>
#include "example_utils.h"
const char TEST_INDEX_NAME[] = "test-bin-index";
bool query_cb(const as_val* p_val, void* udata);
void cleanup(aerospike* p_as);
bool insert_records(aerospike* p_as);
int
main(int argc, char* argv[])
{
if (! example_get_opts(argc, argv, EXAMPLE_MULTI_KEY_OPTS)) {
exit(-1);
}
aerospike as;
example_connect_to_aerospike(&as);
example_remove_test_records(&as);
example_remove_index(&as, TEST_INDEX_NAME);
if (! example_create_integer_index(&as, "test-bin", TEST_INDEX_NAME))
{
cleanup(&as);
exit(-1);
}
if (! insert_records(&as)) {
cleanup(&as);
exit(-1);
}
if (! example_read_test_records(&as)) {
cleanup(&as);
exit(-1);
}
as_error err;
as_query query;
as_query_init(&query, g_namespace, g_set);
as_query_where_inita(&query, 1);
as_query_where(&query, "test-bin", as_integer_equals(7));
LOG("executing query: where test-bin = 7");
if (aerospike_query_foreach(&as, &err, NULL, &query, query_cb, NULL)
!= AEROSPIKE_OK) {
LOG("aerospike_query_foreach() returned %d - %s", err.code,
err.message);
as_query_destroy(&query);
cleanup(&as);
exit(-1);
}
LOG("query executed");
as_query_destroy(&query);
cleanup(&as);
LOG("simple query example successfully completed");
return 0;
}
bool
query_cb(const as_val* p_val, void* udata)
{
if (! p_val) {
LOG("query callback returned null - query is complete");
return true;
}
as_record* p_rec = as_record_fromval(p_val);
if (! p_rec) {
LOG("query callback returned non-as_record object");
return true;
}
LOG("query callback returned record:");
example_dump_record(p_rec);
return true;
}
void
cleanup(aerospike* p_as)
{
example_remove_test_records(p_as);
example_remove_index(p_as, TEST_INDEX_NAME);
example_cleanup(p_as);
}
bool
insert_records(aerospike* p_as)
{
set
as_record rec;
as_record_inita(&rec, 1);
for (uint32_t i = 0; i < g_n_keys; i++) {
as_error err;
as_key key;
as_key_init_int64(&key, g_namespace, g_set, (int64_t)i);
as_record_set_int64(&rec, "test-bin", (int64_t)i);
if (aerospike_key_put(p_as, &err, NULL, &key, &rec) != AEROSPIKE_OK) {
LOG("aerospike_key_put() returned %d - %s", err.code, err.message);
return false;
}
}
LOG("insert succeeded");
return true;
}
how can connect aerospike with gwan?
Thank you
You need to #pragma link your aerospike library, and make sure all your required header files are in the right place. See G-WAN FAQ or read example code in the G-WAN tarball.
Also, in G-WAN the return code of the main function will be used as HTTP response code, so avoid return -1;.
undefined symbol: g_namespace
the error message is clear. As long as this variable is undefined your C servlet won't compile.
I don't know your library but this variable is probably defined in a library include file - or must be defined by the end user (you). Check the library documentation.
Detailed steps to run Aerospike C-client example with G-WAN,
Download and extract G-WAN server tar on your system
You can start the G-WAN server using ./gwan script present in extracted folder, e.g. ./gwan_linux64-bit/
Get Aerospike C-client from https://github.com/aerospike/aerospike-client-c, and install on your system
Copy example.c to ./gwan_linux64-bit/0.0.0.0_8080/#0.0.0.0/csp/
Make following changes to example.c,
Add following #pragma directive,
#pragma include "/home/user/aerospike-client-c/examples/utils/src/include/"
This will help search example_utils.h, which is necessary for all the example scripts in C-client.
Add following #pragma directive,
#pragma link "/home/user/aerospike-client-c/examples/utils/src/main/example_utils.c"
We shall have to link example_utils.c, as it has definitions of all util functions used in example scripts.
Make changes to the return values. Retun proper HTTP error codes.
Now, you are good to go. Run ./gwan server and access your webservice through browser, http://127.0.0.1:8080/?example.c

Resources