#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include "mmap.h"
#include "libpmem.h"
#include "file.h"
#include "os.h"
#define SIZE 4096
#define DEVDAX_DETECT (1 << 0)
#define DEVDAX_ALIGN (1 << 1)
static int Opts;
static char *Path;
static size_t Align;
static void
print_usage(void)
{
printf("Usage: pmemdetect [options] path\n");
printf("Valid options:\n");
printf("-d, --devdax - check if path is Device DAX\n");
printf("-a, --align=N - check Device DAX alignment\n");
printf("-h, --help - print this usage info\n");
}
static const struct option long_options[] = {
{"devdax", no_argument, NULL, 'd'},
{"align", required_argument, NULL, 'a'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0 },
};
static int
parse_args(int argc, char *argv[])
{
int opt;
while ((opt = getopt_long(argc, argv, "a:dh",
long_options, NULL)) != -1) {
switch (opt) {
case 'd':
Opts |= DEVDAX_DETECT;
break;
case 'a':
Opts |= DEVDAX_ALIGN;
char *endptr;
errno = 0;
size_t align = strtoull(optarg, &endptr, 0);
if ((endptr && *endptr != '\0') || errno) {
fprintf(stderr, "'%s' -- invalid alignment",
optarg);
return -1;
}
Align = (size_t)align;
break;
case 'h':
print_usage();
exit(EXIT_SUCCESS);
default:
print_usage();
exit(EXIT_FAILURE);
}
}
if (optind < argc) {
Path = argv[optind];
} else {
print_usage();
exit(EXIT_FAILURE);
}
return 0;
}
static int
is_pmem(const char *path)
{
int ret;
void *addr = util_map_tmpfile(path, SIZE, 0);
if (addr == NULL) {
fprintf(stderr, "file creation failed\n");
return -1;
}
if (pmem_is_pmem(addr, SIZE))
ret = 1;
else
ret = 0;
util_unmap(addr, SIZE);
return ret;
}
static int
is_dev_dax(const char *path)
{
if (os_access(path, W_OK|R_OK)) {
printf("%s -- permission denied\n", path);
return -1;
}
if (!util_file_is_device_dax(path)) {
printf("%s -- not device dax\n", path);
return 0;
}
return 1;
}
static int
is_dev_dax_align(const char *path, size_t req_align)
{
if (is_dev_dax(path) != 1)
return -1;
size_t align = util_file_device_dax_alignment(path);
return (req_align == align) ? 1 : 0;
}
int
main(int argc, char *argv[])
{
#ifdef _WIN32
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
for (int i = 0; i < argc; i++) {
argv[i] = util_toUTF8(wargv[i]);
if (argv[i] == NULL) {
for (i--; i >= 0; i--)
free(argv[i]);
fprintf(stderr, "Error during arguments conversion\n");
return 2;
}
}
#endif
int ret;
if (parse_args(argc, argv)) {
ret = 2;
goto out;
}
util_init();
util_mmap_init();
if (Opts & DEVDAX_DETECT)
ret = is_dev_dax(Path);
else if (Opts & DEVDAX_ALIGN)
ret = is_dev_dax_align(Path, Align);
else
ret = is_pmem(Path);
switch (ret) {
case 0:
ret = 1;
break;
case 1:
ret = 0;
break;
default:
ret = 2;
break;
}
util_mmap_fini();
out:
#ifdef _WIN32
for (int i = argc; i > 0; i--)
free(argv[i - 1]);
#endif
return ret;
}