Ardulink 2 unable to receive message from analog Pin1 using Serial.print - arduino-uno

I have started ardulink mqtt to listen to analog pin 1 of the arduino uno
as follow running on windows 10 with mosquitto mqtt broker 1.5.8
C:\Java\jdk1.8.0_201\bin\java -jar ardulink-mqtt-2.1.0.jar -a 1 -connection "ardulink://serial-jssc?port=COM3&pingprobe=false" -standalone
However I could not get any response despite subscribe the topics with home/devices/ardulink/A1/value/get ?
I do not see any publishing being log from the ardulink log or mosquitto
From the Arduino serial monitor , I did see all the output from Serial.print indicating the sketch was in fact fully uploaded to the Arduino uno.
arduino code
int sensorValue;
// variable to calibrate low value
int sensorLow = 1023;
// variable to calibrate high value
int sensorHigh = 0;
void setup() {
Serial.begin(115200);
// calibrate for the first five seconds after program runs
while (millis() < 5000) {
// record the maximum sensor value
sensorValue = analogRead(A1);
if (sensorValue > sensorHigh) {
sensorHigh = sensorValue;
}
// record the minimum sensor value
if (sensorValue < sensorLow) {
sensorLow = sensorValue;
}
}
}
void loop() {
//read the input from A1 and store it in a variable
sensorValue = analogRead(A1);
Serial.print(sensorValue);
// wait for a moment
delay(1000);
}
Ardulink Mqtt log
C:\ardulink\lib>C:\Java\jdk1.8.0_162\bin\java -jar ardulink-mqtt-2.1.0.jar -a 1 -d 13 -connection "ardulink://serial-jss
c?port=COM4&pingprobe=false" -clientId ardulink
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/ardulink/lib/slf4j-jdk14-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/ardulink/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.JDK14LoggerFactory]
Apr 01, 2019 2:44:04 PM org.apache.camel.impl.DefaultCamelContext start
INFO: Apache Camel 2.17.1 (CamelContext: camel-1) is starting
Apr 01, 2019 2:44:04 PM org.apache.camel.management.ManagedManagementStrategy doStart
INFO: JMX is enabled
Apr 01, 2019 2:44:04 PM org.apache.camel.impl.converter.DefaultTypeConverter doStart
INFO: Loaded 182 type converters
Apr 01, 2019 2:44:04 PM org.apache.camel.impl.DefaultRuntimeEndpointRegistry doStart
INFO: Runtime endpoint registry is in extended mode gathering usage statistics of all incoming and outgoing endpoints (c
ache limit: 1000)
Apr 01, 2019 2:44:14 PM org.ardulink.core.ConnectionBasedLink startListening
INFO: Starting listening on pin ANALOG 1
Apr 01, 2019 2:44:14 PM org.ardulink.core.ConnectionBasedLink startListening
INFO: Starting listening on pin DIGITAL 13
Apr 01, 2019 2:44:14 PM org.apache.camel.impl.DefaultComponent preProcessUri
WARNING: Supplied URI 'mqtt:mqttMain?host=tcp://localhost:1883&subscribeTopicNames=home/devices/ardulink/#&connectAttemp
tsMax=1&reconnectAttemptsMax=0' contains unsafe characters, please check encoding
Apr 01, 2019 2:44:15 PM org.apache.camel.impl.DefaultCamelContext doStartCamel
INFO: AllowUseOriginalMessage is enabled. If access to the original message is not needed, then its recommended to turn
this option off as it may improve performance.
Apr 01, 2019 2:44:15 PM org.apache.camel.impl.DefaultCamelContext doStartCamel
INFO: StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at h
ttp://camel.apache.org/stream-caching.html
Apr 01, 2019 2:44:15 PM org.apache.camel.processor.aggregate.AggregateProcessor doStart
INFO: Defaulting to MemoryAggregationRepository
Apr 01, 2019 2:44:15 PM org.apache.camel.processor.aggregate.AggregateProcessor doStart
INFO: Using CompletionInterval to run every 250 millis.
Apr 01, 2019 2:44:15 PM org.apache.camel.component.mqtt.MQTTEndpoint connect
INFO: Connecting to tcp://localhost:1883 using 10 seconds timeout
Apr 01, 2019 2:44:15 PM org.apache.camel.component.mqtt.MQTTEndpoint$2 onConnected
INFO: MQTT Connection connected to tcp://localhost:1883
Apr 01, 2019 2:44:15 PM org.apache.camel.impl.DefaultCamelContext doStartOrResumeRouteConsumers
INFO: Route: route1 started and consuming from: Endpoint[ardulink://serial-jssc?listenTo=A1%2CD13&pingprobe=false&port=C
OM4]
Apr 01, 2019 2:44:15 PM org.apache.camel.impl.DefaultCamelContext doStartOrResumeRouteConsumers
INFO: Route: route2 started and consuming from: Endpoint[direct://endOfAnalogAggregation]
Apr 01, 2019 2:44:15 PM org.apache.camel.impl.DefaultCamelContext doStartOrResumeRouteConsumers
INFO: Route: route3 started and consuming from: Endpoint[mqtt:mqttMain?host=tcp://localhost:1883&subscribeTopicNames=hom
e/devices/ardulink/#&connectAttemptsMax=1&reconnectAttemptsMax=0]
Apr 01, 2019 2:44:15 PM org.apache.camel.impl.DefaultCamelContext start
INFO: Total 3 routes, of which 3 are started.
Apr 01, 2019 2:44:15 PM org.apache.camel.impl.DefaultCamelContext start
INFO: Apache Camel 2.17.1 (CamelContext: camel-1) started in 10.898 seconds

It seems that you did not flash Ardulink sketch to the Arduino but something self-written (which does not send any message via the serial link). After flashing Ardulink sketch and starting java mqtt client again everything should work.

I managed to resolve the issue after including the standard ardulink protocol , below is the revised arduino code .
int sensorValue;
// variable to calibrate low value
int sensorLow = 1023;
// variable to calibrate high value
int sensorHigh = 0;
// LED pin
const int ledPin = 13;
String inputString = ""; // a string to hold incoming data (this is general code you can reuse)
boolean stringComplete = false; // whether the string is complete (this is general code you can reuse)
void setup() {
// Make the LED pin an output and turn it on
Serial.begin(115200);
Serial.print("alp://rply/");
Serial.print("ok?id=0");
Serial.print('\n'); // End of Message
Serial.flush();
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
// calibrate for the first five seconds after program runs
while (millis() < 5000) {
// record the maximum sensor value
sensorValue = analogRead(A1);
if (sensorValue > sensorHigh) {
sensorHigh = sensorValue;
}
// record the minimum sensor value
if (sensorValue < sensorLow) {
sensorLow = sensorValue;
}
}
digitalWrite(ledPin, LOW);
}
void loop() {
//read the input from A1 and store it in a variable
serialEvent();
sensorValue = analogRead(A1);
if (stringComplete==true){
if(inputString.startsWith("alp://")) {
boolean msgRecognized = true;
if (inputString.substring(6,10)=="ared"){
//Serial.println(sensorValue);
digitalWrite(ledPin, HIGH);
}else{
msgRecognized = false;
}
// Prepare reply message if caller supply a message id (this is general code you can reuse)
int idPosition = inputString.indexOf("?id=");
if(idPosition != -1) {
String id = inputString.substring(idPosition + 4);
// print the reply
Serial.print("alp://rply/");
if(msgRecognized) { // this sketch doesn't know other messages in this case command is ko (not ok)
Serial.print("ok?id=");
} else {
Serial.print("ko?id=");
}
Serial.print(id);
Serial.print('\n'); // End of Message
Serial.flush();
}
}
// clear the string:
inputString = "";
stringComplete = false;
}
if (sensorValue>0){
Serial.print("alp://ared/");
Serial.print("1");
Serial.print("/");
Serial.print(sensorValue);
Serial.print('\n'); // End of Message
Serial.flush();
}
delay(1000);
}
void serialEvent() {
while (Serial.available()>0&&!stringComplete==true) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

Related

ESP32 S2 - reading wrong time after manual set up

The issue:
I have made a WEB app for setting. It has 2 options for RTC - SNTP and manual set up.
SNTP works well. But manual not...
It received GET request like - rtc_datetime=2022-12-06T07%3A02
if(httpd_query_key_value(qry, "rtc_datetime", temp, MAX_GET_QRY_VAL_LEN) == ESP_OK) {
// decoding %3A to : etc
decode(temp,value);
//strcpy(value,temp);
ESP_LOGI(TAG, "Time is: %s", value);
if(value[0]=='\0') {
char resp[] = "Set manual time mode";
httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN);
return ESP_OK;
}
//tm.tm_year = (value[0] - '0')*1000 + (value[1] - '0')*100 + (value[2] - '0')*10 + (value[3] - '0') - 1900;//year
tm.tm_year = string2int(value,4) - 1900;
ESP_LOGI(TAG, "year is: %d", tm.tm_year);
//tm.tm_mon = (value[5] - '0')*10 + (value[6] - '0'); //month
tm.tm_mon = string2int(value+5,2) - 1;
ESP_LOGI(TAG, "mon is: %d", tm.tm_mon);
//tm.tm_mday = (value[8] - '0')*10 + (value[9] - '0');; // day
tm.tm_mday = string2int(value+8,2);
ESP_LOGI(TAG, "day is: %d", tm.tm_mday);
//tm.tm_hour = (value[11] - '0')*10 + (value[12] - '0'); // hour
tm.tm_hour = string2int(value+11,2);
ESP_LOGI(TAG, "hour is: %d", tm.tm_hour);
//tm.tm_min = (value[14] - '0')*10 + (value[15] - '0'); // minute
tm.tm_min = string2int(value+14,2);
ESP_LOGI(TAG, "min is: %d", tm.tm_min);
tm.tm_sec = 0;
time_t t = mktime(&tm);
ESP_LOGI(TAG, "The local date and time is: %s", asctime(&tm));
struct timeval new;
new.tv_usec = 0;
new.tv_sec = t;
settimeofday(&new, NULL);
//localtime(&t);
struct tm timeinfo2;
timeinfo2.tm_sec = 0;
timeinfo2.tm_min = 0;
time_t now2;// = time(NULL);
time(&now2);
localtime_r(&now2, &timeinfo2);
ESP_LOGI(TAG, "curr time - %4d-%2d-%2d %2d:%2d", timeinfo2.tm_year+1900, timeinfo2.tm_mon+1, timeinfo2.tm_mday, timeinfo2.tm_hour, timeinfo2.tm_min);
ESP_LOGI(TAG, "The local date and time is: %s", asctime(&timeinfo2));
char resp[] = "Time is set";
httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN);
asctime(&tm) shows correct time from URL.
But time in timeinfo2 has difference 17 minutes and 53 seconds...
Line by line log:
I (16452) web server: GET request: form=rtc_form&rtc_datetime=2022-12-06T19%3A21&rtc_tz=458
I (16452) web server: r0_form
I (16452) web server: r1_form
I (16452) web server: rtc_form
I (16462) system config: sntp: 0
I (16462) system config: rtc_tz: 458
I (16462) system config: Save /spiffs/rtc.json
I (16492) system config: Set: {"rtc_sntp":0,"rtc_tz":458}
I (16492) web server: Time is: 2022-12-06T19:21
I (16492) web server: year is: 122
I (16492) web server: mon is: 11
I (16502) web server: day is: 6
I (16502) web server: hour is: 19
I (16512) web server: min is: 21
I (16512) web server: The local date and time is: Tue Dec 6 19:21:00 2022
I (16522) web server: curr time - 2022-12- 6 19:38
I (16522) web server: The local date and time is: Tue Dec 6 19:38:53 2022
I have no idea what I do wrong....
tm.tm_year = 2022 - 1900;
tm.tm_mon = 0;
tm.tm_mday = 0;
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
time_t t = mktime(&tm);
ESP_LOGI(TAG, "The local date and time is: %s", asctime(&tm));
struct timeval new;
new.tv_usec = 0;
new.tv_sec = t;
settimeofday(&new, NULL);
struct tm timeinfo2;
timeinfo2.tm_sec = 0;
timeinfo2.tm_min = 0;
time_t now2;
time(&now2);
localtime_r(&now2, &timeinfo2);
ESP_LOGI(TAG, "The local date and time is: %s", asctime(&timeinfo2));
So, this is the code without any data from GET request. Hm... What is a correct initialization for tm struct? I thing true is near...
mktime() "makes" this issue or tm struct is wrong initialized.
The same problem:
I (22892) web server: The local date and time is: Fri Dec 31 00:00:00 2021
I (22902) web server: The local date and time is: Fri Dec 31 00:17:53 2021
I add ctime() log for checking mktime() output, so it showes correct
time_t t = mktime(&tm);
ESP_LOGI(TAG, "Time from epoch t: %s", ctime(&t));
ESP_LOGI(TAG, "Time from tm: %s", asctime(&tm));
Console log:
I (18012) web server: Time from epoch t: Thu Dec 8 09:13:00 2022
I (18022) web server: Time from tm: Thu Dec 8 09:13:00 2022
I've found the same problem in espressif GitHub issues.
It looks like the issue is in the settimeofday() function.
So, I implemented the same workaround:
settimeofday(&new, NULL);
struct timeval get_set_time;
gettimeofday(&get_set_time,NULL);
int time_diff = get_set_time.tv_sec - new.tv_sec;
ESP_LOGI(TAG, "Difference in time: %d", time_diff);
new.tv_sec -= time_diff;
settimeofday(&new, NULL);
Log:
I (15322) web server: Difference in time: 1073
Moreover, the project was migrated to IDF 5.0 version — the bug is no longer there in the settimeofday(). So, the problem was solved.

<Windows Hello WBDI/EngineAdapter development> A question about Adapter Workflow

I got a problem when I developed the WBDI and EngineAdapter with my fingerprint module on Win10 OS.
The problem is why the EngineAdapter doesn't go into below callback functions, after I finished Step 1 and Step 2 below?
Because the document of Microsoft mentioned that below functions will be called when enrollment workflow goes through.
(https://learn.microsoft.com/zh-tw/windows/win32/secbiomet/adapter-workflow)
Below are the callback functions not be called.
(1) "EngineAdapterCreateEnrollment"
(2) "EngineAdapterSetEnrollmentParameters"
Does anyone know how to solve it?
Many thanks.
Step1
Step2
Adapter Workflow
EngineAdapter log
DllMain, Wed Mar 17 14:22:37 2021
WbioQueryEngineInterface, Wed Mar 17 14:22:37 2021
EngineAdapterAttach, Wed Mar 17 14:22:37 2021
EngineAdapterSelectCalibrationFormat, Wed Mar 17 14:22:37 2021
EngineAdapterPipelineInit, Wed Mar 17 14:22:37 2021
DllMain, Wed Mar 17 14:22:42 2021
EngineAdapterActivate, Wed Mar 17 14:22:42 2021
EngineAdapterQueryExtendedInfo, Wed Mar 17 14:22:42 2021
EngineAdapterSetAccountPolicy, Wed Mar 17 14:22:42 2021
DllMain, Wed Mar 17 14:22:43 2021
EngineAdapterClearContext, Wed Mar 17 14:22:45 2021
EngineAdapterQueryPreferredFormat, Wed Mar 17 14:22:45 2021
EngineAdapterCreateKey, Wed Mar 17 14:22:46 2021
EngineAdapterCreateKey, Wed Mar 17 14:22:46 2021
EngineAdapterAcceptSampleData, Wed Mar 17 14:22:46 2021
EngineAdapterIdentifyFeatureSet, Wed Mar 17 14:22:46 2021
EngineAdapterClearContext, Wed Mar 17 14:22:46 2021
EngineAdapterClearContext, Wed Mar 17 14:22:46 2021
WBDI log
IOCTL_BIOMETRIC_GET_ATTRIBUTES, Wed Mar 17 14:22:37 2021
IOCTL_BIOMETRIC_GET_SENSOR_STATUS, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_GET_ATTRIBUTES, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_CAPTURE_DATA, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_CAPTURE_DATA, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_GET_SENSOR_STATUS, Wed Mar 17 14:22:46 2021
EngineAdapter code (EngineAdapter.cpp)
static WINBIO_ENGINE_INTERFACE g_EngineInterface = {
#if (NTDDI_VERSION >= NTDDI_WIN10_RS4)
WINBIO_ENGINE_INTERFACE_VERSION_6,
#elif(NTDDI_VERSION >= NTDDI_WIN10_RS3)
WINBIO_ENGINE_INTERFACE_VERSION_5,
#elif(NTDDI_VERSION >= NTDDI_WIN10_RS1)
WINBIO_ENGINE_INTERFACE_VERSION_4,
#elif(NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
WINBIO_ENGINE_INTERFACE_VERSION_3,
#elif(NTDDI_VERSION >= NTDDI_WIN8)
WINBIO_ENGINE_INTERFACE_VERSION_2,
#elif
WINBIO_ENGINE_INTERFACE_VERSION_1,
#endif
WINBIO_ADAPTER_TYPE_ENGINE,
sizeof(WINBIO_ENGINE_INTERFACE),
{0xb876fdc8, 0x34e7, 0x471a, {0x82, 0xc8, 0x9c, 0xba, 0x6a, 0x35, 0x38, 0xec}},
EngineAdapterAttach,
EngineAdapterDetach,
EngineAdapterClearContext,
EngineAdapterQueryPreferredFormat,
EngineAdapterQueryIndexVectorSize,
EngineAdapterQueryHashAlgorithms,
EngineAdapterSetHashAlgorithm,
EngineAdapterAcceptSampleHint,
EngineAdapterAcceptSampleData,
EngineAdapterExportEngineData,
EngineAdapterVerifyFeatureSet,
EngineAdapterIdentifyFeatureSet,
EngineAdapterCreateEnrollment,
EngineAdapterUpdateEnrollment,
EngineAdapterGetEnrollmentStatus,
EngineAdapterGetEnrollmentHash,
EngineAdapterCheckForDuplicate,
EngineAdapterCommitEnrollment,
EngineAdapterDiscardEnrollment,
EngineAdapterControlUnit,
EngineAdapterControlUnitPrivileged,
#if(NTDDI_VERSION >= NTDDI_WIN8)
EngineAdapterNotifyPowerChange,
EngineAdapter_RESERVED,
//EngineAdapterReserved_1;
#endif//(NTDDI_VERSION >= NTDDI_WIN8)
#if(NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
//
// V3.0 methods begin here...
//
EngineAdapterPipelineInit,
EngineAdapterPipelineCleanup,
EngineAdapterActivate,
EngineAdapterDeactivate,
EngineAdapterQueryExtendedInfo,
EngineAdapterIdentifyAll,
EngineAdapterSetEnrollmentSelector,
EngineAdapterSetEnrollmentParameters,
EngineAdapterQueryExtendedEnrollmentStatus,
EngineAdapterRefreshCache,
EngineAdapterSelectCalibrationFormat,
EngineAdapterQueryCalibrationData,
EngineAdapterSetAccountPolicy,
#endif //(NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
#if(NTDDI_VERSION >= NTDDI_WIN10_RS1)
//
// V4.0 methods begin here...
//
EngineAdapterCreateKey,
EngineAdapterIdentifyFeatureSetSecure,
#endif//(NTDDI_VERSION >= NTDDI_WIN10_RS1)
#if(NTDDI_VERSION >= NTDDI_WIN10_RS3)
//
// V5.0 methods begin here...
//
EngineAdapterAcceptPrivateSensorTypeInfo,
#endif(NTDDI_VERSION >= NTDDI_WIN10_RS3)
#if(NTDDI_VERSION >= NTDDI_WIN10_RS4)
//
// V6.0 methods begin here...
//
EngineAdapterCreateEnrollmentAuthenticated,
EngineAdapterIdentifyFeatureSetAuthenticated
#endif//(NTDDI_VERSION >= NTDDI_WIN10_RS4)
};
WBDI code
switch (ControlCode) {
//
// Mandatory IOCTLs
//
case IOCTL_BIOMETRIC_GET_ATTRIBUTES:
m_BiometricDevice->OnGetAttributes(FxRequest);
break;
case IOCTL_BIOMETRIC_RESET:
m_BiometricDevice->OnReset(FxRequest);
break;
case IOCTL_BIOMETRIC_CALIBRATE:
m_BiometricDevice->OnCalibrate(FxRequest);
break;
case IOCTL_BIOMETRIC_GET_SENSOR_STATUS:
m_BiometricDevice->OnGetSensorStatus(FxRequest);
break;
case IOCTL_BIOMETRIC_CAPTURE_DATA:
m_BiometricDevice->OnCaptureData(FxRequest);
break;
}
void
CBiometricDevice::OnGetAttributes(
_Inout_ IWDFIoRequest *FxRequest
)
{
CRequestHelper MyRequest(FxRequest); // RAII helper class
ULONG controlCode = 0;
PUCHAR inputBuffer= NULL;
SIZE_T inputBufferSize = 0;
PWINBIO_SENSOR_ATTRIBUTES sensorAttributes = NULL;
SIZE_T outputBufferSize;
//
// Get the request parameters
//
GetIoRequestParams(FxRequest,
&controlCode,
&inputBuffer,
&inputBufferSize,
(PUCHAR *)&sensorAttributes,
&outputBufferSize);
//
// Make sure we have an output buffer big enough
//
if (sensorAttributes == NULL || outputBufferSize < sizeof(DWORD))
{
// We cannot return size information.
TraceEvents(TRACE_LEVEL_ERROR,
BIOMETRIC_TRACE_DEVICE,
"%!FUNC!Output buffer NULL or too small to return size information.");
MyRequest.SetCompletionHr(E_INVALIDARG);
return;
}
// We only have one supported format, so sizeof (WINBIO_SENSOR_ATTRIBUTES) is sufficient.
if (outputBufferSize < sizeof(WINBIO_SENSOR_ATTRIBUTES))
{
// Buffer too small.
TraceEvents(TRACE_LEVEL_ERROR,
BIOMETRIC_TRACE_DEVICE,
"%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_SENSOR_ATTRIBUTES));
sensorAttributes->PayloadSize = (DWORD) sizeof(WINBIO_SENSOR_ATTRIBUTES);
MyRequest.SetInformation(sizeof(DWORD));
MyRequest.SetCompletionHr(S_OK);
return;
}
//
// Fill in the attribute payload structure
//
RtlZeroMemory(sensorAttributes, outputBufferSize);
sensorAttributes->PayloadSize = (DWORD) sizeof(WINBIO_SENSOR_ATTRIBUTES);
sensorAttributes->WinBioHresult = S_OK;
sensorAttributes->WinBioVersion.MajorVersion = WINBIO_WBDI_MAJOR_VERSION;
sensorAttributes->WinBioVersion.MinorVersion = WINBIO_WBDI_MINOR_VERSION;
sensorAttributes->SensorType = WINBIO_TYPE_FINGERPRINT;
sensorAttributes->SensorSubType = WINBIO_FP_SENSOR_SUBTYPE_TOUCH;// WINBIO_FP_SENSOR_SUBTYPE_SWIPE;//WINBIO_FP_SENSOR_SUBTYPE_TOUCH;
sensorAttributes->Capabilities = WINBIO_CAPABILITY_SENSOR | WINBIO_CAPABILITY_MATCHING | WINBIO_CAPABILITY_DATABASE;// WINBIO_CAPABILITY_SENSOR | WINBIO_CAPABILITY_MATCHING | WINBIO_CAPABILITY_DATABASE | WINBIO_CAPABILITY_PROCESSING;// WINBIO_CAPABILITY_SENSOR;
sensorAttributes->SupportedFormatEntries = 1;
sensorAttributes->SupportedFormat[0].Owner = WINBIO_ANSI_381_FORMAT_OWNER;
sensorAttributes->SupportedFormat[0].Type= WINBIO_ANSI_381_FORMAT_TYPE;
RtlCopyMemory(sensorAttributes->ManufacturerName, SAMPLE_MANUFACTURER_NAME, (wcslen(SAMPLE_MANUFACTURER_NAME)+1)*sizeof(WCHAR));
RtlCopyMemory(sensorAttributes->ModelName, SAMPLE_MODEL_NAME, (wcslen(SAMPLE_MODEL_NAME)+1)*sizeof(WCHAR));
RtlCopyMemory(sensorAttributes->SerialNumber, SAMPLE_SERIAL_NUMBER, (wcslen(SAMPLE_SERIAL_NUMBER)+1)*sizeof(WCHAR));
sensorAttributes->FirmwareVersion.MajorVersion = 1;
sensorAttributes->FirmwareVersion.MinorVersion = 0;
MyRequest.SetInformation(sensorAttributes->PayloadSize);
MyRequest.SetCompletionHr(S_OK);
}
void
CBiometricDevice::OnGetSensorStatus(
_Inout_ IWDFIoRequest *FxRequest
)
{
CRequestHelper MyRequest(FxRequest); // RAII helper class
ULONG controlCode = 0;
PUCHAR inputBuffer= NULL;
SIZE_T inputBufferSize = 0;
PWINBIO_DIAGNOSTICS diagnostics = NULL;
SIZE_T outputBufferSize;
//
// Get the request parameters
//
GetIoRequestParams(FxRequest,
&controlCode,
&inputBuffer,
&inputBufferSize,
(PUCHAR *)&diagnostics,
&outputBufferSize);
//
// Make sure we have an output buffer big enough
//
if (diagnostics == NULL || outputBufferSize < sizeof(DWORD))
{
// We cannot return size information.
TraceEvents(TRACE_LEVEL_ERROR,
BIOMETRIC_TRACE_DEVICE,
"%!FUNC!Output buffer NULL or too small to return size information.");
MyRequest.SetCompletionHr(E_INVALIDARG);
return;
}
if (outputBufferSize < sizeof(WINBIO_DIAGNOSTICS))
{
// Buffer too small.
TraceEvents(TRACE_LEVEL_ERROR,
BIOMETRIC_TRACE_DEVICE,
"%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_DIAGNOSTICS));
diagnostics->PayloadSize = (DWORD)sizeof(WINBIO_DIAGNOSTICS);
MyRequest.SetInformation(sizeof(DWORD));
MyRequest.SetCompletionHr(S_OK);
return;
}
//
// Fill in the OUT payload structure
//
RtlZeroMemory(diagnostics, outputBufferSize);
diagnostics->PayloadSize = (DWORD) sizeof(WINBIO_DIAGNOSTICS);
diagnostics->WinBioHresult = S_OK;
//diagnostics->SensorStatus = WINBIO_SENSOR_READY;
if (SensorStatusFlag)
{
SensorStatusFlag = 0;
diagnostics->SensorStatus = WINBIO_SENSOR_ACCEPT;
}
else
{
diagnostics->SensorStatus = WINBIO_SENSOR_READY;
}
MyRequest.SetInformation(diagnostics->PayloadSize);
MyRequest.SetCompletionHr(S_OK);
}
void
CBiometricDevice::OnCaptureData(
_Inout_ IWDFIoRequest *FxRequest
)
{
ULONG controlCode = 0;
PWINBIO_CAPTURE_PARAMETERS captureParams = NULL;
SIZE_T inputBufferSize = 0;
PWINBIO_CAPTURE_DATA captureData = NULL;
SIZE_T outputBufferSize = 0;
//
// We can only have one outstanding data capture request at a time.
// Check to see if we have a request pending.
//
bool requestPending = false;
EnterCriticalSection(&m_RequestLock);
if (m_PendingRequest == NULL)
{
//
// See if we have an active sleep thread.
// If so, tell it to exit.
// Wait for it to exit.
//
if (m_SleepThread != INVALID_HANDLE_VALUE)
{
LeaveCriticalSection(&m_RequestLock);
// TODO: Add code to signal thread to exit.
// NOTE: Sleeping for INFINITE time is dangerous. A real driver
// should be able to handle the case where the thread does
// not exit.
WaitForSingleObject(m_SleepThread, INFINITE);
CloseHandle(m_SleepThread);
m_SleepThread = INVALID_HANDLE_VALUE;
EnterCriticalSection(&m_RequestLock);
}
//
// We might have had to leave the CS to wait for the sleep thread.
// Double check that the pending request is still NULL.
//
if (m_PendingRequest == NULL)
{
// Save the request.
m_PendingRequest = FxRequest;
// Mark the request as cancellable.
m_PendingRequest->MarkCancelable(this);
}
else
{
requestPending = true;
}
}
else
{
requestPending = true;
}
LeaveCriticalSection(&m_RequestLock);
if (requestPending)
{
// Complete the request to tell the app that there is already
// a pending data collection request.
FxRequest->Complete(WINBIO_E_DATA_COLLECTION_IN_PROGRESS);
return;
}
//
// Get the request parameters
//
GetIoRequestParams(FxRequest,
&controlCode,
(PUCHAR *)&captureParams,
&inputBufferSize,
(PUCHAR *)&captureData,
&outputBufferSize);
//
// Check input parameters.
//
if (inputBufferSize < sizeof (WINBIO_CAPTURE_PARAMETERS))
{
// Invalid arguments
TraceEvents(TRACE_LEVEL_ERROR,
BIOMETRIC_TRACE_DEVICE,
"%!FUNC!Invalid argument(s).");
CompletePendingRequest(E_INVALIDARG, 0);
return;
}
//
// Make sure we have an output buffer big enough
//
if (outputBufferSize < sizeof(DWORD))
{
// We cannot return size information.
TraceEvents(TRACE_LEVEL_ERROR,
BIOMETRIC_TRACE_DEVICE,
"%!FUNC!Output buffer NULL or too small to return size information.");
CompletePendingRequest(E_INVALIDARG, 0);
return;
}
//
// Check output buffer size.
//
if (outputBufferSize < sizeof (WINBIO_CAPTURE_DATA))
{
// Buffer too small.
TraceEvents(TRACE_LEVEL_ERROR,
BIOMETRIC_TRACE_DEVICE,
"%!FUNC!Buffer too small - must be at least 0x%x.", sizeof (WINBIO_CAPTURE_DATA));
//
// NOTE: The output buffer size necessary for this sample is sizeof(WINBIO_CAPTURE_DATA).
// Real devices will need additional space to handle a typical capture.
// The value that should be returned here is sizeof(WINBIO_CAPTURE_DATA) + CaptureBufferSize.
//
captureData->PayloadSize = (DWORD)sizeof(WINBIO_CAPTURE_DATA)+12;
CompletePendingRequest(S_OK, sizeof(DWORD));
return;
}
//
// NOTE: This call always fails in this sample since it is not
// written for a real device.
//
//
// Set default values in output buffer.
//
SensorStatusFlag = 1;
RtlZeroMemory(captureData, outputBufferSize);
captureData->PayloadSize = (DWORD)outputBufferSize;
captureData->WinBioHresult = S_OK;
captureData->SensorStatus = WINBIO_SENSOR_ACCEPT;
captureData->RejectDetail = 0;
captureData->CaptureData.Size = (DWORD)12;
UCHAR szBuffer[] = { 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04 };
RtlCopyMemory(captureData->CaptureData.Data, szBuffer,12);
//
// Check purpose, format and type.
//
if (captureParams->Purpose == WINBIO_NO_PURPOSE_AVAILABLE)
{
captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_PURPOSE;
}
else if ((captureParams->Format.Type != WINBIO_ANSI_381_FORMAT_TYPE) ||
(captureParams->Format.Owner != WINBIO_ANSI_381_FORMAT_OWNER))
{
captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_DATA_FORMAT;
}
else if (captureParams->Flags != WINBIO_DATA_FLAG_RAW)
{
captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_DATA_TYPE;
}
//
// Create thread to sleep 1 seconds before completing the request.
//
m_SleepParams.SleepValue = 1;
m_SleepParams.Hr = S_OK;
m_SleepParams.Information = captureData->PayloadSize;
m_SleepThread = CreateThread(NULL, // default security attributes
0, // use default stack size
CaptureSleepThread, // thread function name
this, // argument to thread function
0, // use default creation flags
NULL); // returns the thread identifier
}
DWORD WINAPI
CaptureSleepThread(
LPVOID lpParam
)
{
CBiometricDevice *device = (CBiometricDevice *) lpParam;
PCAPTURE_SLEEP_PARAMS sleepParams = device->GetCaptureSleepParams();
//
// Make sure it is less than or equal to 1 minute.
//
if (sleepParams->SleepValue > 60)
{
sleepParams->SleepValue = 60;
}
Sleep(sleepParams->SleepValue * 1000);
device->CompletePendingRequest(sleepParams->Hr, sleepParams->Information);
return 0;
}

What capabilities required for ioctl() on emmc on systemd?

I want to run my program with systemd with a regular user ( non-root). This program uses ioctl() syscall to access emmc registers.I want to learn which capabilities required to be added to my systemd unit file.
I tried with below unit file:
[Unit]
Description=EMMC-LIFETIME UTILITY
[Service]
User=tron
Group=disk
ExecStart=/HARICI/emmc-lifetime /dev/mmcblk0 -v
CapabilityBoundingSet=CAP_SYS_ADMIN
DeviceAllow=/dev/mmcblk0 rw
[Install]
WantedBy=multi-user.target
Here is the code of emmc-lifetime:
int main(int argc, char **argv)
{
if(argc < 2){
printf("Usage: %s <mmcfilename> (-v)\n", argv[0]);
printf("Example: %s /dev/mmcblk1 -v\n", argv[0]);
return 1;
}
char ext_csd[512], ext_csd_rev;
int fd, ret;
fd = open(argv[1], O_RDWR);
if (fd < 0) {
printf("Failed to open eMMC device, please check which path you have passed\n");
return 1;
}
struct mmc_ioc_cmd idata;
memset(&idata, 0, sizeof(idata));
memset(ext_csd, 0, sizeof(char) * 512);
idata.write_flag = 0;
idata.opcode = MMC_SEND_EXT_CSD;
idata.arg = 0;
idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
idata.blksz = 512;
idata.blocks = 1;
mmc_ioc_cmd_set_data(idata, ext_csd);
ret = ioctl(fd, MMC_IOC_CMD, &idata);
if (ret){
printf("ioctl failed, are you sure it is an MMC device???\n");
return ret;
}
ext_csd_rev = ext_csd[EXT_CSD_REV];
if (ext_csd_rev >= 7) {
if(argc==3 && !strcmp(argv[2],"-v")){
printf("EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A: 0x%02x\n",
ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]);
printf("EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B: 0x%02x\n",
ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]);
printf("EXT_CSD_PRE_EOL_INFO: 0x%02x\n",
ext_csd[EXT_CSD_PRE_EOL_INFO]);
}else{
printf("%d\n",ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]*10);
}
}
if(fd)
close(fd);
return ret;
If I comment out "User=tron" in my unit file, everything works expectedly:
Nov 03 01:17:03 tron systemd[1]: Started EMMC-LIFETIME UTILITY.
Nov 03 01:17:03 tron emmc-lifetime[28294]: EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A: 0x01
Nov 03 01:17:03 tron emmc-lifetime[28294]: EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B: 0x01
Nov 03 01:17:03 tron emmc-lifetime[28294]: EXT_CSD_PRE_EOL_INFO: 0x01
But if I uncomment "User=tron", here is the result:
Nov 03 00:57:17 tron systemd[1]: Started EMMC-LIFETIME UTILITY.
Nov 03 00:57:17 tron emmc-lifetime[27706]: ioctl failed, are you sure it is an MMC device???
Nov 03 00:57:17 tron systemd[1]: emmc-info.service: Main process exited, code=exited, status=255/n/a
Nov 03 00:57:18 tron systemd[1]: emmc-info.service: Unit entered failed state.
Nov 03 00:57:18 tron systemd[1]: emmc-info.service: Failed with result 'exit-code'.
What capabilities are required in my unit file to run my executable as "tron" user ?
Solved. For the capabilities side, it must have CAP_SYS_RAWIO.
We can use :
setcap cap_sys_rawio=+eip /HARICI/emmc-lifetime
And by this way, we can run "emmc-lifetime" binary with non-root user. Please note that, this user must be in "disk" group to be able to open "/dev/mmcblkX"
But unfortunately, this doesn't work in systemd unit files.
In systemd unit files, if you write:
User=some-non-root-user
CapabilityBoundingSet=SOME_CAPABILITY
Does not work. Thats why my above code allways fails.
I must find another way to run my binary with non-root privileges.

Duplicate Keys noticed while writing to TOML file; tree.Has() is not working as expected

While writing into TOML file using go-toml parser, I'm seeing all duplicate entries.
Which one is correct about tree.WriteTo() function?
a. overwrites the fields in the file
b. appends the tree to the file? i.e., to the existing file, write the tree content again.
I wanted to achieve the update operation to the existing config parameter (present in TOML file).
I tried this:
//Read the config file
tree, _ := toml.LoadFile("/home/robot/test.toml")
//Read user input
reqBody, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}
//Check whether the input config parameter is present in the file or not
configArray := strings.Split(string(reqBody), ";")
for index, each := range configArray {
config := strings.Split(each, "=")
fmt.Println("Param name : ", config[0])
fmt.Println("Param value : ", config[1])
fmt.Println(index)
isPresent := tree.Has(config[0])
fmt.Println(isPresent)
if isPresent == true {
tree.Set(config[0], config[1])
}else {
fmt.Println("Config Parameter not found")
}
}
// Now the tree has updated values, update the file.
outputReader, err = os.OpenFile("/home/robot/test.toml",os.O_RDWR,0644)
if err != nil {
fmt.Println("Error opening the file")
}
var numBytes int64
numBytes, err = tree.WriteTo(outputReader)
if err != nil {
fmt.Println("Error writing to the file")
}
fmt.Println(numBytes)
tree.Has() is always returning false, even though the valid key is provided. Not sure why! Please see the output logs pasted.
tree.WriteTo() is appending all the tree entries to the file. i.e., it is not updating the parameter values, but writing everything newly resulting in duplicate configuration parameters in the file.
If tree.WriteTo() is meant to write entire tree content to file, then is there any API or way to update the existing configurations in TOML file?
Output logs:
TOML content (i.e., dump of tree):
Sep 03 13:27:33 mn-0 janus[31157]: [http]
Sep 03 13:27:33 mn-0 janus[31157]: enableAudit = true
Sep 03 13:27:33 mn-0 janus[31157]: idleTimeout = "600s"
Sep 03 13:27:33 mn-0 janus[31157]: logLevel = "debug"
Sep 03 13:27:33 mn-0 janus[31157]: port = 443
Sep 03 13:27:33 mn-0 janus[31157]: readTimeout = "10s"
Sep 03 13:27:33 mn-0 janus[31157]: tlsMode = true
Sep 03 13:27:33 mn-0 janus[31157]: writeTimeout = "10s"
Sep 03 13:27:33 mn-0 janus[31157]: [http.cred]
Sep 03 13:27:33 mn-0 janus[31157]: sessionValidity = "1h"
Sep 03 13:27:33 mn-0 janus[31157]: strictSecureMode = false
Sep 03 13:27:33 mn-0 janus[31157]: users = ["robot"]
Sep 03 13:27:33 mn-0 janus[31157]: [http.ipConfig]
Sep 03 13:27:33 mn-0 janus[31157]: ipAddr = ""
Sep 03 13:27:33 mn-0 janus[31157]: role = "ssh"
Input invalid key:
Sep 03 13:27:33 mn-0 janus[31157]: Param name : http.enableAudt
Sep 03 13:27:33 mn-0 janus[31157]: Param value : true
Sep 03 13:27:33 mn-0 janus[31157]: 0
Sep 03 13:27:33 mn-0 janus[31157]: false
Input valid Key:
Sep 03 13:27:33 mn-0 janus[31157]: Param name : http.enableAudit
Sep 03 13:27:33 mn-0 janus[31157]: Param value : false
Sep 03 13:27:33 mn-0 janus[31157]: 1
Sep 03 13:27:33 mn-0 janus[31157]: false
One more question on unmarshal() or configuration validation while reading,
Say my structure is like this.
type IPConfig struct {
User string
Role string
IPAddr string
}
type MyConfiguration struct {
MyConfiguration MyConfiguration
}
a.
If the TOML file has this:
[ipConfig]
role = "ssh"
ipAddr = ""
i.e., it doesn't have one more parameter, "User". How do I catch this while Unmarshal? At least Unmarshal() will not throw any error here.
b.
If the TOML file has this:
[ipConfig]
role = "ssh"
ipAddr = ""
user = "lauren"
abc = "xyz"
i.e., it has extra configuration parameter "abc". How to catch this? Unmarshal() didn't throw any error even for this.
Any way to get these validation errors?
For question 1:
It is hard to figure out what may be going on without having access to the content of the files. If you believe this is a bug, please open an issue on Github, including the reproduction steps. Thank you!
For question 2:
You need to remove or truncate the file before writing to it.
Go-toml does not know that you are writing to a file. WriteTo takes a io.Writer, which just signifies "something you can write to". So when you open the file for read/write, the "writer" part of the file has a 0 offset. So when toml writes to it (using WriteTo), it will just be replacing bytes to the file.
If you want to overwrite the content of the file using WriteTo, you need to call .truncate(0) or similar on the file before writing to it.
Note: as of writing, comments are discarded during Load. There is an issue on Github asking for that feature.
For question 3:
There is no support for erroring on missing keys or on extra keys. There is an issue open at the moment to support the latter.

What "deleted" means in /proc/$pid/maps?

I downloaded libhugetlbfs.so and have a simple test source :
int glbarr[1024*1024]={0} ;
int main()
{
char * ptr ;
ptr = (char *) malloc( 1024 * 1024 * 1 ) ;
printf(" press any key to go on \n");
getchar() ;
for(int idx=0;idx<100;idx++){
char strtmp[64] = {0} ;
sprintf(strtmp,"%020d",idx) ;
strcpy( ptr+1024*idx , strtmp ) ;
} //for
for(int idx=0;idx<100;idx++){
glbarr[idx] = idx ;
}
printf(" press any key to go on \n");
getchar() ;
} // main
then set the env :
export LD_PRELOAD=libhugetlbfs.so
export HUGETLB_MORECORE=yes
export HUGETLB_DEBUG=1
At last , execute test_malloc.exe :
INFO: Found pagesize 2048 kB
INFO: Detected page sizes:
INFO: Size: 2048 kB (default) Mount: /mnt/SharedMem_2M
INFO: Parsed kernel version: [3] . [10] . [0]
INFO: Feature private_reservations is present in this kernel
INFO: Feature noreserve_safe is present in this kernel
INFO: Feature map_hugetlb is present in this kernel
INFO: Kernel has MAP_PRIVATE reservations. Disabling heap prefaulting.
INFO: Kernel supports MAP_HUGETLB
INFO: HUGETLB_SHARE=0, sharing disabled
INFO: HUGETLB_NO_RESERVE=no, reservations enabled
INFO: Segment 0 (phdr 2): 0x400000-0x400a04 (filesz=0xa04) (prot = 0x5)
INFO: Segment 1 (phdr 3): 0x600de0-0xa01080 (filesz=0x274) (prot = 0x3)
DEBUG: symbol to copy at 0x601060: stdin
DEBUG: Total memsz = 0x400ca4, memsz of largest segment = 0x4002a0
INFO: libhugetlbfs version: 2.20
INFO: Mapped hugeseg at 0x2aaaaac00000. Copying 0xa04 bytes and 0 extra bytes from 0x400000...done
INFO: Prepare succeeded
INFO: Mapped hugeseg at 0x2aaaaac00000. Copying 0x274 bytes and 0x14 extra bytes from 0x600de0...done
INFO: Prepare succeeded
INFO: setup_morecore(): heapaddr = 0x1c00000
INFO: hugetlbfs_morecore(2101248) = ...
INFO: heapbase = 0x1c00000, heaptop = 0x1c00000, mapsize = 0, delta=2101248
INFO: Attempting to map 4194304 bytes
INFO: ... = 0x1c00000
INFO: hugetlbfs_morecore(0) = ...
INFO: heapbase = 0x1c00000, heaptop = 0x1e01000, mapsize = 400000, delta=-2093056
INFO: ... = 0x1e01000
and the /proc/pidof test_malloc.exe/maps :
00400000-00600000 r-xp 00000000 00:2b 6019488 /mnt/SharedMem_2M/libhugetlbfs.tmp.uI55WD (deleted)
00600000-00c00000 rw-p 00000000 00:2b 6123885 /mnt/SharedMem_2M/libhugetlbfs.tmp.VUALYM (deleted)
01c00000-02000000 rw-p 00000000 00:0d 6123886 /anon_hugepage (deleted)
numastat -m showes hugepage really in use for 8M ,
What bother me is what do "deleted" means in maps output ?!
either in /mnt/SharedMem_2M or /anon_hugepage
Edit :
and the debug information :
INFO: Found pagesize 2048 kB
INFO: Detected page sizes:
INFO: Size: 2048 kB (default) Mount: /mnt/SharedMem_2M
INFO: Parsed kernel version: [3] . [10] . [0]
INFO: Feature private_reservations is present in this kernel
INFO: Feature noreserve_safe is present in this kernel
INFO: Feature map_hugetlb is present in this kernel
INFO: Kernel has MAP_PRIVATE reservations. Disabling heap prefaulting.
INFO: Kernel supports MAP_HUGETLB
INFO: HUGETLB_SHARE=0, sharing disabled
INFO: HUGETLB_NO_RESERVE=no, reservations enabled
INFO: Segment 0 (phdr 3): 0x600de0-0xa01080 (filesz=0x274) (prot = 0x3)
DEBUG: symbol to copy at 0x601060: stdin
DEBUG: Total memsz = 0x4002a0, memsz of largest segment = 0x4002a0
INFO: libhugetlbfs version: 2.20
INFO: Mapped hugeseg at 0x2aaaaac00000. Copying 0x274 bytes and 0x14 extra bytes from 0x600de0...done
INFO: Prepare succeeded
INFO: setup_morecore(): heapaddr = 0x2200000
INFO: hugetlbfs_morecore(2101248) = ...
INFO: heapbase = 0x2200000, heaptop = 0x2200000, mapsize = 0, delta=2101248
INFO: Attempting to map 4194304 bytes
INFO: ... = 0x2200000
INFO: hugetlbfs_morecore(0) = ...
INFO: heapbase = 0x2200000, heaptop = 0x2401000, mapsize = 400000, delta=-2093056
INFO: ... = 0x2401000
and the maps :
00400000 default file=/home/marschen/test/posix-memalign/test_malloc.exe mapped=1 N0=1 kernelpagesize_kB=4
00600000 default file=/mnt/SharedMem_2M/libhugetlbfs.tmp.85Y41e\040(deleted) huge anon=1 dirty=1 N0=1 kernelpagesize_kB=2048
02200000 default file=/anon_hugepage\040(deleted) huge anon=1 dirty=1 N0=1 kernelpagesize_kB=2048
Temporary file deletion (unlinking) is normal for libhugetlbfs when it uses hugetlb fs pseudo filesystem (grep hugetlbfs /proc/filesystems) for getting mmaps backed with hugetlb pages.
For example, there is hugetlbfs_unlinked_fd function of libhugetlbfs/hugeutils.c
https://github.com/libhugetlbfs/libhugetlbfs/blob/e44180072b796c0e28e53c4d01ef6279caaa2a99/hugeutils.c#L1033
int hugetlbfs_unlinked_fd_for_size(long page_size)
{
const char *path;
char name[PATH_MAX+1];
int fd;
path = hugetlbfs_find_path_for_size(page_size);
..
name[sizeof(name)-1] = '\0';
strcpy(name, path);
strncat(name, "/libhugetlbfs.tmp.XXXXXX", sizeof(name)-1);
/* FIXME: deal with overflows */
fd = mkstemp64(name);
....
unlink(name);
return fd;
}
Temporary file name is randomly generated in mkstemp function; it also creates the file and opens it. Then this file is unlinked (man 2 unlink) from the filesystem (file name is marked as deleted in the directory, there is still inode and file data, but other programs can't access this file by name).
While unlinked fd is opened, it can be used to work with hugetlb mmap and to store data. Only when this fd is closed, file data will be actually deleted by fs.
Early unlinking of mktemp files is often used: When a file created with mkstemp() is deleted?
Some useful information can be also listed in HOWTO of libhugetlbfs project
https://github.com/libhugetlbfs/libhugetlbfs/blob/master/HOWTO

Resources