c858e9b6 |
/*
* msync.c |
83cbbef8 |
* Copyright (C) 2008-2012 KLab Inc. |
c858e9b6 |
*/ |
a0346c4a |
#include "makuosan.h"
|
05348f1d |
typedef struct msyncdata
{
int s; /* */
int loopflag; /* */
int loglevel; /* */
int sendflag; /* */
int delflag; /* */
int grpflag; /* */
char scfile[256]; /* */
char passwd[256]; /* */
char target[256]; /* */
char mcmd[256]; /* */
char mopt[256]; /* */
char sopt[256]; /* */
char path[PATH_MAX]; /* */
excludeitem *exclude; /* */
} msyncdata; |
1f4b3de7 |
|
f5b6f77b |
void version() |
1f4b3de7 |
{ |
a0346c4a |
printf("msync version %s (CLI for makuosan)\n", PACKAGE_VERSION); |
f5b6f77b |
}
void usage()
{
version(); |
a0346c4a |
printf("usage: msync [OPTION] [FILENAME]\n");
printf("\n");
printf(" OPTION\n");
printf(" --status # show makuosan status\n");
printf(" --members # show makuosan members\n");
printf(" --check # file check use md5\n"); |
3eaafa57 |
printf(" --delete # \n"); |
7ec57664 |
printf(" --sync # \n"); |
a0346c4a |
printf(" --exclude=PATTERN # \n");
printf(" --exclude-from=FILE # \n");
printf("\n");
printf(" -l LOGLEVEL(0-9) # log level select. default=0\n");
printf(" -c MSYNC_TARGET # \n");
printf(" -f SCRIPT_FILE # \n");
printf(" -t HOSTNAME # distnation hostname\n");
printf(" -v # log level increment\n");
printf(" -n # dry run\n");
printf(" -r # recurse into directories\n"); |
1f4b3de7 |
printf("\n"); |
a0346c4a |
printf(" MSYNC_TARGET\n");
printf(" tcp:HOST:PORT ex) tcp:127.0.0.1:5000\n");
printf(" unix:SOCKET ex) unix:makuosan.sock\n");
printf("\n");
printf(" SCRIPT_FILE\n");
printf(" (It writes later)\n"); |
1f4b3de7 |
printf("\n"); |
a0346c4a |
}
|
05348f1d |
excludeitem *add_exclude(msyncdata *md, char *pattern) |
a0346c4a |
{
excludeitem *item = malloc(sizeof(excludeitem));
item->pattern = malloc(strlen(pattern) + 1);
strcpy(item->pattern, pattern); |
af8d11e0 |
item->prev = NULL;
item->next = NULL; |
05348f1d |
if(md->exclude){
md->exclude->prev = item;
item->next = md->exclude; |
a0346c4a |
} |
05348f1d |
md->exclude = item; |
a0346c4a |
return(item); |
1f4b3de7 |
}
|
c858e9b6 |
int connect_socket_tcp(char *host, char *port) |
1f4b3de7 |
{ |
c858e9b6 |
int s;
struct addrinfo hint;
struct addrinfo *res;
if(!host || !port){ |
1f4b3de7 |
return(-1);
} |
c858e9b6 |
memset(&hint, 0, sizeof(struct addrinfo)); |
37d3fc2b |
hint. ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP; |
c858e9b6 |
if(getaddrinfo(host, port, &hint, &res)){ |
1f4b3de7 |
return(-1);
} |
c858e9b6 |
if(!res){ |
1f4b3de7 |
return(-1);
} |
c858e9b6 |
s = socket(AF_INET, SOCK_STREAM, 0);
if(s == -1){
freeaddrinfo(res);
return(-1); |
1f4b3de7 |
} |
c858e9b6 |
if(connect(s, res->ai_addr, res->ai_addrlen) == -1){
freeaddrinfo(res); |
1f4b3de7 |
close(s);
return(-1);
} |
c858e9b6 |
freeaddrinfo(res); |
1f4b3de7 |
return(s);
}
|
c858e9b6 |
int connect_socket_unix(char *path) |
1f4b3de7 |
{ |
c858e9b6 |
int s; |
1f4b3de7 |
struct sockaddr_un sa; |
c858e9b6 |
if(!path){
return(-1);
}
if(strlen(path) >= sizeof(sa.sun_path)){
return(-1);
}
s = socket(AF_UNIX, SOCK_STREAM, 0);
if(s == -1){
return(-1);
}
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path,path);
if(connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1){
close(s);
return(-1); |
1f4b3de7 |
}
return(s);
}
int connect_socket(char *target)
{ |
c858e9b6 |
char *h;
char *p; |
1f4b3de7 |
char buff[256];
strcpy(buff, target);
p = strtok(buff,":");
if(!p){
usage(); |
c858e9b6 |
exit(1); |
1f4b3de7 |
}
if(!strcmp(p, "tcp")){ |
c858e9b6 |
h = strtok(NULL,":");
p = strtok(NULL,":");
return(connect_socket_tcp(h,p)); |
1f4b3de7 |
}
if(!strcmp(p, "unix")){ |
c858e9b6 |
p = strtok(NULL,":");
return(connect_socket_unix(p)); |
1f4b3de7 |
} |
d38d0833 |
return(connect_socket_unix(buff)); |
f9cb6348 |
} |
1f4b3de7 |
|
f9cb6348 |
int writeline(int s, char *buff) |
1f4b3de7 |
{ |
f9cb6348 |
int r;
int clen;
int size;
clen = strlen(buff);
size = clen;
while(size){
r = write(s, buff + clen - size, size);
if(r == -1){
return(-1);
}
size -= r;
}
return(0);
}
|
c858e9b6 |
int check_prompt(int s, char *buff, char *passwd)
{
if(!strcmp(buff, "> ")){
return(1);
}
if(!strcmp(buff, "password: \x1b]E") && passwd){
writeline(s, passwd);
writeline(s, "\r\n");
return(2);
}
return(0);
}
|
f9cb6348 |
int readline(int s, char *buff, int size, int prompt, char *passwd)
{ |
c3144016 |
int r = 0; |
f9cb6348 |
char d = 0;
char *p = buff; |
c858e9b6 |
while(p < buff + size){
*p = 0;
if(prompt){
switch(check_prompt(s, buff, passwd)){
case 1:
return(-2);
case 2:
p = buff;
continue; |
f9cb6348 |
}
} |
c3144016 |
r = read(s, &d, 1);
if(r == 0){
return(p - buff);
}
if(r == -1){
return(-1);
}
if(d == '\n'){
if(p != buff){ |
c858e9b6 |
return(p - buff); |
c3144016 |
}
}else{
if(d != '\r'){ |
c858e9b6 |
*(p++) = d; |
c3144016 |
} |
c858e9b6 |
} |
f9cb6348 |
} |
c858e9b6 |
return(-1); /* over flow */ |
f9cb6348 |
}
|
05348f1d |
int wait_prompt(int s, char *passwd, int view, int *line){ |
1f4b3de7 |
int r; |
f31a5410 |
char buff[8192]; |
1b4c64d4 |
while((r = readline(s, buff, sizeof(buff), 1, passwd))){ |
f9cb6348 |
if(r == -1){
/* read error */ |
05348f1d |
r = -1;
break; |
f9cb6348 |
}
if(r == -2){
/* return prompt */ |
05348f1d |
r = 1;
break; |
f9cb6348 |
} |
c2cdbd80 |
if(!strcmp(buff, "alive")){ |
05348f1d |
continue;
}
if(line){
(*line)++;
}
if(view){
if(!memcmp(buff, "error:", 6)){
fprintf(stderr, "%s\n", buff);
}else{
fprintf(stdout, "%s\n", buff);
} |
f31a5410 |
} |
f9cb6348 |
} |
05348f1d |
return(r); |
f9cb6348 |
}
|
05348f1d |
int makuo(int s, char *c, int view) |
f9cb6348 |
{ |
c858e9b6 |
int r; |
05348f1d |
int line = 1; |
f9cb6348 |
char buff[256]; |
c858e9b6 |
if(sizeof(buff) < strlen(c) + 2){
fprintf(stderr, "error: command too long\n");
return(-1);
} |
f9cb6348 |
sprintf(buff, "%s\r\n", c);
if(writeline(s, buff) == -1){ |
c858e9b6 |
fprintf(stderr, "error: can't write socket\n");
return(-1);
} |
05348f1d |
r = wait_prompt(s, NULL, view, &line); |
c858e9b6 |
if(r == -1){
fprintf(stderr, "error: can't read socket\n"); |
f9cb6348 |
return(-1);
} |
05348f1d |
if(r == 0){
return(0);
}
return(line);
}
void makuo_aliveon(msyncdata *md)
{
int r;
char cmd[256];
struct timeval tv;
sprintf(cmd, "alive on");
r = makuo(md->s, cmd, 0);
if(r == 0){
exit(1);
}
if(r == -1){
exit(1);
}
if(r == 1){
tv.tv_sec = 30;
tv.tv_usec = 0;
}else{
tv.tv_sec = 0;
tv.tv_usec = 0;
}
setsockopt(md->s, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)); |
c858e9b6 |
}
|
05348f1d |
void makuo_log(msyncdata *md) |
c858e9b6 |
{
int r;
char cmd[256]; |
05348f1d |
sprintf(cmd, "loglevel %d", md->loglevel);
r = makuo(md->s, cmd, 0); |
c858e9b6 |
if(r == 0){
fprintf(stderr, "error: remote close\n"); |
05348f1d |
exit(1); |
c858e9b6 |
}
if(r == -1){ |
05348f1d |
exit(1); |
c858e9b6 |
} |
f9cb6348 |
}
|
05348f1d |
void makuo_exclude(msyncdata *md) |
a0346c4a |
{
int r;
char cmd[1024];
excludeitem *item; |
05348f1d |
for(item=md->exclude;item;item=item->next){ |
a0346c4a |
sprintf(cmd, "exclude add %s", item->pattern); |
05348f1d |
r = makuo(md->s, cmd, 0); |
a0346c4a |
if(r == 0){
fprintf(stderr, "error: makuosan remote close. (%s)\n", cmd); |
05348f1d |
exit(1); |
a0346c4a |
}
if(r == -1){
fprintf(stderr, "error: makuosan socket error. (%s)\n", cmd); |
05348f1d |
exit(1); |
a0346c4a |
}
}
}
int makuo_exec(int s, char *cmd)
{ |
05348f1d |
int r = makuo(s, cmd, 1); |
a0346c4a |
if(r == 0){
fprintf(stderr, "error: makuosan remote close. (%s)\n", cmd);
return(1);
}
if(r == -1){
fprintf(stderr, "error: makuosan socket error. (%s)\n", cmd);
return(1);
}
return(0);
}
|
05348f1d |
void makuo_send(msyncdata *md)
{
char cmd[1024];
if(md->delflag){
sprintf(cmd, "dsync%s %s", md->mopt, md->path);
if(makuo_exec(md->s, cmd)){
close(md->s);
exit(1);
}
}
if(md->sendflag){
sprintf(cmd, "%s%s%s %s", md->mcmd, md->mopt, md->sopt, md->path);
}else{
sprintf(cmd, "%s%s %s", md->mcmd, md->mopt, md->path);
}
if(makuo_exec(md->s, cmd)){
close(md->s);
exit(1);
}
}
int makuo_quit(msyncdata *md) |
c858e9b6 |
{ |
05348f1d |
int r = makuo(md->s, "quit", 0);
close(md->s); |
c858e9b6 |
if(r == 0){
return(0); /* success */
}
if(r == -1){
return(1);
}
fprintf(stderr, "quit error?!\n");
return(1);
}
|
05348f1d |
int exclude_from(msyncdata *md, char *filename) |
f9cb6348 |
{ |
1f4b3de7 |
int f; |
f9cb6348 |
int r;
char line[256]; |
1f4b3de7 |
|
f9cb6348 |
if(!strcmp(filename, "-")){ |
c858e9b6 |
f = dup(0); |
f9cb6348 |
}else{
f = open(filename, O_RDONLY); |
c858e9b6 |
}
if(f == -1){
fprintf(stderr,"can't open: %s\n", filename);
return(1); |
f9cb6348 |
} |
1b4c64d4 |
while((r = readline(f, line, sizeof(line), 0, NULL))){ |
f9cb6348 |
if(r == -1){
fprintf(stderr, "file read error: %s\n", filename); |
c858e9b6 |
close(f);
return(1); |
f9cb6348 |
} |
50cd0ac2 |
if((*line != '\r') && (*line != '\n') && (*line !=0)){ |
05348f1d |
add_exclude(md, line); |
50cd0ac2 |
} |
f9cb6348 |
} |
a0346c4a |
close(f);
return(0); |
c858e9b6 |
}
|
05348f1d |
int makuo_file(msyncdata *md) |
c858e9b6 |
{ |
a0346c4a |
int f;
int r;
char line[256]; |
05348f1d |
char *filename; |
c858e9b6 |
|
05348f1d |
filename = md->scfile;
if(!strlen(filename)){
return(0);
} |
a0346c4a |
if(!strcmp(filename, "-")){
/* f = stdin */
f = dup(0);
}else{
f = open(filename, O_RDONLY); |
c858e9b6 |
} |
a0346c4a |
if(f == -1){
fprintf(stderr,"can't open: %s\n", filename); |
c858e9b6 |
return(1);
}
|
a0346c4a |
/* command read loop */ |
1b4c64d4 |
while((r = readline(f, line, sizeof(line), 0, NULL))){ |
a0346c4a |
if(r == -1){
fprintf(stderr, "file read error: %s\n", filename); |
05348f1d |
break; |
a0346c4a |
} |
05348f1d |
if(makuo_exec(md->s, line)){ |
a0346c4a |
close(f); |
05348f1d |
exit(1); |
a0346c4a |
}
}
close(f); |
05348f1d |
return(1); |
f9cb6348 |
}
int loadpass(char *filename, char *passwd, int size)
{
int f;
f = open(filename, O_RDONLY);
if(f == -1){
fprintf(stderr, "file open error %s\n", filename);
return(-1);
}
if(readline(f, passwd, size, 0, NULL) == -1){
fprintf(stderr, "file read error %s\n", filename);
close(f);
return(-1);
}
close(f);
return(0);
}
|
c2cdbd80 |
void get_envopt(msyncdata *md) |
f9cb6348 |
{ |
c2cdbd80 |
char *p; |
1b4c64d4 |
if((p = getenv("MSYNC_TARGET"))){ |
c2cdbd80 |
if(strlen(p) < sizeof(md->target)){
strcpy(md->target, p);
}else{ |
1b4c64d4 |
fprintf(stderr, "MSYNC_TARGET too long. %s\n", p); |
c2cdbd80 |
exit(1);
} |
f9cb6348 |
}
}
|
05348f1d |
struct option *optinit() |
f9cb6348 |
{ |
f5b6f77b |
static struct option longopt[10]; |
a0346c4a |
longopt[0].name = "help";
longopt[0].has_arg = 0;
longopt[0].flag = NULL;
longopt[0].val = 'h';
longopt[1].name = "status";
longopt[1].has_arg = 0;
longopt[1].flag = NULL;
longopt[1].val = 'S';
longopt[2].name = "members";
longopt[2].has_arg = 0;
longopt[2].flag = NULL;
longopt[2].val = 'M';
longopt[3].name = "check";
longopt[3].has_arg = 0;
longopt[3].flag = NULL;
longopt[3].val = 'C';
longopt[4].name = "exclude";
longopt[4].has_arg = 1;
longopt[4].flag = NULL;
longopt[4].val = 'E';
longopt[5].name = "exclude-from";
longopt[5].has_arg = 1;
longopt[5].flag = NULL;
longopt[5].val = 'F';
longopt[6].name = "delete";
longopt[6].has_arg = 0;
longopt[6].flag = NULL;
longopt[6].val = 'D'; |
7ec57664 |
longopt[7].name = "sync";
longopt[7].has_arg = 0;
longopt[7].flag = NULL;
longopt[7].val = 'd'; |
f5b6f77b |
longopt[8].name = "version"; |
05348f1d |
longopt[8].has_arg = 0;
longopt[8].flag = NULL; |
f5b6f77b |
longopt[8].val = 'V';
longopt[9].name = NULL;
longopt[9].has_arg = 0;
longopt[9].flag = NULL;
longopt[9].val = 0; |
05348f1d |
return(longopt);
} |
a0346c4a |
|
05348f1d |
void parse_opt(int argc, char *argv[], struct option *opt, msyncdata *md)
{
int r; |
f5b6f77b |
while((r = getopt_long(argc, argv, "g:c:f:t:K:l:hvrnV", opt, NULL)) != -1){ |
1f4b3de7 |
switch(r){
case 'h':
usage(); |
05348f1d |
exit(0); |
c858e9b6 |
|
f5b6f77b |
case 'V':
version();
exit(0);
|
3eaafa57 |
case 'D': |
05348f1d |
md->delflag = 1; |
3eaafa57 |
break;
|
7ec57664 |
case 'd': |
05348f1d |
strcpy(md->mcmd, "sync"); |
7ec57664 |
break;
|
a0346c4a |
case 'S': |
05348f1d |
strcpy(md->mcmd, "status");
md->loopflag = 0;
md->sendflag = 0; |
a0346c4a |
break;
case 'M': |
05348f1d |
strcpy(md->mcmd, "members");
md->loopflag = 0;
md->sendflag = 0; |
a0346c4a |
break;
case 'C': |
05348f1d |
strcpy(md->mcmd, "check");
md->sendflag = 0; |
a0346c4a |
break;
case 'E': |
05348f1d |
add_exclude(md, optarg); |
a0346c4a |
break;
case 'F': |
05348f1d |
if(exclude_from(md, optarg)){
exit(1); |
a0346c4a |
}
break;
case 'r': |
05348f1d |
strcat(md->mopt," -r"); |
a0346c4a |
break;
case 'n': |
05348f1d |
strcat(md->mopt," -n"); |
a0346c4a |
break;
case 't': |
05348f1d |
strcat(md->mopt," -t ");
strcat(md->mopt,optarg); |
a0346c4a |
break;
|
5cf3fe0f |
case 'g': |
05348f1d |
md->grpflag = 1;
strcat(md->sopt," -g ");
strcat(md->sopt,optarg); |
5cf3fe0f |
break;
|
a0346c4a |
case 'v': |
05348f1d |
md->loglevel++; |
a0346c4a |
break;
|
c858e9b6 |
case 'l': |
05348f1d |
md->loglevel = atoi(optarg); |
f9cb6348 |
break; |
c858e9b6 |
|
1f4b3de7 |
case 'f': |
05348f1d |
if(strlen(optarg) < sizeof(md->scfile)){
strcpy(md->scfile, optarg); |
c858e9b6 |
}else{
fprintf(stderr, "filename too long\n"); |
05348f1d |
exit(1); |
c858e9b6 |
} |
1f4b3de7 |
break; |
c858e9b6 |
|
1f4b3de7 |
case 'c': |
05348f1d |
if(strlen(optarg) < sizeof(md->target)){
strcpy(md->target, optarg); |
c858e9b6 |
}else{
fprintf(stderr, "target too long\n"); |
05348f1d |
exit(1); |
c858e9b6 |
} |
1f4b3de7 |
break; |
c858e9b6 |
|
f9cb6348 |
case 'K': |
05348f1d |
if(loadpass(optarg, md->passwd, sizeof(md->passwd)) == -1){
exit(1); |
f9cb6348 |
}
break;
|
a0346c4a |
case '?':
usage(); |
05348f1d |
exit(1); |
a0346c4a |
break;
} |
f9cb6348 |
} |
05348f1d |
if(md->delflag && !md->sendflag){ |
3eaafa57 |
usage(); |
05348f1d |
exit(1); |
5cf3fe0f |
} |
05348f1d |
if(md->grpflag && !md->sendflag){ |
5cf3fe0f |
usage(); |
05348f1d |
exit(1); |
3eaafa57 |
} |
05348f1d |
if(argc == optind){
md->loopflag = 0; |
1f4b3de7 |
} |
05348f1d |
} |
c858e9b6 |
|
05348f1d |
int connect_wait(msyncdata *md)
{
int r;
r = wait_prompt(md->s, md->passwd, 0, NULL); |
c858e9b6 |
if(r == 0){
fprintf(stderr, "remote socket close\n");
return(1);
}
if(r == -1){
fprintf(stderr, "socket read error\n");
return(1);
} |
05348f1d |
return(0);
} |
f9cb6348 |
|
05348f1d |
void connect_target(msyncdata *md)
{
struct timeval tv;
md->s = connect_socket(md->target);
if(md->s == -1){
fprintf(stderr, "can't connect %s\n", md->target);
exit(1); |
a0346c4a |
} |
05348f1d |
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(md->s, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
if(connect_wait(md)){
close(md->s);
exit(1);
}
} |
a0346c4a |
|
05348f1d |
void msync_init(msyncdata *md)
{
memset(md, 0, sizeof(msyncdata));
md->loopflag = 1;
md->sendflag = 1;
strcpy(md->mcmd, "send"); |
c2cdbd80 |
strcpy(md->target, "tcp:127.0.0.1:5000"); |
05348f1d |
} |
c858e9b6 |
|
05348f1d |
int main(int argc, char *argv[])
{
int i;
msyncdata md;
if(argc == 1){
usage();
exit(1); |
a0346c4a |
}
|
05348f1d |
msync_init(&md); |
c2cdbd80 |
get_envopt(&md); |
05348f1d |
parse_opt(argc, argv, optinit(), &md);
connect_target(&md);
makuo_aliveon(&md);
makuo_log(&md);
makuo_exclude(&md);
if(!makuo_file(&md)){
if(!md.loopflag){
md.path[0] = 0;
makuo_send(&md);
}else{ |
3eaafa57 |
for(i=optind;i<argc;i++){ |
05348f1d |
strcpy(md.path, argv[i]);
makuo_send(&md); |
3eaafa57 |
}
} |
1f4b3de7 |
} |
05348f1d |
return(makuo_quit(&md)); |
1f4b3de7 |
} |
f9cb6348 |
|