Made online change work on ur20
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include "atmb_boot_link.h"
|
||||
#include "../src/atom_bridge.h"
|
||||
/*****************************************************************************
|
||||
* Copyright: Copyright CODESYS Development GmbH
|
||||
@@ -38,6 +42,9 @@ DLL_DECL int CDECL ComponentEntry(INIT_STRUCT *pInitStruct)
|
||||
s_pfCMCallHook = pInitStruct->pfCMCallHook;
|
||||
s_pfCMRegisterClass = pInitStruct->pfCMRegisterClass;
|
||||
s_pfCMCreateInstance = pInitStruct->pfCMCreateInstance;
|
||||
|
||||
/* Best effort only: never make component startup depend on this. */
|
||||
atmb_ensure_boot_link();
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#ifndef ATMB_BOOT_LINK_H
|
||||
#define ATMB_BOOT_LINK_H
|
||||
|
||||
/* Linux-only boot-project pathname workaround. Include in CmpFrame.c only,
|
||||
* with _GNU_SOURCE defined before all system headers.
|
||||
* No PLC memory, communication state, worker thread or cyclic work is involved.
|
||||
*/
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static void atmb_ensure_boot_link(void)
|
||||
{
|
||||
/* ComponentEntry is called at module initialization, not on each scan.
|
||||
* Guard against repeated entry; failure is deliberately not retried.
|
||||
*/
|
||||
static int attempted;
|
||||
const char *name = "libCmpAtomModbus.so";
|
||||
const char *problem = NULL;
|
||||
Dl_info info;
|
||||
struct stat source, existing;
|
||||
char *module_path = NULL;
|
||||
int directory = -1;
|
||||
int error = 0;
|
||||
int saved_errno = errno;
|
||||
|
||||
if (attempted)
|
||||
return;
|
||||
attempted = 1;
|
||||
|
||||
/* The component function address identifies this loaded ELF object. Using
|
||||
* code rather than a local data symbol also works with runtimes that do not
|
||||
* expose local data addresses through dladdr().
|
||||
*/
|
||||
if (!dladdr((void *)(uintptr_t)&atmb_ensure_boot_link, &info) || !info.dli_fname) {
|
||||
problem = "cannot locate loaded module";
|
||||
goto finish;
|
||||
}
|
||||
module_path = realpath(info.dli_fname, NULL);
|
||||
if (!module_path) {
|
||||
error = errno;
|
||||
problem = "cannot resolve loaded module pathname";
|
||||
goto finish;
|
||||
}
|
||||
if (stat(module_path, &source) != 0) {
|
||||
error = errno;
|
||||
problem = "cannot inspect loaded module file";
|
||||
goto finish;
|
||||
}
|
||||
if (!S_ISREG(source.st_mode)) {
|
||||
problem = "loaded module pathname is not a regular file";
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Boot creation was observed looking up the bare filename relative to
|
||||
* runtime cwd. Anchor this directory with an FD; never change cwd.
|
||||
*/
|
||||
directory = open(".", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if (directory < 0) {
|
||||
error = errno;
|
||||
problem = "cannot open runtime working directory";
|
||||
goto finish;
|
||||
}
|
||||
if (fstatat(directory, name, &existing, AT_SYMLINK_NOFOLLOW) == 0) {
|
||||
struct stat resolved;
|
||||
if (fstatat(directory, name, &resolved, 0) == 0 &&
|
||||
resolved.st_dev == source.st_dev &&
|
||||
resolved.st_ino == source.st_ino)
|
||||
goto finish; /* Correct link, hard link, or the source itself. */
|
||||
problem = "existing file or link left untouched; check boot-project path";
|
||||
goto finish;
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
error = errno;
|
||||
problem = "cannot inspect boot-project pathname";
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* symlinkat fails on EEXIST: even a concurrent creator cannot be replaced.
|
||||
* Keep this link on shutdown; boot-project creation may still need it.
|
||||
*/
|
||||
if (symlinkat(module_path, directory, name) != 0) {
|
||||
error = errno;
|
||||
problem = "cannot create boot-project link";
|
||||
goto finish;
|
||||
}
|
||||
syslog(LOG_INFO, "CmpAtomModbus: created boot link %s -> %s in runtime cwd",
|
||||
name, module_path);
|
||||
|
||||
finish:
|
||||
if (problem) {
|
||||
if (error)
|
||||
syslog(LOG_WARNING, "CmpAtomModbus: %s: %s (errno=%d); Modbus startup continues",
|
||||
problem, strerror(error), error);
|
||||
else
|
||||
syslog(LOG_WARNING, "CmpAtomModbus: %s; Modbus startup continues", problem);
|
||||
}
|
||||
if (directory >= 0)
|
||||
close(directory);
|
||||
free(module_path);
|
||||
errno = saved_errno;
|
||||
}
|
||||
#endif
|
||||
@@ -1,8 +1,8 @@
|
||||
# Generated from supplied ExtensionSDK; build with target Linux toolchain.
|
||||
SDKDIR ?= ../../ExtensionSDK
|
||||
MAJORVER=0
|
||||
MINORVER=4
|
||||
CMPVERSION=0x00050000
|
||||
MINORVER=5
|
||||
CMPVERSION=0x00050001
|
||||
# Local development ID; check no other component uses this ID.
|
||||
CMPID=0x2001
|
||||
DOS2UNIX=dos2unix
|
||||
@@ -10,4 +10,9 @@ M4=m4
|
||||
CC ?= gcc
|
||||
# The SDK otherwise includes CmpFrame in its component identity wildcard.
|
||||
override CSRC := CmpAtomModbus.c
|
||||
# dladdr locates this module; -ldl also supports glibc older than 2.34.
|
||||
LDLIBS += -ldl
|
||||
include $(SDKDIR)/makefile
|
||||
|
||||
# Recompile the startup hook when the link helper changes.
|
||||
$(OUTDIR)/CmpFrame.o: atmb_boot_link.h
|
||||
|
||||
Reference in New Issue
Block a user