/*
* Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <inttypes.h>
#include <stdint.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#ifdef HAVE_LIBPTHREAD
#include <pthread.h>
#endif
#ifdef HAVE_SCHED
#include <sched.h>
#endif
#include "istgt.h"
#include "istgt_misc.h"
#if !defined(__GNUC__)
#undef __attribute__
#define __attribute__(x)
#endif
static void fatal(const char *format, ...) __attribute__((__noreturn__, __format__(__printf__, 1, 2)));
static void
fatal(const char *format, ...)
{
char buf[MAX_TMPBUF];
va_list ap;
va_start(ap, format);
vsnprintf(buf, sizeof buf, format, ap);
fprintf(stderr, "%s", buf);
syslog(LOG_ERR, "%s", buf);
va_end(ap);
exit(EXIT_FAILURE);
}
void *
xmalloc(size_t size)
{
void *p;
if (size < 1)
size = 1;
p = malloc(size);
if (p == NULL)
fatal("no memory\n");
return p;
}
void *
xrealloc(void *p, size_t size)
{
if (size < 1)
size = 1;
if (p == NULL) {
p = malloc(size);
} else {
p = realloc(p, size);
}
if (p == NULL)
fatal("no memory\n");
return p;
}
void
xfree(void *p)
{
if (p == NULL)
return;
free(p);
}
char *
xstrdup(const char *s)
{
char *p;
size_t size;
if (s == NULL)
return NULL;
size = strlen(s) + 1;
p = xmalloc(size);
memcpy(p, s, size - 1);
p[size - 1] = '\0';
return p;
}
char *
strlwr(char *s)
{
char *p;
if (s == NULL)
return NULL;
p = s;
while (*p != '\0') {
*p = tolower((int) *p);
p++;
}
return s;
}
char *
strupr(char *s)
{
char *p;
if (s == NULL)
return NULL;
p = s;
while (*p != '\0') {
*p = toupper((int) *p);
p++;
}
return s;
}
char *
strsepq(char **stringp, const char *delim)
{
char *p, *q, *r;
int quoted = 0, bslash = 0;
p = *stringp;
if (p == NULL)
return NULL;
r = q = p;
while (*q != '\0' && *q != '\n') {
/* eat quoted characters */
if (bslash) {
bslash = 0;
*r++ = *q++;
continue;
} else if (quoted) {
if (quoted == '"' && *q == '\\') {
bslash = 1;
q++;
continue;
} else if (*q == quoted) {
quoted = 0;
q++;
continue;
}
*r++ = *q++;
continue;
} else if (*q == '\\') {
bslash = 1;
q++;
continue;
} else if (*q == '"' || *q == '\'') {
quoted = *q;
q++;
continue;
}
/* separator? */
if (strchr(delim, (int) *q) == NULL) {
*r++ = *q++;
continue;
}
/* new string */
q++;
break;
}
*r = '\0';
/* skip tailer */
while (*q != '\0' && strchr(delim, (int) *q) != NULL) {
q++;
}
if (*q != '\0') {
*stringp = q;
} else {
*stringp = NULL;
}
return p;
}
char *
trim_string(char *s)
{
char *p, *q;
if (s == NULL)
return NULL;
/* remove header */
p = s;
while (*p != '\0' && isspace((int) *p)) {
p++;
}
/* remove tailer */
q = p + strlen(p);
while (q - 1 >= p && isspace((int) *(q - 1))) {
q--;
*q = '\0';
}
/* if remove header, move */
if (p != s) {
q = s;
while (*p != '\0') {
*q++ = *p++;
}
}
return s;
}
char *
escape_string(const char *s)
{
const char *p;
char *q, *r;
size_t size;
if (s == NULL)
return NULL;
p = s;
size = 0;
while (*p != '\0') {
if (*p == '"' || *p == '\\' || *p == '\'') {
size += 2;
} else {
size++;
}
p++;
}
p = s;
r = q = xmalloc(size + 1);
while (*p != '\0') {
if (*p == '"' || *p == '\\' || *p == '\'') {
*q++ = '\\';
*q++ = *p++;
} else {
*q++ = *p++;
}
}
*q++ = '\0';
return r;
}
/* LBA = (M * 60 + S) * 75 + F - 150 */
uint32_t
istgt_msf2lba(uint32_t msf)
{
uint32_t lba;
lba = ((msf >> 16) & 0xff) * 60 * 75;
lba += ((msf >> 8) & 0xff) * 75;
lba += msf & 0xff;
lba -= 150;
return lba;
}
uint32_t
istgt_lba2msf(uint32_t lba)
{
uint32_t m, s, f;
lba += 150;
m = (lba / 75) / 60;
s = (lba / 75) % 60;
f = lba % 75;
return ((m << 16) | (s << 8) | f);
}
uint8_t
istgt_dget8(const uint8_t *data)
{
uint8_t value;
value = (data[0] & 0xffU) << 0;
return value;
}
void
istgt_dset8(uint8_t *data, uint32_t value)
{
data[0] = (value >> 0) & 0xffU;
}
uint16_t
istgt_dget16(const uint8_t *data)
{
uint16_t value;
value = (data[0] & 0xffU) << 8;
value |= (data[1] & 0xffU) << 0;
return value;
}
void
istgt_dset16(uint8_t *data, uint32_t value)
{
data[0] = (value >> 8) & 0xffU;
data[1] = (value >> 0) & 0xffU;
}
uint32_t
istgt_dget24(const uint8_t *data)
{
uint32_t value;
value = (data[0] & 0xffU) << 16;
value |= (data[1] & 0xffU) << 8;
value |= (data[2] & 0xffU) << 0;
return value;
}
void
istgt_dset24(uint8_t *data, uint32_t value)
{
data[0] = (value >> 16) & 0xffU;
data[1] = (value >> 8) & 0xffU;
data[2] = (value >> 0) & 0xffU;
}
uint32_t
istgt_dget32(const uint8_t *data)
{
uint32_t value;
value = (data[0] & 0xffU) << 24;
value |= (data[1] & 0xffU) << 16;
value |= (data[2] & 0xffU) << 8;
value |= (data[3] & 0xffU) << 0;
return value;
}
void
istgt_dset32(uint8_t *data, uint32_t value)
{
data[0] = (value >> 24) & 0xffU;
data[1] = (value >> 16) & 0xffU;
data[2] = (value >> 8) & 0xffU;
data[3] = (value >> 0) & 0xffU;
}
uint64_t
istgt_dget48(const uint8_t *data)
{
uint64_t value;
value = (data[0] & 0xffULL) << 40;
value |= (data[1] & 0xffULL) << 32;
value |= (data[2] & 0xffULL) << 24;
value |= (data[3] & 0xffULL) << 16;
value |= (data[4] & 0xffULL) << 8;
value |= (data[5] & 0xffULL) << 0;
return value;
}
void
istgt_dset48(uint8_t *data, uint64_t value)
{
data[0] = (value >> 40) & 0xffULL;
data[1] = (value >> 32) & 0xffULL;
data[2] = (value >> 24) & 0xffULL;
data[3] = (value >> 16) & 0xffULL;
data[4] = (value >> 8) & 0xffULL;
data[5] = (value >> 0) & 0xffULL;
}
uint64_t
istgt_dget64(const uint8_t *data)
{
uint64_t value;
value = (data[0] & 0xffULL) << 56;
value |= (data[1] & 0xffULL) << 48;
value |= (data[2] & 0xffULL) << 40;
value |= (data[3] & 0xffULL) << 32;
value |= (data[4] & 0xffULL) << 24;
value |= (data[5] & 0xffULL) << 16;
value |= (data[6] & 0xffULL) << 8;
value |= (data[7] & 0xffULL) << 0;
return value;
}
void
istgt_dset64(uint8_t *data, uint64_t value)
{
data[0] = (value >> 56) & 0xffULL;
data[1] = (value >> 48) & 0xffULL;
data[2] = (value >> 40) & 0xffULL;
data[3] = (value >> 32) & 0xffULL;
data[4] = (value >> 24) & 0xffULL;
data[5] = (value >> 16) & 0xffULL;
data[6] = (value >> 8) & 0xffULL;
data[7] = (value >> 0) & 0xffULL;
}
void
istgt_dump(const char *label, const uint8_t *buf, size_t len)
{
istgt_fdump(stdout, label, buf, len);
}
void
istgt_fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len)
{
char tmpbuf[MAX_TMPBUF];
char buf8[8+1];
size_t total;
size_t idx;
fprintf(fp, "%s\n", label);
memset(buf8, 0, sizeof buf8);
total = 0;
for (idx = 0; idx < len; idx++) {
if (idx != 0 && idx % 8 == 0) {
total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
"%s", buf8);
fprintf(fp, "%s\n", tmpbuf);
total = 0;
}
total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
"%2.2x ", buf[idx] & 0xff);
buf8[idx % 8] = isprint(buf[idx]) ? buf[idx] : '.';
}
for ( ; idx % 8 != 0; idx++) {
total += snprintf(tmpbuf + total, sizeof tmpbuf - total, " ");
buf8[idx % 8] = ' ';
}
total += snprintf(tmpbuf + total, sizeof tmpbuf - total, "%s", buf8);
fprintf(fp, "%s\n", tmpbuf);
fflush(fp);
}
#ifndef HAVE_SRANDOMDEV
#include <time.h>
void
srandomdev(void)
{
unsigned long seed;
time_t now;
pid_t pid;
pid = getpid();
now = time(NULL);
seed = pid ^ now;
srandom(seed);
}
#endif /* HAVE_SRANDOMDEV */
#ifndef HAVE_ARC4RANDOM
static int istgt_arc4random_initialized = 0;
uint32_t
arc4random(void)
{
uint32_t r;
uint32_t r1, r2;
if (!istgt_arc4random_initialized) {
srandomdev();
istgt_arc4random_initialized = 1;
}
r1 = (uint32_t) (random() & 0xffff);
r2 = (uint32_t) (random() & 0xffff);
r = (r1 << 16) | r2;
return r;
}
#endif /* HAVE_ARC4RANDOM */
void
istgt_gen_random(uint8_t *buf, size_t len)
{
#ifdef USE_RANDOM
long l;
size_t idx;
srandomdev();
for (idx = 0; idx < len; idx++) {
l = random();
buf[idx] = (uint8_t) l;
}
#else
uint32_t r;
size_t idx;
for (idx = 0; idx < len; idx++) {
r = arc4random();
buf[idx] = (uint8_t) r;
}
#endif /* USE_RANDOM */
}
int
istgt_bin2hex(char *buf, size_t len, const uint8_t *data, size_t data_len)
{
const char *digits = "0123456789ABCDEF";
size_t total = 0;
size_t idx;
if (len < 3)
return -1;
buf[total] = '0';
total++;
buf[total] = 'x';
total++;
buf[total] = '\0';
for (idx = 0; idx < data_len; idx++) {
if (total + 3 > len) {
buf[total] = '\0';
return - 1;
}
buf[total] = digits[(data[idx] >> 4) & 0x0fU];
total++;
buf[total] = digits[data[idx] & 0x0fU];
total++;
}
buf[total] = '\0';
return total;
}
int
istgt_hex2bin(uint8_t *data, size_t data_len, const char *str)
{
const char *digits = "0123456789ABCDEF";
const char *dp;
const char *p;
size_t total = 0;
int n0, n1;
p = str;
if (p[0] != '0' && (p[1] != 'x' && p[1] != 'X'))
return -1;
p += 2;
while (p[0] != '\0' && p[1] != '\0') {
if (total >= data_len) {
return -1;
}
dp = strchr(digits, toupper((int) p[0]));
if (dp == NULL) {
return -1;
}
n0 = (int) (dp - digits);
dp = strchr(digits, toupper((int) p[1]));
if (dp == NULL) {
return -1;
}
n1 = (int) (dp - digits);
data[total] = (uint8_t) (((n0 & 0x0fU) << 4) | (n1 & 0x0fU));
total++;
p += 2;
}
return total;
}
void
istgt_yield(void)
{
#if defined (HAVE_PTHREAD_YIELD)
pthread_yield();
#elif defined (HAVE_SCHED_YIELD)
sched_yield();
#else
usleep(0);
#endif
}
#ifndef HAVE_STRLCPY
size_t
strlcpy(char *dst, const char *src, size_t size)
{
size_t len;
if (dst == NULL)
return 0;
if (size < 1) {
return 0;
}
len = strlen(src);
if (len > size - 1) {
len = size - 1;
}
memcpy(dst, src, len);
dst[len] = '\0';
return len;
}
#endif /* HAVE_STRLCPY */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>