Compare commits

...

9 Commits

3 changed files with 297 additions and 198 deletions

View File

@ -47,51 +47,10 @@ int main(int argc, char *argv[]) {
exit(1); exit(1);
} }
if (!strcmp(argv[1], "time")) { bzero(buffer, 256);
strcpy(buffer, "current_time"); for (int i = 1; i < argc; i++) {
} else if (!strcmp(argv[1], "start")) { strcat(buffer, argv[i]);
strcpy(buffer, "start"); strcat(buffer, " ");
} else if (!strcmp(argv[1], "stop")) {
strcpy(buffer, "stop");
} else if (!strcmp(argv[1], "kill")) {
strcpy(buffer, "kill");
} else if (!strcmp(argv[1], "split")) {
strcpy(buffer, "split");
} else if (!strcmp(argv[1], "skip")) {
strcpy(buffer, "skip");
} else if (!strcmp(argv[1], "pause")) {
strcpy(buffer, "pause");
} else if (!strcmp(argv[1], "resume")) {
strcpy(buffer, "resume");
} else if (!strcmp(argv[1], "undo")) {
strcpy(buffer, "undo");
} else if (!strcmp(argv[1], "redo")) {
strcpy(buffer, "redo");
} else if (!strcmp(argv[1], "foreground")) {
strcpy(buffer, "Foreground-Color");
} else if (!strcmp(argv[1], "background")) {
strcpy(buffer, "Background-Color");
} else if (!strcmp(argv[1], "save")) {
strcpy(buffer, "save");
} else if (!strcmp(argv[1], "runs")) {
strcpy(buffer, "run_count");
} else if (!strcmp(argv[1], "segments")) {
strcpy(buffer, "segment_count");
} else if (!strcmp(argv[1], "start-split-stop")) {
strcpy(buffer, "start-split-stop");
} else if (!strcmp(argv[1], "pause-resume")) {
strcpy(buffer, "pause-resume");
} else if (!strcmp(argv[1], "start-stop")) {
strcpy(buffer, "start-stop");
} else if (!strcmp(argv[1], "start-split")) {
strcpy(buffer, "start-split");
} else if (!strcmp(argv[1], "split-stop")) {
strcpy(buffer, "split-stop");
} else if (!strcmp(argv[1], "undo-redo")) {
strcpy(buffer, "undo-redo");
} else {
perror("No valid command given");
exit(1);
} }
/* Send message to the server */ /* Send message to the server */
@ -104,26 +63,11 @@ int main(int argc, char *argv[]) {
/* Now read server response */ /* Now read server response */
bzero(buffer,256); bzero(buffer,256);
n = read(sockfd, &buffer, 256); n = read(sockfd, &buffer, 256);
//read an int response
if (!strcmp(argv[1], "time") || !strcmp(argv[1], "runs") || !strcmp(argv[1], "segments")) {
int x = -1;
x = *(int*)&buffer;
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
if (x != -1)
printf("%d\n",x);
}
//read a string response
else {
if (n < 0) { if (n < 0) {
perror("ERROR reading from socket"); perror("ERROR reading from socket");
exit(1); exit(1);
} }
if (buffer != NULL) if (buffer != NULL)
printf("%s", buffer); printf("%s\n", buffer);
}
return 0; return 0;
} }

View File

@ -12,7 +12,6 @@
#define NS_PER_S 1000000000 #define NS_PER_S 1000000000
struct timespec finish, delta; struct timespec finish, delta;
int pausedTime = 0;
bool timerActive = false; bool timerActive = false;
bool paused = false; bool paused = false;
bool alive = true; bool alive = true;
@ -25,6 +24,7 @@ enum event_type {
SKIP, SKIP,
PAUSE, PAUSE,
RESUME, RESUME,
RESET,
STOP STOP
}; };
struct run_event { struct run_event {
@ -38,8 +38,8 @@ struct segment {
}; };
struct route { struct route {
char *name; char *name;
struct segment *segments;
int segment_count; int segment_count;
struct segment *segments;
}; };
struct run_event *run; struct run_event *run;
@ -53,7 +53,7 @@ char *default_file_name = "untitled.quest";
int run_count = 0; int run_count = 0;
int files = 0; int files = 0;
char **filePaths = NULL; char **filePaths = NULL;
char **names, **values; char **meta_keys, **meta_values;
int valuecount; int valuecount;
struct segment *segments; struct segment *segments;
int segment_count = 0; int segment_count = 0;
@ -72,11 +72,13 @@ void timespecToRFC3339(struct timespec t, char buf[]);
void loadFiles(); void loadFiles();
void add_segment(char *sname, char *lname, char *desc); void add_segment(char *sname, char *lname, char *desc);
void addFile(char *path); void addFile(char *path);
void sendValue(int sock, char* name);
void sendInt(int sock, int value); void sendInt(int sock, int value);
void doprocessing (int sock); void sendValue(int sock, char* name);
void addPauseTime(); void sendString(int sock, char* str);
void subtractPauseTime(); void process_socket_input(int sock);
void set_metadata(char *key, char *value);
void save_metadata_to_file(char *token, char *token2);
void reset_timer();
int current_ms(); int current_ms();
//basic timer commands //basic timer commands
@ -88,9 +90,11 @@ void undo();
void redo(); void redo();
void pause_timer(); void pause_timer();
void resume(); void resume();
void reset();
//convenient combination commands //convenient combination commands
void start_split_stop(); void start_split_stop();
void start_reset();
void start_split(); void start_split();
void split_stop(); void split_stop();
void start_stop(); void start_stop();
@ -148,6 +152,7 @@ void add_event(enum event_type t)
offset_timespec(timerOffset, &run[runMarker].time); offset_timespec(timerOffset, &run[runMarker].time);
runMarker++; runMarker++;
runMarker2 = runMarker; runMarker2 = runMarker;
hasUndoneAtLeastOnce = false;
} }
void reset_timer() void reset_timer()
@ -179,6 +184,16 @@ void stop()
runUnsaved = true; runUnsaved = true;
} }
//Identical function to stop() but with a RESET event
void reset()
{
if (!timerActive) return;
timerActive = false;
add_event(RESET);
finish = run[runMarker - 1].time;
runUnsaved = true;
}
void start_split_stop() void start_split_stop()
{ {
if (!timerActive) { if (!timerActive) {
@ -210,6 +225,12 @@ void start_stop()
else stop(); else stop();
} }
void start_reset()
{
if (!timerActive) start();
else reset();
}
void split() void split()
{ {
if (!timerActive) return; if (!timerActive) return;
@ -222,46 +243,20 @@ void skip()
add_event(SKIP); add_event(SKIP);
} }
void addPauseTime()
{
int pauseEvent = 0;
for (int i = runMarker - 2; i >= 1; i--) {
if (run[i].type == PAUSE) {
pauseEvent = i;
break;
}
}
sub_timespec(run[pauseEvent].time, run[runMarker - 1].time, &delta);
pausedTime += timespecToMS(delta);
}
void subtractPauseTime()
{
int pauseEvent = 0;
for (int i = runMarker - 1; i >= i; i--) {
if (run[i].type == PAUSE) {
pauseEvent = i;
break;
}
}
sub_timespec(run[pauseEvent].time, run[runMarker].time, &delta);
pausedTime -= timespecToMS(delta);
}
void undo() void undo()
{ {
if (!timerActive) return;
if (runMarker > 0) { if (runMarker > 0) {
runMarker--; runMarker--;
if (run[runMarker].type == STOP) if (run[runMarker].type == STOP) {
timerActive = true; timerActive = true;
runUnsaved = false;
}
if (run[runMarker].type == START) if (run[runMarker].type == START)
timerActive = false; timerActive = false;
if (run[runMarker].type == PAUSE) if (run[runMarker].type == PAUSE)
paused = false; paused = false;
if (run[runMarker].type == RESUME) { if (run[runMarker].type == RESUME) {
paused = true; paused = true;
subtractPauseTime();
} }
hasUndoneAtLeastOnce = true; hasUndoneAtLeastOnce = true;
} }
@ -272,17 +267,20 @@ void redo()
if (!timerActive) return; if (!timerActive) return;
if (runMarker < runMarker2) { if (runMarker < runMarker2) {
runMarker++; runMarker++;
if (run[runMarker - 1].type == STOP) if (run[runMarker - 1].type == STOP) {
timerActive = false; timerActive = false;
runUnsaved = true;
finish = run[runMarker - 1].time;
}
if (run[runMarker - 1].type == START) if (run[runMarker - 1].type == START)
timerActive = true; timerActive = true;
if (run[runMarker - 1].type == PAUSE) if (run[runMarker - 1].type == PAUSE)
paused = true; paused = true;
if (run[runMarker - 1].type == RESUME) { if (run[runMarker - 1].type == RESUME) {
paused = false; paused = false;
addPauseTime();
} }
} else { }
if (runMarker == runMarker2) {
hasUndoneAtLeastOnce = false; hasUndoneAtLeastOnce = false;
} }
} }
@ -309,7 +307,6 @@ void resume()
if (paused) { if (paused) {
add_event(RESUME); add_event(RESUME);
paused = false; paused = false;
addPauseTime();
} }
} }
@ -359,6 +356,9 @@ void appendRunToFile()
case RESUME: case RESUME:
fprintf(fp, "\t%s\n", "Resume"); fprintf(fp, "\t%s\n", "Resume");
break; break;
case RESET:
fprintf(fp, "\t%s\n", "Reset");
break;
case STOP: case STOP:
fprintf(fp, "\t%s\n", "Stop"); fprintf(fp, "\t%s\n", "Stop");
break; break;
@ -397,7 +397,6 @@ void loadFiles()
char buff2[255]; char buff2[255];
for (int i = 0; i < files; i++) { for (int i = 0; i < files; i++) {
printf("loading file: \"%s\"\n", filePaths[i]);
fp = fopen(filePaths[i], "r+"); fp = fopen(filePaths[i], "r+");
while(1) { while(1) {
if (!fgets(buff, 255, fp)) if (!fgets(buff, 255, fp))
@ -443,33 +442,14 @@ void loadFiles()
if (!fgets(buff2, 255, fp)) if (!fgets(buff2, 255, fp))
break; break;
if (buff2[0] == '\t') { if (buff2[0] == '\t') {
valuecount++; buff[strlen(buff) - 1] = '\0';
buff2[strlen(buff2) - 1] = '\0';
names = realloc(names, sizeof(char*) * valuecount); set_metadata(buff, buff2 + 1);
names[valuecount - 1] = malloc(strlen(buff));
strncpy(names[valuecount - 1], buff, strlen(buff) - 1);
names[valuecount - 1][strlen(buff)] = '\0';
values = realloc(values, sizeof(char*) * valuecount);
values[valuecount - 1] = malloc(strlen(buff2) - 1);
strncpy(values[valuecount - 1], buff2 + 1, strlen(buff2) - 1);
values[valuecount - 1][strlen(buff2)] = '\0';
} }
} }
fclose(fp); fclose(fp);
} }
//Print metadata arrays
for (int i = 0; i < valuecount; i++) {
printf("%s | %s", names[i], values[i]);
}
//Print segments
for (int i = 0; i < segment_count; i++) {
printf("Segment %d: %s\n", i, segments[i].shortname);
}
//Print run count
printf("%d\n", run_count);
} }
void add_segment(char *sname, char *lname, char *desc) void add_segment(char *sname, char *lname, char *desc)
@ -494,18 +474,18 @@ int current_ms()
{ {
if (timerActive) if (timerActive)
clock_gettime(CLOCK_REALTIME, &finish); clock_gettime(CLOCK_REALTIME, &finish);
if (paused) { //if (paused) {
sub_timespec(run[0].time, run[runMarker - 1].time, &delta); // sub_timespec(run[0].time, run[runMarker - 1].time, &delta);
} else { //} else {
sub_timespec(run[0].time, finish, &delta); sub_timespec(run[0].time, finish, &delta);
} //}
return timespecToMS(delta) - pausedTime; return timespecToMS(delta);
} }
void sendInt(int sock, int value) void sendInt(int sock, int value)
{ {
char buffer[256]; char buffer[256];
strncpy(buffer, (char*)&value, sizeof(int)); sprintf(buffer, "%d", value);
int n = write(sock, &buffer, 256); int n = write(sock, &buffer, 256);
if (n < 0) { if (n < 0) {
perror("ERROR writing to socket"); perror("ERROR writing to socket");
@ -518,16 +498,20 @@ void sendValue(int sock, char* name)
char buffer[256]; char buffer[256];
int n, x; int n, x;
bool namefound = false; bool namefound = false;
if (name == NULL) {
strcpy(buffer, "DATA NOT PRESENT");
} else {
for(int i = 0; i < valuecount; i++) { for(int i = 0; i < valuecount; i++) {
if (!strcmp(names[i], name)) { if (!strcmp(meta_keys[i], name)) {
x = i; x = i;
namefound = true; namefound = true;
} }
} }
if (namefound) if (namefound)
strcpy(buffer, values[x]); strcpy(buffer, meta_values[x]);
else else
strcpy(buffer, "DATA NOT PRESENT"); strcpy(buffer, "DATA NOT PRESENT");
}
n = write(sock, &buffer, 256); n = write(sock, &buffer, 256);
if (n < 0) { if (n < 0) {
perror("ERROR writing to socket"); perror("ERROR writing to socket");
@ -535,81 +519,252 @@ void sendValue(int sock, char* name)
} }
} }
void doprocessing (int sock) void sendString(int sock, char* str)
{
char buffer[256];
strcpy(buffer, str);
int n = write(sock, &buffer, 256);
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
}
void set_metadata(char *key, char *value)
{
char key_pos = -1;
for (int i = 0; i < valuecount; i++)
if (!strcmp(meta_keys[i], key))
key_pos = i;
if (key_pos > -1) {
meta_values[key_pos] = realloc(meta_values[key_pos], strlen(value));
strncpy(meta_values[key_pos], value, strlen(value));
meta_values[key_pos][strlen(value)] = '\0';
} else {
valuecount++;
meta_keys = realloc(meta_keys, sizeof(char*) * valuecount);
meta_keys[valuecount - 1] = malloc(strlen(key));
strncpy(meta_keys[valuecount - 1], key, strlen(key));
meta_keys[valuecount - 1][strlen(key)] = '\0';
meta_values = realloc(meta_values, sizeof(char*) * valuecount);
meta_values[valuecount - 1] = malloc(strlen(value));
strncpy(meta_values[valuecount - 1], value, strlen(value));
meta_values[valuecount - 1][strlen(value)] = '\0';
}
}
void save_metadata_to_file(char *token, char *token2)
{
char* save_path = NULL;
if (files <= 0)
save_path = default_file_name;
else
save_path = filePaths[0];
FILE* fp;
fp = fopen(save_path, "r+");
fprintf(fp, "%s\n", token);
fprintf(fp, "\t%s\n\n", token2);
fclose(fp);
}
void process_socket_input(int sock)
{ {
int n; int n;
char buffer[256]; char buffer[256];
n = read(sock, &buffer, 256); n = read(sock, &buffer, 256);
if (n < 0) { if (n < 0) {
perror("ERROR reading from socket"); perror("ERROR reading from socket");
exit(1); exit(1);
} }
if (!strcmp(buffer, "current_time")) { char *token = strtok(buffer, " ");
//printf("Recieved time command\n");
sendInt(sock, current_ms()); //Imperative commands
} else if (!strcmp(buffer, "start")) { if (!strcmp(token, "start")) {
printf("Recieved start command\n");
start(); start();
} else if (!strcmp(buffer, "stop")) { } else if (!strcmp(token, "stop")) {
printf("Recieved stop command\n");
stop(); stop();
} else if (!strcmp(buffer, "kill")) { } else if (!strcmp(token, "reset")) {
printf("Recieved kill command\n"); reset();
} else if (!strcmp(token, "kill")) {
alive = false; alive = false;
} else if (!strcmp(buffer, "split")) { } else if (!strcmp(token, "split")) {
printf("Recieved split command\n");
split(); split();
} else if (!strcmp(buffer, "skip")) { } else if (!strcmp(token, "skip")) {
printf("Recieved skip command\n");
skip(); skip();
} else if (!strcmp(buffer, "pause")) { } else if (!strcmp(token, "pause")) {
printf("Recieved pause command\n");
pause_timer(); pause_timer();
} else if (!strcmp(buffer, "resume")) { } else if (!strcmp(token, "resume")) {
printf("Recieved resume command\n");
resume(); resume();
} else if (!strcmp(buffer, "undo")) { } else if (!strcmp(token, "undo")) {
printf("Recieved undo command\n");
undo(); undo();
} else if (!strcmp(buffer, "redo")) { } else if (!strcmp(token, "redo")) {
printf("Recieved redo command\n");
redo(); redo();
} else if (!strcmp(buffer, "Foreground-Color")) { } else if (!strcmp(token, "save")) {
printf("Recieved request for foreground color\n");
sendValue(sock, "Foreground-Color");
} else if (!strcmp(buffer, "Background-Color")) {
printf("Recieved request for background color\n");
sendValue(sock, "Background-Color");
} else if (!strcmp(buffer, "save")) {
printf("Recieved save command\n");
appendRunToFile(); appendRunToFile();
} else if (!strcmp(buffer, "run_count")) { } else if (!strcmp(token, "start-split-stop")) {
printf("Recieved request for run count\n");
sendInt(sock, run_count);
} else if (!strcmp(buffer, "segment_count")) {
printf("Recieved request for segment count\n");
sendInt(sock, segment_count);
} else if (!strcmp(buffer, "start_split_stop")) {
printf("Recieved start_split_stop command\n");
start_split_stop(); start_split_stop();
} else if (!strcmp(buffer, "pause_resume")) { } else if (!strcmp(token, "pause-resume")) {
printf("Recieved pause_resume command\n");
pause_resume(); pause_resume();
} else if (!strcmp(buffer, "start-stop")) { } else if (!strcmp(token, "start-stop")) {
printf("Recieved start-stop command\n");
start_stop(); start_stop();
} else if (!strcmp(buffer, "start-split")) { } else if (!strcmp(token, "start-reset")) {
printf("Recieved start-split command\n"); start_reset();
} else if (!strcmp(token, "start-split")) {
start_split(); start_split();
} else if (!strcmp(buffer, "split-stop")) { } else if (!strcmp(token, "split-stop")) {
printf("Recieved split-stop command\n");
split_stop(); split_stop();
} else if (!strcmp(buffer, "undo-redo")) { } else if (!strcmp(token, "undo-redo")) {
printf("Recieved undo-redo command\n");
undo_redo(); undo_redo();
} else {
printf("Recieved invalid command, ignoring...\n"); //Getters
} else if (!strcmp(token, "get")) {
token = strtok(NULL, " ");
if (!strcmp(token, "current_time")) {
sendInt(sock, current_ms());
} else if (!strcmp(token, "current_time_with_pause")) {
int running_pause = 0;
struct timespec p, r;
bool tracking_pause = false;
for (int i = 0; i < runMarker; i++) {
if (run[i].type == PAUSE) {
sub_timespec(run[0].time, run[i].time, &p);
tracking_pause = true;
}
if (run[i].type == RESUME) {
sub_timespec(run[0].time, run[i].time, &r);
running_pause += timespecToMS(r) - timespecToMS(p);
tracking_pause = false;
} else if (i == runMarker - 1 && tracking_pause) {
running_pause += current_ms() - timespecToMS(p);
}
}
sendInt(sock, current_ms() - running_pause);
} else if (!strcmp(token, "run_count")) {
sendInt(sock, run_count);
} else if (!strcmp(token, "segment_count")) {
sendInt(sock, segment_count);
} else if (!strcmp(token, "route_count")) {
sendInt(sock, route_count);
} else if (!strcmp(token, "event_count")) {
sendInt(sock, runMarker);
} else if (!strcmp(token, "segment_shortname")) {
token = strtok(NULL, " ");
int x = atoi(token);
sendString(sock, segments[x].shortname);
} else if (!strcmp(token, "segment_longname")) {
token = strtok(NULL, " ");
int x = atoi(token);
sendString(sock, segments[x].longname);
} else if (!strcmp(token, "segment_description")) {
token = strtok(NULL, " ");
int x = atoi(token);
sendString(sock, segments[x].description);
} else if (!strcmp(token, "route_name")) {
token = strtok(NULL, " ");
int x = atoi(token);
sendString(sock, routes[x].name);
} else if (!strcmp(token, "route_segment_count")) {
token = strtok(NULL, " ");
int x = atoi(token);
sendInt(sock, routes[x].segment_count);
} else if (!strcmp(token, "route_segment_shortname")) {
token = strtok(NULL, " ");
int x = atoi(token);
token = strtok(NULL, " ");
int y = atoi(token);
sendString(sock, routes[x].segments[y].shortname);
} else if (!strcmp(token, "event_time")) {
token = strtok(NULL, " ");
int x;
if (!strcmp(token, "last"))
x = runMarker - 1;
else if (!strcmp(token, "first"))
x = 0;
else
x = atoi(token);
struct timespec t;
sub_timespec(run[0].time, run[x].time, &t);
sendInt(sock, timespecToMS(t));
} else if (!strcmp(token, "event_time_with_pause")) {
token = strtok(NULL, " ");
int x;
if (!strcmp(token, "last"))
x = runMarker - 1;
else if (!strcmp(token, "first"))
x = 0;
else
x = atoi(token);
int running_pause = 0;
struct timespec p, r;
bool tracking_pause = false;
for (int i = 0; i < x; i++) {
if (run[i].type == PAUSE) {
sub_timespec(run[0].time, run[i].time, &p);
tracking_pause = true;
}
if (run[i].type == RESUME) {
sub_timespec(run[0].time, run[i].time, &r);
running_pause += timespecToMS(r) - timespecToMS(p);
tracking_pause = false;
} else if (i == x - 1 && tracking_pause) {
sub_timespec(run[0].time, run[x].time, &r);
running_pause += timespecToMS(r) - timespecToMS(p);
}
}
struct timespec t;
sub_timespec(run[0].time, run[x].time, &t);
sendInt(sock, timespecToMS(t) - running_pause);
} else if (!strcmp(token, "event_type")) {
token = strtok(NULL, " ");
int x;
if (!strcmp(token, "last"))
x = runMarker - 1;
else if (!strcmp(token, "first"))
x = 0;
else
x = atoi(token);
char *reply;
switch (run[x].type) {
case START:
reply = "START";
break;
case SPLIT:
reply = "SPLIT";
break;
case SKIP:
reply = "SKIP";
break;
case PAUSE:
reply = "PAUSE";
break;
case RESUME:
reply = "RESUME";
break;
case RESET:
reply = "RESET";
break;
case STOP:
reply = "STOP";
break;
}
sendString(sock, reply);
} else if (!strcmp(token, "meta")) {
token = strtok(NULL, " ");
sendValue(sock, token);
}
//Setters
} else if (!strcmp(token, "set")) {
token = strtok(NULL, " ");
if (!strcmp(token, "meta")) {
token = strtok(NULL, " ");
char *token2 = strtok(NULL, " ");
set_metadata(token, token2);
save_metadata_to_file(token, token2);
}
} }
} }
@ -656,7 +811,7 @@ int main(int argc, char *argv[])
perror("ERROR on accept"); perror("ERROR on accept");
exit(1); exit(1);
} }
doprocessing(newsockfd); process_socket_input(newsockfd);
close(newsockfd); close(newsockfd);
} }
free(run); free(run);

View File

@ -193,7 +193,7 @@ int main (int argc, char *argv[])
char ti[13]; char ti[13];
//Request foreground color from config file //Request foreground color from config file
fp = popen("./result/bin/quest-log foreground", "r"); fp = popen("./result/bin/quest-log Foreground-Color", "r");
if (fgets(path, sizeof(path), fp)) { if (fgets(path, sizeof(path), fp)) {
if (strcmp(path, "DATA NOT PRESENT")) if (strcmp(path, "DATA NOT PRESENT"))
processColorString(&f, path); processColorString(&f, path);
@ -202,7 +202,7 @@ int main (int argc, char *argv[])
pclose(fp); pclose(fp);
//Request background color from config file //Request background color from config file
fp = popen("./result/bin/quest-log background", "r"); fp = popen("./result/bin/quest-log Background-Color", "r");
if (fgets(path, sizeof(path), fp)) { if (fgets(path, sizeof(path), fp)) {
if (strcmp(path, "DATA NOT PRESENT")) if (strcmp(path, "DATA NOT PRESENT"))
processColorString(&b, path); processColorString(&b, path);
@ -217,7 +217,7 @@ int main (int argc, char *argv[])
} }
while (1) { while (1) {
int time = 0; int time = 0;
fp = popen("./result/bin/quest-log time", "r"); fp = popen("./result/bin/quest-log current_time", "r");
if (fp == NULL) { if (fp == NULL) {
printf("Failed to run command\n"); printf("Failed to run command\n");
exit(1); exit(1);