// tgt.h
#ifndef __TGT_H__
#define __TGT_H__
#include <inttypes.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define TGT_IPC_ADDR "/var/run/tgtd.ipc_abstract_namespace"
static int control_port=0; //defualt=3260
enum tgtadm_op {
OP_NEW, //--op new
OP_DELETE, //--op delete
OP_SHOW, //--op show
OP_BIND, //--op bind
OP_UNBIND, //--op unbind
OP_UPDATE, //--op update
OP_STATS, //--op stat
OP_START, //--op start
OP_STOP, //--op stop
};
enum tgtadm_mode {
MODE_SYSTEM, // --mode system
MODE_TARGET, // --mode target
MODE_DEVICE, // --mode logicalunit
MODE_PORTAL, // --mode portal
MODE_LLD, // --mode lld
MODE_SESSION, //--mode session
MODE_CONNECTION,//--mode connection
MODE_ACCOUNT, //--mode account
};
enum tgtadm_errno {
TGTADM_SUCCESS,
TGTADM_UNKNOWN_ERR,
TGTADM_NOMEM,
TGTADM_NO_DRIVER,
TGTADM_NO_TARGET,
TGTADM_NO_LUN,
TGTADM_NO_SESSION,
TGTADM_NO_CONNECTION,
TGTADM_NO_BINDING,
TGTADM_TARGET_EXIST,
TGTADM_LUN_EXIST,
TGTADM_BINDING_EXIST,
TGTADM_ACL_EXIST,
TGTADM_ACL_NOEXIST,
TGTADM_USER_EXIST,
TGTADM_NO_USER,
TGTADM_TOO_MANY_USER,
TGTADM_INVALID_REQUEST,
TGTADM_OUTACCOUNT_EXIST,
TGTADM_TARGET_ACTIVE,
TGTADM_LUN_ACTIVE,
TGTADM_DRIVER_ACTIVE,
TGTADM_UNSUPPORTED_OPERATION,
TGTADM_UNKNOWN_PARAM,
TGTADM_PREVENT_REMOVAL,
};
typedef enum tgtadm_errno tgtadm_err;
struct tgtadm_req {
enum tgtadm_mode mode;
enum tgtadm_op op;
char lld[64];
uint32_t len;
int32_t tid;
uint64_t sid;
uint64_t lun;
uint32_t cid;
uint32_t host_no;
uint32_t device_type;
uint32_t ac_dir;
uint32_t pack;
uint32_t force;
};
struct tgtadm_rsp {
uint32_t err;
uint32_t len;
};
struct concat_buf{
FILE *streamf;
int err;
int used;
char *buf;
size_t size;
};
static const char *tgtadm_strerror(int err)
{
static const struct {
enum tgtadm_errno err;
char *desc;
} errors[] = {
{ TGTADM_SUCCESS, "success" },
{ TGTADM_UNKNOWN_ERR, "unknown error" },
{ TGTADM_NOMEM, "out of memory" },
{ TGTADM_NO_DRIVER, "can't find the driver" },
{ TGTADM_NO_TARGET, "can't find the target" },
{ TGTADM_NO_LUN, "can't find the logical unit" },
{ TGTADM_NO_SESSION, "can't find the session" },
{ TGTADM_NO_CONNECTION, "can't find the connection" },
{ TGTADM_NO_BINDING, "can't find the binding" },
{ TGTADM_TARGET_EXIST, "this target already exists" },
{ TGTADM_BINDING_EXIST, "this binding already exists" },
{ TGTADM_LUN_EXIST, "this logical unit number already exists" },
{ TGTADM_ACL_EXIST, "this access control rule already exists" },
{ TGTADM_ACL_NOEXIST, "this access control rule does not exist" },
{ TGTADM_USER_EXIST, "this account already exists" },
{ TGTADM_NO_USER, "can't find the account" },
{ TGTADM_TOO_MANY_USER, "too many accounts" },
{ TGTADM_INVALID_REQUEST, "invalid request" },
{ TGTADM_OUTACCOUNT_EXIST, "this target already has an outgoing account" },
{ TGTADM_TARGET_ACTIVE, "this target is still active" },
{ TGTADM_LUN_ACTIVE, "this logical unit is still active" },
{ TGTADM_DRIVER_ACTIVE, "this driver is busy" },
{ TGTADM_UNSUPPORTED_OPERATION, "this operation isn't supported" },
{ TGTADM_UNKNOWN_PARAM, "unknown parameter" },
{ TGTADM_PREVENT_REMOVAL, "this device has Prevent Removal set" }
};
int i;
for (i = 0; i < ARRAY_SIZE(errors); ++i)
if (errors[i].err == err)
return errors[i].desc;
return "(unknown tgtadm_errno)";
}
#endif
//tgt.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "tgt.h"
const char* LLD="iscsi";
void concat_buf_init(struct concat_buf *b){
b->streamf=open_memstream(&b->buf,&b->size);
b->err=b->streamf?0:errno;
b->used=0;
}
int concat_printf(struct concat_buf *b,const char*format,...){
va_list args;
int nprinted;
if(!b->err){
va_start(args,format);
nprinted=vfprintf(b->streamf,format,args);
if(nprinted>=0)
b->used += nprinted;
else{
b->err=nprinted;
fclose(b->streamf);
b->streamf =NULL;
}
va_end(args);
}
return b->err;
}
int concat_buf_finish(struct concat_buf *b){
if(b->streamf){
fclose(b->streamf);
b->streamf=NULL;
if(b->size)
b->size++; //account for trailing NULL char
}
return b->err;
}
int concat_write(struct concat_buf *b, int fd, int offset)
{
concat_buf_finish(b);
if (b->err) {
errno = b->err;
return -1;
}
if (b->size - offset > 0)
return write(fd, b->buf + offset, b->size - offset);
else {
errno = EINVAL;
return -1;
}
}
void concat_buf_release(struct concat_buf *b)
{
concat_buf_finish(b);
if (b->buf) {
free(b->buf);
memset(b, 0, sizeof(*b));
}
}
int tgt_mgmt_connect(int *fd){
int ret;
struct sockaddr_un addr;
char mgmt_path[256];
*fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (*fd < 0) {
printf("can't create a socket!\n");
return errno;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_LOCAL;
sprintf(mgmt_path, "%s.%d", TGT_IPC_ADDR, control_port);
strncpy(addr.sun_path, mgmt_path, sizeof(addr.sun_path));
ret = connect(*fd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0)
return errno;
return 0;
}
int tgt_mgmt_rsp(int fd,struct tgtadm_req *req){
struct tgtadm_rsp rsp;
int ret,rest,len;
retry:
ret=recv(fd,&rsp,sizeof(rsp),MSG_WAITALL);
if(ret<0){
if(errno==EAGAIN) goto retry;
else if(errno==EINTR)
printf("interrupted by a signal!\n");
else
printf("can't get the response!\n");
return errno;
}else if(ret==0){
printf("tgtd closed the socket!\n");
return 0;
}else if(ret!=sizeof(rsp)){
printf("a partial response!\n");
return 0;
}
if(rsp.err!=0){
printf("%s!\n",tgtadm_strerror(rsp.err));
return EINVAL;
}
rest=rsp.len-sizeof(rsp);
if(!rest) return 0;
while(rest){
char buf[4096];
memset(buf,0,sizeof(buf));
len=sizeof(buf)-1;
len=(len<rest?len:rest);
ret=read(fd,buf,len);
if(ret<=0){
printf("\ncan't get the full response!\n");
return errno;
}
fputs(buf,stdout);
rest-=len;
}
return 0;
}
int tgt_mgmt_req(struct tgtadm_req *req,struct concat_buf*b){
int ret,fd=0,done=0;
req->len=sizeof(*req)+b->size;
ret=tgt_mgmt_connect(&fd);
if(ret<0){
printf("can't connect to tgt daemon !\n");
goto out;
}
ret=write(fd,req,sizeof(*req));
if(ret<0||ret!=sizeof(*req)){
printf("failed to send request hdr to tgt daemon!\n");
ret=errno;
goto out;
}
while(done<b->size){
ret=concat_write(b,fd,done);
if(ret>0)
done+=ret;
else if(errno!=EAGAIN){
printf("failed to send request buf to tgt daemon!\n");
ret=errno;
goto out;
}
}
printf("send to tgtd %d!\n",req->len);
ret=tgt_mgmt_rsp(fd,req);
out:
if(fd>0) close(0);
concat_buf_release(b);
return ret;
}
int tgt_create_tgt(int tid,char *tgtname){
struct tgtadm_req adm_req={0},*req=&adm_req;
struct concat_buf b;
int ret;
strcpy(req->lld,LLD);//default
req->mode=1; //MODE_TARGET
req->op=0; //OP_NEW
req->tid=tid;
req->sid=req->cid=req->host_no=0;//default
req->lun=-1; //default
req->device_type=0; //default TYPE_DISK
req->ac_dir=0; //default 1=outgoing
req->pack=0; //default
req->force=0; //default 1=force
concat_buf_init(&b);
concat_printf(&b,"targetname=%s",tgtname);
ret=concat_buf_finish(&b);
if(ret){
printf("failed to create request,errno:%d\n",ret);
exit(ret);
}
ret=tgt_mgmt_req(req,&b);
return ret;
}
int tgt_delete_tgt(int tid){
struct tgtadm_req adm_req={0},*req=&adm_req;
struct concat_buf b;
int ret;
strcpy(req->lld,LLD);//default
req->mode=1; //MODE_TARGET
req->op=1; //OP_DELETE
req->tid=tid;
req->sid=req->cid=req->host_no=0;//default
req->lun=-1; //default
req->device_type=req->ac_dir=req->pack=req->force=0; //default
concat_buf_init(&b);
ret=concat_buf_finish(&b);
if(ret){
printf("failed to create request,errno:%d\n",ret);
exit(ret);
}
ret=tgt_mgmt_req(req,&b);
return ret;
}
int tgt_add_lun(int tid,int lunid,char *lunname){
struct tgtadm_req adm_req={0},*req=&adm_req;
struct concat_buf b;
int ret;
strcpy(req->lld,LLD);//default
req->mode=2; //MODE_DEVICE --mode logicalunit
req->op=0; //OP_NEW
req->tid=tid;
req->sid=req->cid=req->host_no=0;//default
req->lun=lunid; //default
req->device_type=req->ac_dir=req->pack=req->force=0; //default
concat_buf_init(&b);
concat_printf(&b,"path=%s",lunname);
ret=concat_buf_finish(&b);
if(ret){
printf("failed to create request,errno:%d\n",ret);
exit(ret);
}
ret=tgt_mgmt_req(req,&b);
return ret;
}
int tgt_del_lun(int tid,int lunid){
struct tgtadm_req adm_req={0},*req=&adm_req;
struct concat_buf b;
int ret;
strcpy(req->lld,LLD);//default
req->mode=2; //MODE_DEVICE --mode logicalunit
req->op=1; //OP_DELETE
req->tid=tid;
req->sid=req->cid=req->host_no=0;//default
req->lun=lunid; //default
req->device_type=req->ac_dir=req->pack=req->force=0; //default
concat_buf_init(&b);
ret=concat_buf_finish(&b);
if(ret){
printf("failed to create request,errno:%d\n",ret);
exit(ret);
}
ret=tgt_mgmt_req(req,&b);
return ret;
}
int tgt_bind_initiator(int tid,int type,char*init_name){
struct tgtadm_req adm_req={0},*req=&adm_req;
struct concat_buf b;
int ret;
strcpy(req->lld,LLD);//default
req->mode=1; //MODE_TARGET
req->op=3; //OP_BIND
req->tid=tid;
req->sid=req->cid=req->host_no=0;//default
req->lun=-1; //default
req->device_type=req->ac_dir=req->pack=req->force=0; //default
concat_buf_init(&b);
if(type==1){
concat_printf(&b,"initiator-address=%s",init_name);
}else if(type==0){
concat_printf(&b,"initiator-name=%s",init_name);
}else{
printf("type error: \n");
}
ret=concat_buf_finish(&b);
if(ret){
printf("failed to create request,errno:%d\n",ret);
exit(ret);
}
ret=tgt_mgmt_req(req,&b);
return ret;
}
int tgt_unbind_initiator(int tid,int type,char*init_name){
struct tgtadm_req adm_req={0},*req=&adm_req;
struct concat_buf b;
int ret;
strcpy(req->lld,LLD); //default
req->mode=1; //MODE_TARGET
req->op=4; //OP_BIND
req->tid=tid;
req->sid=req->cid=req->host_no=0;//default
req->lun=-1; //default
req->device_type=req->ac_dir=req->pack=req->force=0; //default
concat_buf_init(&b);
if(type==1){
concat_printf(&b,"initiator-address=%s",init_name);
}else if(type==0){
concat_printf(&b,"initiator-name=%s",init_name);
}else{
printf("type error: \n");
}
ret=concat_buf_finish(&b);
if(ret){
printf("failed to create request,errno:%d\n",ret);
exit(ret);
}
ret=tgt_mgmt_req(req,&b);
return ret;
}
int tgt_show_tgt(int tid){
struct tgtadm_req adm_req={0},*req=&adm_req;
struct concat_buf b;
int ret;
strcpy(req->lld,LLD); //default
req->mode=1; //MODE_TARGET
req->op=2; //OP_SHOW
req->tid=tid?tid:-1; // 0=ALL
req->sid=req->cid=req->host_no=0;//default
req->lun=-1; //default
req->device_type=req->ac_dir=req->pack=req->force=0; //default
concat_buf_init(&b);
ret=concat_buf_finish(&b);
if(ret){
printf("failed to create request,errno:%d\n",ret);
exit(ret);
}
ret=tgt_mgmt_req(req,&b);
return ret;
}
int main(int argc,char*argv[]){
//tgt_show_tgt(0);
//tgt_create_tgt(2,"guoming");
//tgt_add_lun(2,1,"/dev/sdb3");
//tgt_bind_initiator(1,1,"192.168.1.0/24");
//tgt_unbind_initiator(1,1,"ALL");
tgt_unbind_initiator(1,1,"192.168.1.180");
tgt_bind_initiator(1,0,"cgm88s");
//tgt_del_lun(2,1);
//tgt_delete_tgt(2);
}