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 "config.h"
|
||||||
#include "ed2k.h"
|
#include "ed2k.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
/* Needed, bcuz of custom %B format */
|
/* Needed, bcuz of custom %B format */
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
@ -409,10 +410,12 @@ void api_free()
|
|||||||
uio_error("Cannot cancel api keepalive thread");
|
uio_error("Cannot cancel api keepalive thread");
|
||||||
} else {
|
} else {
|
||||||
int je = pthread_join(api_ka_thread, NULL);
|
int je = pthread_join(api_ka_thread, NULL);
|
||||||
if (je != 0) {
|
if (je != 0)
|
||||||
uio_error("Cannot join api keepalive thread: %s",
|
uio_error("Cannot join api keepalive thread: %s",
|
||||||
strerror(je));
|
strerror(je));
|
||||||
}
|
else
|
||||||
|
uio_debug("Keepalive thread ended");
|
||||||
|
|
||||||
if (pthread_mutex_destroy(&api_work_mx) != 0)
|
if (pthread_mutex_destroy(&api_work_mx) != 0)
|
||||||
uio_error("Cannot destroy api work mutex");
|
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)
|
static ssize_t api_send(char *buffer, size_t data_len, size_t buf_size)
|
||||||
{
|
{
|
||||||
ssize_t read_len;
|
ssize_t read_len;
|
||||||
|
int en;
|
||||||
|
|
||||||
api_ratelimit();
|
api_ratelimit();
|
||||||
uio_debug("{Api}: Sending: %.*s", (int)data_len, buffer);
|
uio_debug("{Api}: Sending: %.*s", (int)data_len, buffer);
|
||||||
if (api_encryption)
|
if (api_encryption)
|
||||||
data_len = api_encrypt(buffer, data_len);
|
data_len = api_encrypt(buffer, data_len);
|
||||||
|
|
||||||
if (net_send(buffer, data_len) == -1) {
|
en = net_send(buffer, data_len);
|
||||||
uio_error("Cannot send data: %s", strerror(errno));
|
if (en < 0)
|
||||||
return -1;
|
return en;
|
||||||
}
|
|
||||||
|
|
||||||
read_len = net_read(buffer, buf_size);
|
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();
|
api_ratelimit_sent();
|
||||||
|
|
||||||
if (api_encryption)
|
if (api_encryption)
|
||||||
@ -566,8 +581,11 @@ enum error api_cmd_version(struct api_result *res)
|
|||||||
enum error err = NOERR;
|
enum error err = NOERR;
|
||||||
pthread_mutex_lock(&api_work_mx);
|
pthread_mutex_lock(&api_work_mx);
|
||||||
|
|
||||||
if (res_len == -1) {
|
if (res_len < 0) {
|
||||||
err = ERR_API_COMMFAIL;
|
if (res_len == -2 && should_exit)
|
||||||
|
err = ERR_SHOULD_EXIT;
|
||||||
|
else
|
||||||
|
err = ERR_API_COMMFAIL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,8 +625,11 @@ static enum error api_cmd_auth(const char *uname, const char *pass,
|
|||||||
sizeof(buffer));
|
sizeof(buffer));
|
||||||
enum error err = NOERR;
|
enum error err = NOERR;
|
||||||
|
|
||||||
if (res_len == -1) {
|
if (res_len < 0) {
|
||||||
err = ERR_API_COMMFAIL;
|
if (res_len == -2 && should_exit)
|
||||||
|
err = ERR_SHOULD_EXIT;
|
||||||
|
else
|
||||||
|
err = ERR_API_COMMFAIL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,8 +674,11 @@ static enum error api_cmd_logout(struct api_result *res)
|
|||||||
long code;
|
long code;
|
||||||
enum error err = NOERR;
|
enum error err = NOERR;
|
||||||
|
|
||||||
if (res_len == -1) {
|
if (res_len < 0) {
|
||||||
err = ERR_API_COMMFAIL;
|
if (res_len == -2 && should_exit)
|
||||||
|
err = ERR_SHOULD_EXIT;
|
||||||
|
else
|
||||||
|
err = ERR_API_COMMFAIL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,8 +707,11 @@ enum error api_cmd_uptime(struct api_result *res)
|
|||||||
long code;
|
long code;
|
||||||
enum error err = NOERR;
|
enum error err = NOERR;
|
||||||
|
|
||||||
if (res_len == -1) {
|
if (res_len < 0) {
|
||||||
err = ERR_API_COMMFAIL;
|
if (res_len == -2 && should_exit)
|
||||||
|
err = ERR_SHOULD_EXIT;
|
||||||
|
else
|
||||||
|
err = ERR_API_COMMFAIL;
|
||||||
goto end;
|
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),
|
api_session, size, hash_str, ml_state, watched),
|
||||||
sizeof(buffer));
|
sizeof(buffer));
|
||||||
|
|
||||||
if (res_len == -1) {
|
if (res_len < 0) {
|
||||||
err = ERR_API_COMMFAIL;
|
if (res_len == -2 && should_exit)
|
||||||
|
err = ERR_SHOULD_EXIT;
|
||||||
|
else
|
||||||
|
err = ERR_API_COMMFAIL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,39 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "uio.h"
|
#include "uio.h"
|
||||||
#include "cmd.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 main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int exit_code = EXIT_SUCCESS;
|
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)
|
if (err == ERR_OPT_EXIT)
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
else if (err != NOERR)
|
else if (err != NOERR)
|
||||||
@ -20,7 +42,9 @@ int main(int argc, char **argv)
|
|||||||
//config_dump();
|
//config_dump();
|
||||||
|
|
||||||
err = cmd_main();
|
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;
|
exit_code = EXIT_FAILURE;
|
||||||
|
|
||||||
config_free();
|
config_free();
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "ed2k.h"
|
#include "ed2k.h"
|
||||||
#include "ed2k_util.h"
|
#include "ed2k_util.h"
|
||||||
#include "uio.h"
|
#include "uio.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
static struct ed2k_util_opts l_opts;
|
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];
|
unsigned char buf[blksize], hash[ED2K_HASH_SIZE];
|
||||||
struct ed2k_ctx ed2k;
|
struct ed2k_ctx ed2k;
|
||||||
|
enum error err;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
size_t read_len;
|
size_t read_len;
|
||||||
|
int en;
|
||||||
|
|
||||||
if (l_opts.pre_hash_fn) {
|
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)
|
if (err == ED2KUTIL_DONTHASH)
|
||||||
return NOERR;
|
return NOERR;
|
||||||
else if (err != 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");
|
f = fopen(file_path, "rb");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
uio_error("Failed to open file: %s (%s)", file_path, strerror(errno));
|
en = errno;
|
||||||
return ERR_ED2KUTIL_FS;
|
|
||||||
|
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);
|
ed2k_init(&ed2k);
|
||||||
read_len = fread(buf, 1, sizeof(buf), f);
|
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);
|
ed2k_update(&ed2k, buf, read_len);
|
||||||
read_len = fread(buf, 1, sizeof(buf), f);
|
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);
|
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)
|
if (l_opts.post_hash_fn)
|
||||||
return l_opts.post_hash_fn(file_path, hash, st, l_opts.data);
|
return l_opts.post_hash_fn(file_path, hash, st, l_opts.data);
|
||||||
return NOERR;
|
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,
|
static int ed2k_util_walk(const char *fpath, const struct stat *sb,
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
E(ERR_THRD) /* Generic pthread error */ \
|
E(ERR_THRD) /* Generic pthread error */ \
|
||||||
\
|
\
|
||||||
E(ERR_LIBEVENT) /* There are some problem with a libevent function */ \
|
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) \
|
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);
|
ssize_t w_len = send(net_socket, msg, msg_len, 0);
|
||||||
if (w_len == -1) {
|
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 -1;
|
||||||
}
|
}
|
||||||
return w_len;
|
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);
|
ssize_t read = recv(net_socket, out_data, read_size, 0);
|
||||||
if (read == -1) {
|
if (read == -1) {
|
||||||
|
int en = errno;
|
||||||
|
|
||||||
uio_error("{net} Read failed: %s", strerror(errno));
|
uio_error("{net} Read failed: %s", strerror(errno));
|
||||||
|
if (en == EINTR)
|
||||||
|
return -2;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (read == read_size)
|
||||||
|
uio_warning("{net} Data may have been discarded!");
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ enum error net_init();
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Send and read data to and from the api
|
* 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_send(const void *msg, size_t msg_len);
|
||||||
ssize_t net_read(void *out_data, size_t read_size);
|
ssize_t net_read(void *out_data, size_t read_size);
|
||||||
|
Loading…
Reference in New Issue
Block a user