Graceful C-c termination 1/2
This commit is contained in:
parent
9a00b28279
commit
6cf62ab039
62
src/api.c
62
src/api.c
@ -15,6 +15,7 @@
|
||||
#include "config.h"
|
||||
#include "ed2k.h"
|
||||
#include "util.h"
|
||||
#include "globals.h"
|
||||
|
||||
/* Needed, bcuz of custom %B format */
|
||||
#pragma GCC diagnostic push
|
||||
@ -409,10 +410,12 @@ void api_free()
|
||||
uio_error("Cannot cancel api keepalive thread");
|
||||
} else {
|
||||
int je = pthread_join(api_ka_thread, NULL);
|
||||
if (je != 0) {
|
||||
if (je != 0)
|
||||
uio_error("Cannot join api keepalive thread: %s",
|
||||
strerror(je));
|
||||
}
|
||||
else
|
||||
uio_debug("Keepalive thread ended");
|
||||
|
||||
if (pthread_mutex_destroy(&api_work_mx) != 0)
|
||||
uio_error("Cannot destroy api work mutex");
|
||||
}
|
||||
@ -473,21 +476,33 @@ static void api_ratelimit()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the written byte count
|
||||
* Or -1 on error, and -2 if errno was EINTR
|
||||
*/
|
||||
static ssize_t api_send(char *buffer, size_t data_len, size_t buf_size)
|
||||
{
|
||||
ssize_t read_len;
|
||||
int en;
|
||||
|
||||
api_ratelimit();
|
||||
uio_debug("{Api}: Sending: %.*s", (int)data_len, buffer);
|
||||
if (api_encryption)
|
||||
data_len = api_encrypt(buffer, data_len);
|
||||
|
||||
if (net_send(buffer, data_len) == -1) {
|
||||
uio_error("Cannot send data: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
en = net_send(buffer, data_len);
|
||||
if (en < 0)
|
||||
return en;
|
||||
|
||||
read_len = net_read(buffer, buf_size);
|
||||
if (read_len < 0) {
|
||||
uio_error("!!! BAD PLACE EINTR !!! report pls");
|
||||
return en; /* This could lead so some problems if we also want to
|
||||
log out. If we hit this, the msg got sent, but we
|
||||
couldn't read the response. That means, in the
|
||||
logout call, this msg's data will be read
|
||||
Let's see if this ever comes up */
|
||||
}
|
||||
api_ratelimit_sent();
|
||||
|
||||
if (api_encryption)
|
||||
@ -566,8 +581,11 @@ enum error api_cmd_version(struct api_result *res)
|
||||
enum error err = NOERR;
|
||||
pthread_mutex_lock(&api_work_mx);
|
||||
|
||||
if (res_len == -1) {
|
||||
err = ERR_API_COMMFAIL;
|
||||
if (res_len < 0) {
|
||||
if (res_len == -2 && should_exit)
|
||||
err = ERR_SHOULD_EXIT;
|
||||
else
|
||||
err = ERR_API_COMMFAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -607,8 +625,11 @@ static enum error api_cmd_auth(const char *uname, const char *pass,
|
||||
sizeof(buffer));
|
||||
enum error err = NOERR;
|
||||
|
||||
if (res_len == -1) {
|
||||
err = ERR_API_COMMFAIL;
|
||||
if (res_len < 0) {
|
||||
if (res_len == -2 && should_exit)
|
||||
err = ERR_SHOULD_EXIT;
|
||||
else
|
||||
err = ERR_API_COMMFAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -653,8 +674,11 @@ static enum error api_cmd_logout(struct api_result *res)
|
||||
long code;
|
||||
enum error err = NOERR;
|
||||
|
||||
if (res_len == -1) {
|
||||
err = ERR_API_COMMFAIL;
|
||||
if (res_len < 0) {
|
||||
if (res_len == -2 && should_exit)
|
||||
err = ERR_SHOULD_EXIT;
|
||||
else
|
||||
err = ERR_API_COMMFAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -683,8 +707,11 @@ enum error api_cmd_uptime(struct api_result *res)
|
||||
long code;
|
||||
enum error err = NOERR;
|
||||
|
||||
if (res_len == -1) {
|
||||
err = ERR_API_COMMFAIL;
|
||||
if (res_len < 0) {
|
||||
if (res_len == -2 && should_exit)
|
||||
err = ERR_SHOULD_EXIT;
|
||||
else
|
||||
err = ERR_API_COMMFAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -729,8 +756,11 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
|
||||
api_session, size, hash_str, ml_state, watched),
|
||||
sizeof(buffer));
|
||||
|
||||
if (res_len == -1) {
|
||||
err = ERR_API_COMMFAIL;
|
||||
if (res_len < 0) {
|
||||
if (res_len == -2 && should_exit)
|
||||
err = ERR_SHOULD_EXIT;
|
||||
else
|
||||
err = ERR_API_COMMFAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,39 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "error.h"
|
||||
#include "uio.h"
|
||||
#include "cmd.h"
|
||||
#include "globals.h"
|
||||
|
||||
bool should_exit = false;
|
||||
|
||||
static void signal_handler(int signum, siginfo_t *info, void *ctx)
|
||||
{
|
||||
should_exit = true;
|
||||
printf("\033[0GGot C-c. Press again to force exit\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int exit_code = EXIT_SUCCESS;
|
||||
enum error err = config_parse(argc, argv);
|
||||
enum error err;
|
||||
struct sigaction sact = {
|
||||
.sa_flags = SA_SIGINFO | SA_RESETHAND,
|
||||
//.sa_flags = SA_SIGINFO,
|
||||
.sa_sigaction = signal_handler,
|
||||
};
|
||||
|
||||
if (sigaction(SIGINT, &sact, NULL) != 0) {
|
||||
uio_error("Cannot set up signal handler: %s", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
err = config_parse(argc, argv);
|
||||
if (err == ERR_OPT_EXIT)
|
||||
return EXIT_SUCCESS;
|
||||
else if (err != NOERR)
|
||||
@ -20,7 +42,9 @@ int main(int argc, char **argv)
|
||||
//config_dump();
|
||||
|
||||
err = cmd_main();
|
||||
if (err != NOERR)
|
||||
if (err == ERR_SHOULD_EXIT)
|
||||
uio_debug("Exiting as requested orz");
|
||||
else if (err != NOERR)
|
||||
exit_code = EXIT_FAILURE;
|
||||
|
||||
config_free();
|
||||
|
@ -3,10 +3,12 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ftw.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ed2k.h"
|
||||
#include "ed2k_util.h"
|
||||
#include "uio.h"
|
||||
#include "globals.h"
|
||||
|
||||
static struct ed2k_util_opts l_opts;
|
||||
|
||||
@ -15,11 +17,13 @@ static enum error ed2k_util_hash(const char *file_path, blksize_t blksize,
|
||||
{
|
||||
unsigned char buf[blksize], hash[ED2K_HASH_SIZE];
|
||||
struct ed2k_ctx ed2k;
|
||||
enum error err;
|
||||
FILE *f;
|
||||
size_t read_len;
|
||||
int en;
|
||||
|
||||
if (l_opts.pre_hash_fn) {
|
||||
enum error err = l_opts.pre_hash_fn(file_path, st, l_opts.data);
|
||||
err = l_opts.pre_hash_fn(file_path, st, l_opts.data);
|
||||
if (err == ED2KUTIL_DONTHASH)
|
||||
return NOERR;
|
||||
else if (err != NOERR)
|
||||
@ -28,24 +32,52 @@ static enum error ed2k_util_hash(const char *file_path, blksize_t blksize,
|
||||
|
||||
f = fopen(file_path, "rb");
|
||||
if (!f) {
|
||||
uio_error("Failed to open file: %s (%s)", file_path, strerror(errno));
|
||||
return ERR_ED2KUTIL_FS;
|
||||
en = errno;
|
||||
|
||||
uio_error("Failed to open file: %s (%s)", file_path, strerror(en));
|
||||
if (en == EINTR && should_exit)
|
||||
return ERR_SHOULD_EXIT;
|
||||
else
|
||||
return ERR_ED2KUTIL_FS;
|
||||
}
|
||||
|
||||
ed2k_init(&ed2k);
|
||||
read_len = fread(buf, 1, sizeof(buf), f);
|
||||
while (read_len > 0) {
|
||||
/* From my test, fread wont return anything special on signal interrupt */
|
||||
while (read_len > 0 && !should_exit) {
|
||||
ed2k_update(&ed2k, buf, read_len);
|
||||
read_len = fread(buf, 1, sizeof(buf), f);
|
||||
}
|
||||
// TODO check if eof or error
|
||||
if (should_exit) {
|
||||
err = ERR_SHOULD_EXIT;
|
||||
goto fail;
|
||||
}
|
||||
if (ferror(f)) { /* Loop stopped bcuz of error, not EOF */
|
||||
uio_error("Failure while reading file");
|
||||
err = ERR_ED2KUTIL_FS;
|
||||
goto fail;
|
||||
}
|
||||
assert(feof(f));
|
||||
|
||||
ed2k_final(&ed2k, hash);
|
||||
fclose(f);
|
||||
if (fclose(f) != 0) {
|
||||
en = errno;
|
||||
|
||||
uio_debug("Fclose failed: %s", strerror(en));
|
||||
if (en == EINTR && should_exit)
|
||||
return ERR_SHOULD_EXIT;
|
||||
else
|
||||
return ERR_ED2KUTIL_FS;
|
||||
}
|
||||
|
||||
if (l_opts.post_hash_fn)
|
||||
return l_opts.post_hash_fn(file_path, hash, st, l_opts.data);
|
||||
return NOERR;
|
||||
|
||||
fail:
|
||||
if (f) /* We can't get a 2nd interrupt now */
|
||||
fclose(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ed2k_util_walk(const char *fpath, const struct stat *sb,
|
||||
|
@ -45,6 +45,8 @@
|
||||
E(ERR_THRD) /* Generic pthread error */ \
|
||||
\
|
||||
E(ERR_LIBEVENT) /* There are some problem with a libevent function */ \
|
||||
\
|
||||
E(ERR_SHOULD_EXIT) /* Probably got a C-c, program should exit now */ \
|
||||
E(_ERR_COUNT) \
|
||||
|
||||
|
||||
|
7
src/globals.h
Normal file
7
src/globals.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _GLOBALS_H
|
||||
#define _GLOBALS_H
|
||||
#include <stdbool.h>
|
||||
|
||||
extern bool should_exit;
|
||||
|
||||
#endif /* _GLOBALS_H */
|
12
src/net.c
12
src/net.c
@ -248,7 +248,11 @@ ssize_t net_send(const void *msg, size_t msg_len)
|
||||
{
|
||||
ssize_t w_len = send(net_socket, msg, msg_len, 0);
|
||||
if (w_len == -1) {
|
||||
uio_error("{net} Send failed: %s", strerror(errno));
|
||||
int en = errno;
|
||||
|
||||
uio_error("{net} Send failed: %s", strerror(en));
|
||||
if (en == EINTR)
|
||||
return -2;
|
||||
return -1;
|
||||
}
|
||||
return w_len;
|
||||
@ -258,8 +262,14 @@ ssize_t net_read(void* out_data, size_t read_size)
|
||||
{
|
||||
ssize_t read = recv(net_socket, out_data, read_size, 0);
|
||||
if (read == -1) {
|
||||
int en = errno;
|
||||
|
||||
uio_error("{net} Read failed: %s", strerror(errno));
|
||||
if (en == EINTR)
|
||||
return -2;
|
||||
return -1;
|
||||
}
|
||||
if (read == read_size)
|
||||
uio_warning("{net} Data may have been discarded!");
|
||||
return read;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ enum error net_init();
|
||||
|
||||
/*
|
||||
* Send and read data to and from the api
|
||||
* Returns the number of bytes sent/read or -1 on error
|
||||
* If the error is EINTR, it returns -2
|
||||
*/
|
||||
ssize_t net_send(const void *msg, size_t msg_len);
|
||||
ssize_t net_read(void *out_data, size_t read_size);
|
||||
|
Loading…
Reference in New Issue
Block a user