#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <libgen.h>
#include <string.h>
#include <inttypes.h>
#include <err.h>
#include "common.h"
#include "output.h"
#include <libpmemlog.h>
#include <libpmemblk.h>
#include "mmap.h"
#include "queue.h"
struct pmemwrite
{
char *fname;
int nargs;
char **args;
};
static struct pmemwrite pmemwrite = {
.fname = NULL,
.nargs = 0,
.args = NULL,
};
static void
print_usage(char *appname)
{
printf("Usage: %s <file> <args>...\n", appname);
printf("Valid arguments:\n");
printf("<blockno>:w:<string> - write <string> to <blockno> block\n");
printf("<blockno>:z - set zero flag on <blockno> block\n");
printf("<blockno>:z - set error flag on <blockno> block\n");
}
static int
pmemwrite_log(struct pmemwrite *pwp)
{
PMEMlogpool *plp = pmemlog_open(pwp->fname);
if (!plp) {
warn("%s", pwp->fname);
return -1;
}
int i;
int ret = 0;
for (i = 0; i < pwp->nargs; i++) {
size_t len = strlen(pwp->args[i]);
if (pmemlog_append(plp, pwp->args[i], len)) {
warn("%s", pwp->fname);
ret = -1;
break;
}
}
pmemlog_close(plp);
return ret;
}
static int
pmemwrite_blk(struct pmemwrite *pwp)
{
PMEMblkpool *pbp = pmemblk_open(pwp->fname, 0);
if (!pbp) {
warn("%s", pwp->fname);
return -1;
}
int i;
int ret = 0;
size_t blksize = pmemblk_bsize(pbp);
char *blk = malloc(blksize);
if (!blk) {
ret = -1;
outv_err("malloc(%lu) failed\n", blksize);
goto nomem;
}
for (i = 0; i < pwp->nargs; i++) {
int64_t blockno;
char *buff;
size_t buffsize = strlen(pwp->args[i]) + 1;
buff = malloc(buffsize);
if (buff == NULL) {
ret = -1;
outv_err("malloc(%lu) failed\n", buffsize);
goto end;
}
char flag;
if (sscanf(pwp->args[i], "%" SCNi64 ":w:%[^:]",
&blockno, buff) == 2) {
memset(blk, 0, blksize);
size_t bufflen = strlen(buff);
if (bufflen == 0) {
free(buff);
goto end;
}
if (bufflen > blksize) {
outv_err("String is longer than block size. "
"Truncating.\n");
bufflen = blksize;
}
memcpy(blk, buff, bufflen);
ret = pmemblk_write(pbp, blk, blockno);
free(buff);
if (ret)
goto end;
} else if (sscanf(pwp->args[i], "%" SCNi64 ":%c",
&blockno, &flag) == 2) {
free(buff);
switch (flag) {
case 'z':
ret = pmemblk_set_zero(pbp, blockno);
break;
case 'e':
ret = pmemblk_set_error(pbp, blockno);
break;
default:
outv_err("Invalid flag '%c'\n", flag);
ret = -1;
goto end;
}
if (ret) {
warn("%s", pwp->fname);
goto end;
}
} else {
free(buff);
outv_err("Invalid argument '%s'\n", pwp->args[i]);
ret = -1;
goto end;
}
}
end:
free(blk);
nomem:
pmemblk_close(pbp);
return ret;
}
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]);
outv_err("Error during arguments conversion\n");
return 1;
}
}
#endif
int opt;
int ret = 0;
util_init();
char *appname = basename(argv[0]);
while ((opt = getopt(argc, argv, "h")) != -1) {
switch (opt) {
case 'h':
print_usage(appname);
ret = 0;
goto end;
default:
print_usage(appname);
ret = 1;
goto end;
}
}
if (optind + 1 < argc) {
pmemwrite.fname = argv[optind];
optind++;
pmemwrite.nargs = argc - optind;
pmemwrite.args = &argv[optind];
} else {
print_usage(appname);
ret = 1;
goto end;
}
out_set_vlevel(1);
struct pmem_pool_params params;
pmem_pool_parse_params(pmemwrite.fname, ¶ms, 1);
switch (params.type) {
case PMEM_POOL_TYPE_BLK:
ret = pmemwrite_blk(&pmemwrite);
break;
case PMEM_POOL_TYPE_LOG:
ret = pmemwrite_log(&pmemwrite);
break;
default:
ret = 1;
}
end:
#ifdef _WIN32
for (int i = argc; i > 0; i--)
free(argv[i - 1]);
#endif
return ret;
}