c858e9b6 |
/*
* msync.c |
dbdc4e5a |
* Copyright (C) 2008 KLab Inc. |
c858e9b6 |
*/
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64 |
a0346c4a |
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif |
c858e9b6 |
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h> |
a0346c4a |
#include "makuosan.h"
excludeitem *exclude = NULL; |
1f4b3de7 |
void usage()
{ |
a0346c4a |
printf("msync version %s (CLI for makuosan)\n", PACKAGE_VERSION);
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");
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 |
}
excludeitem *add_exclude(char *pattern)
{
excludeitem *item = malloc(sizeof(excludeitem));
item->pattern = malloc(strlen(pattern) + 1);
strcpy(item->pattern, pattern);
item->prev = NULL;
item->next = NULL;
if(exclude){
exclude->prev = item;
item->next = exclude;
}
exclude = item;
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));
hint.ai_family = AF_INET;
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 |
}
return(-1); |
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)
{
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 |
}
} |
c858e9b6 |
switch(read(s, &d, 1)){
case 0:
return(p - buff);
case -1:
return(-1);
break;
default:
if(d == '\r'){
break;
}
if((d == '\n') && (p != buff)){
return(p - buff);
}
*(p++) = d;
break;
} |
f9cb6348 |
} |
c858e9b6 |
return(-1); /* over flow */ |
f9cb6348 |
}
int wait_prompt(int s, char *passwd){ |
1f4b3de7 |
int r; |
f9cb6348 |
char buff[1024];
while(r = readline(s, buff, sizeof(buff), 1, passwd)){
if(r == -1){
/* read error */
return(-1);
}
if(r == -2){
/* return prompt */
return(1);
}
fprintf(stderr, "%s\n", buff);
}
return(0);
}
int makuo(int s, char *c)
{ |
c858e9b6 |
int r; |
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);
}
r = wait_prompt(s, NULL);
if(r == -1){
fprintf(stderr, "error: can't read socket\n"); |
f9cb6348 |
return(-1);
} |
c858e9b6 |
return(r);
}
|
a0346c4a |
int makuo_log(int s, int l) |
c858e9b6 |
{
int r;
char cmd[256];
sprintf(cmd, "loglevel %d", l);
r = makuo(s, cmd);
if(r == 0){
fprintf(stderr, "error: remote close\n");
return(1);
}
if(r == -1){
return(1);
} |
f9cb6348 |
return(0);
}
|
a0346c4a |
int makuo_exclude(int s)
{
int r;
char cmd[1024];
excludeitem *item;
for(item=exclude;item;item=item->next){
sprintf(cmd, "exclude add %s", item->pattern);
r = makuo(s, cmd);
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);
}
int makuo_exec(int s, char *cmd)
{
int r = makuo(s, cmd);
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);
}
int makuo_quit(int s) |
c858e9b6 |
{
int r = makuo(s, "quit"); |
a0346c4a |
close(s); |
c858e9b6 |
if(r == 0){
return(0); /* success */
}
if(r == -1){
return(1);
}
fprintf(stderr, "quit error?!\n");
return(1);
}
|
a0346c4a |
int exclude_from(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 |
}
while(r = readline(f, line, sizeof(line), 0, NULL)){
if(r == -1){
fprintf(stderr, "file read error: %s\n", filename); |
c858e9b6 |
close(f);
return(1); |
f9cb6348 |
} |
a0346c4a |
add_exclude(line); |
f9cb6348 |
} |
a0346c4a |
close(f);
return(0); |
c858e9b6 |
}
|
a0346c4a |
int fromfile(int s, char *filename) |
c858e9b6 |
{ |
a0346c4a |
int f;
int r;
char line[256]; |
c858e9b6 |
|
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 */
while(r = readline(f, line, sizeof(line), 0, NULL)){
if(r == -1){
fprintf(stderr, "file read error: %s\n", filename);
close(f);
return(1);
}
if(makuo_exec(s, line)){
close(f);
return(1);
}
}
close(f);
return(makuo_quit(s)); |
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);
}
|
c858e9b6 |
void defaulttarget(char *target, int size) |
f9cb6348 |
{ |
c858e9b6 |
char *p = getenv("MSYNC_TARGET");
strcpy(target, "tcp:127.0.0.1:5000");
if(p && (strlen(p) < size)){ |
f9cb6348 |
strcpy(target, p);
}
}
int main(int argc, char *argv[])
{ |
a0346c4a |
int i; |
f9cb6348 |
int r;
int s;
|
a0346c4a |
if(argc == 1){
usage();
return(1);
}
/* makuo command */
char cmd[1024];
char mcmd[256];
char mopt[256];
strcpy(mcmd,"send");
strcpy(mopt,"");
|
f9cb6348 |
/* option */ |
a0346c4a |
int loopflag = 1; |
f9cb6348 |
int loglevel = 0;
char scfile[256];
char passwd[256];
char target[256]; |
1f4b3de7 |
|
a0346c4a |
/* long option */
struct option longopt[7];
memset(longopt, 0, sizeof(longopt));
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';
|
f9cb6348 |
/* default */ |
1f4b3de7 |
scfile[0] = 0; |
f9cb6348 |
passwd[0] = 0; |
c858e9b6 |
defaulttarget(target, sizeof(target)); |
1f4b3de7 |
|
a0346c4a |
while((r = getopt_long(argc, argv, "c:f:t:K:l:hvrn", longopt, NULL)) != -1){ |
1f4b3de7 |
switch(r){
case 'h':
usage(); |
c858e9b6 |
return(0);
|
a0346c4a |
case 'S':
strcpy(mcmd, "status");
loopflag = 0;
break;
case 'M':
strcpy(mcmd, "members");
loopflag = 0;
break;
case 'C':
strcpy(mcmd, "check");
break;
case 'E':
add_exclude(optarg);
break;
case 'F':
if(exclude_from(optarg)){
return(1);
}
break;
case 'r':
strcat(mopt," -r");
break;
case 'n':
strcat(mopt," -n");
break;
case 't':
strcat(mopt," -t ");
strcat(mopt,optarg);
break;
case 'v':
loglevel++;
break;
|
c858e9b6 |
case 'l':
loglevel = atoi(optarg); |
f9cb6348 |
break; |
c858e9b6 |
|
1f4b3de7 |
case 'f': |
c858e9b6 |
if(strlen(optarg) < sizeof(scfile)){
strcpy(scfile, optarg);
}else{
fprintf(stderr, "filename too long\n");
return(1);
} |
1f4b3de7 |
break; |
c858e9b6 |
|
1f4b3de7 |
case 'c': |
c858e9b6 |
if(strlen(optarg) < sizeof(target)){
strcpy(target, optarg);
}else{
fprintf(stderr, "target too long\n");
return(1);
} |
1f4b3de7 |
break; |
c858e9b6 |
|
f9cb6348 |
case 'K':
if(loadpass(optarg, passwd, sizeof(passwd)) == -1){
return(1);
}
break;
|
a0346c4a |
case '?':
usage();
return(1);
break;
} |
f9cb6348 |
}
|
1f4b3de7 |
s = connect_socket(target);
if(s == -1){ |
c858e9b6 |
fprintf(stderr, "can't connect %s\n", target); |
1f4b3de7 |
return(1);
} |
c858e9b6 |
|
f9cb6348 |
r = wait_prompt(s, passwd); |
c858e9b6 |
if(r == 0){
fprintf(stderr, "remote socket close\n");
close(s);
return(1);
} |
a0346c4a |
|
c858e9b6 |
if(r == -1){
fprintf(stderr, "socket read error\n");
close(s);
return(1);
} |
f9cb6348 |
|
a0346c4a |
if(makuo_log(s, loglevel)){
close(s);
return(1);
}
if(makuo_exclude(s)){ |
c858e9b6 |
close(s);
return(1);
}
if(scfile[0]){ |
a0346c4a |
return(fromfile(s, scfile));
}
if(loopflag && (optind < argc)){
for(i=optind;i<argc;i++){
sprintf(cmd, "%s%s %s", mcmd, mopt, argv[i]);
if(makuo_exec(s, cmd)){
close(s);
return(1);
}
} |
c858e9b6 |
}else{ |
a0346c4a |
sprintf(cmd, "%s%s", mcmd, mopt);
for(i=optind;i<argc;i++){
strcat(cmd, " ");
strcat(cmd, argv[i]);
}
if(makuo_exec(s, cmd)){
close(s);
return(1);
} |
1f4b3de7 |
} |
a0346c4a |
return(makuo_quit(s)); |
1f4b3de7 |
} |
f9cb6348 |
|