sane_close/sane_exit doesn't free all used pipe/timer_fd if we loop use sane_close /sane_ext without exiting program.
Sample code as below to loop use sane api without exiting program will lead to too many opened files error.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sane/sane.h>
#include <sane/saneopts.h>
void print_option_values(SANE_Handle device) {
SANE_Int num_options;
SANE_Status status;
// Get the number of options available for the device
status = sane_control_option(device, 0, SANE_ACTION_GET_VALUE, &num_options, NULL);
if (status != SANE_STATUS_GOOD) {
fprintf(stderr, "Failed to get number of options: %s\n", sane_strstatus(status));
return;
}
printf("Device has %d options:\n", num_options);
// Iterate through all options
for (SANE_Int opt = 1; opt < num_options; opt++) {
const SANE_Option_Descriptor *desc = sane_get_option_descriptor(device, opt);
if (!desc) {
fprintf(stderr, "Option %d has no descriptor.\n", opt);
continue;
}
printf("Option %d: %s (%s)\n", opt, desc->name ? desc->name : "Unnamed", desc->title ? desc->title : "No title");
if (!(desc->cap & SANE_CAP_INACTIVE)) { // Skip inactive options
char value_buffer[1024] = {0}; // Adjust buffer size as needed
status = sane_control_option(device, opt, SANE_ACTION_GET_VALUE, value_buffer, NULL);
if (status == SANE_STATUS_GOOD) {
switch (desc->type) {
case SANE_TYPE_BOOL:
printf(" Value: %s\n", (*(SANE_Bool *)value_buffer) ? "True" : "False");
break;
case SANE_TYPE_INT:
printf(" Value: %d\n", *(SANE_Int *)value_buffer);
break;
case SANE_TYPE_FIXED:
printf(" Value: %.2f\n", SANE_UNFIX(*(SANE_Fixed *)value_buffer));
break;
case SANE_TYPE_STRING:
printf(" Value: %s\n", value_buffer);
break;
default:
printf(" Value: Unknown type\n");
break;
}
} else {
fprintf(stderr, " Failed to get value: %s\n", sane_strstatus(status));
}
} else {
printf(" Option is inactive.\n");
}
}
}
int main() {
for (int iteration = 0; iteration < 1000; iteration++) { // Replace with a suitable termination condition
printf("\nIteration %d: Initializing SANE...\n", iteration + 1);
SANE_Status status;
SANE_Int version_code;
const SANE_Device **device_list;
// Initialize SANE
status = sane_init(&version_code, NULL);
if (status != SANE_STATUS_GOOD) {
fprintf(stderr, "Failed to initialize SANE: %s\n", sane_strstatus(status));
return 1;
}
printf("SANE initialized. Version: %d.%d.%d\n",
SANE_VERSION_MAJOR(version_code),
SANE_VERSION_MINOR(version_code),
SANE_VERSION_BUILD(version_code));
// Get the list of devices
status = sane_get_devices(&device_list, SANE_FALSE);
if (status != SANE_STATUS_GOOD) {
fprintf(stderr, "Failed to get device list: %s\n", sane_strstatus(status));
sane_exit();
sleep(1);
continue; // Retry in the next iteration
}
if (!device_list || !device_list[0]) {
fprintf(stderr, "No devices found.\n");
sane_exit();
sleep(5);
continue; // Retry in the next iteration
}
printf("Using device: %s (%s)\n", device_list[0]->name, device_list[0]->vendor);
// Open the first available device
SANE_Handle device;
status = sane_open(device_list[0]->name, &device);
if (status != SANE_STATUS_GOOD) {
fprintf(stderr, "Failed to open device: %s\n", sane_strstatus(status));
sane_exit();
sleep(5);
continue; // Retry in the next iteration
}
// Fetch and print all option values
print_option_values(device);
// Close the device and cleanup
sane_close(device);
sane_exit();
// Wait for 5 seconds before the next iteration
sleep(5);
}
return 0;
}
Check program with lsof will find that a lot new pipe/timefd related fp added.
Did we free all used resources on sane_close/sane_exit which is added mainly around sane_get_devices api.
Edited by darren qiao