this generally went unnoticed, as the tunnel usually terminates right before we exit anyway. however, if multiple Channels are synced, it may become visible. this is a "shotgun" implementation, where the main loop just reaps all unclaimed children. arguably, it would be cleaner if each socket actually tracked its own process, but getting synchronous kills+waits right is tricky, so we continue to pretend that there is no process as far as the socket layer is concerned. poll()/select() are not restartable, so they need EINTR handling now that SIGCHLD is actually delivered.
188 lines
4 KiB
C
188 lines
4 KiB
C
// SPDX-FileCopyrightText: 2022 Oswald Buddenhagen <ossi@users.sf.net>
|
|
// SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-isync-GPL-exception
|
|
//
|
|
// mbsync - mailbox synchronizer
|
|
//
|
|
|
|
#include "main_p.h"
|
|
|
|
typedef struct store_ent {
|
|
struct store_ent *next;
|
|
store_conf_t *conf;
|
|
} store_ent_t;
|
|
|
|
typedef struct {
|
|
core_vars_t *cvars;
|
|
store_conf_t *store;
|
|
driver_t *drv;
|
|
store_t *ctx;
|
|
store_ent_t *storeptr;
|
|
int cben, done;
|
|
} list_vars_t;
|
|
|
|
static store_ent_t *
|
|
add_store( store_ent_t ***storeapp, store_conf_t *store )
|
|
{
|
|
store_ent_t *se = nfzalloc( sizeof(*se) );
|
|
se->conf = store;
|
|
**storeapp = se;
|
|
*storeapp = &se->next;
|
|
return se;
|
|
}
|
|
|
|
static void do_list_stores( list_vars_t *lvars );
|
|
static void list_next_store( list_vars_t *lvars );
|
|
|
|
void
|
|
list_stores( core_vars_t *cvars, char **argv )
|
|
{
|
|
list_vars_t lvars[1];
|
|
store_ent_t *strs = NULL, **strapp = &strs;
|
|
store_conf_t *store;
|
|
|
|
memset( lvars, 0, sizeof(*lvars) );
|
|
lvars->cvars = cvars;
|
|
|
|
if (!stores) {
|
|
fputs( "No stores defined.\n", stderr );
|
|
cvars->ret = 1;
|
|
return;
|
|
}
|
|
|
|
if (!*argv) { // Implicit --all
|
|
for (store = stores; store; store = store->next)
|
|
add_store( &strapp, store );
|
|
} else {
|
|
for (; *argv; argv++) {
|
|
for (store = stores; store; store = store->next) {
|
|
if (!strcmp( store->name, *argv )) {
|
|
add_store( &strapp, store );
|
|
goto gotstr;
|
|
}
|
|
}
|
|
error( "No store named '%s' defined.\n", *argv );
|
|
cvars->ret = 1;
|
|
gotstr: ;
|
|
}
|
|
}
|
|
if (cvars->ret)
|
|
return;
|
|
lvars->storeptr = strs;
|
|
|
|
do_list_stores( lvars );
|
|
main_loop();
|
|
}
|
|
|
|
static void
|
|
list_store_bad( void *aux )
|
|
{
|
|
list_vars_t *lvars = (list_vars_t *)aux;
|
|
|
|
lvars->drv->cancel_store( lvars->ctx );
|
|
lvars->cvars->ret = 1;
|
|
list_next_store( lvars );
|
|
}
|
|
|
|
static void
|
|
advance_store( list_vars_t *lvars )
|
|
{
|
|
store_ent_t *nstr = lvars->storeptr->next;
|
|
free( lvars->storeptr );
|
|
lvars->storeptr = nstr;
|
|
}
|
|
|
|
static void list_store_connected( int sts, void *aux );
|
|
|
|
static void
|
|
do_list_stores( list_vars_t *lvars )
|
|
{
|
|
while (lvars->storeptr) {
|
|
lvars->store = lvars->storeptr->conf;
|
|
lvars->drv = lvars->store->driver;
|
|
int st = lvars->drv->get_fail_state( lvars->store );
|
|
if (st != FAIL_TEMP) {
|
|
info( "Skipping %sfailed store %s.\n",
|
|
(st == FAIL_WAIT) ? "temporarily " : "", lvars->store->name );
|
|
lvars->cvars->ret = 1;
|
|
goto next;
|
|
}
|
|
|
|
uint dcaps = lvars->drv->get_caps( NULL );
|
|
store_t *ctx = lvars->drv->alloc_store( lvars->store, "" );
|
|
if ((DFlags & DEBUG_DRV) || ((DFlags & FORCEASYNC(F)) && !(dcaps & DRV_ASYNC))) {
|
|
lvars->drv = &proxy_driver;
|
|
ctx = proxy_alloc_store( ctx, "", DFlags & FORCEASYNC(F) );
|
|
}
|
|
lvars->ctx = ctx;
|
|
lvars->drv->set_callbacks( ctx, NULL, list_store_bad, lvars );
|
|
info( "Opening store %s...\n", lvars->store->name );
|
|
lvars->cben = lvars->done = 0;
|
|
lvars->drv->connect_store( lvars->ctx, list_store_connected, lvars );
|
|
if (!lvars->done) {
|
|
lvars->cben = 1;
|
|
return;
|
|
}
|
|
|
|
next:
|
|
advance_store( lvars );
|
|
}
|
|
cleanup_mainloop();
|
|
}
|
|
|
|
static void
|
|
list_next_store( list_vars_t *lvars )
|
|
{
|
|
if (lvars->cben) {
|
|
advance_store( lvars );
|
|
do_list_stores( lvars );
|
|
}
|
|
}
|
|
|
|
static void
|
|
list_done_store( list_vars_t *lvars )
|
|
{
|
|
lvars->done = 1;
|
|
lvars->drv->free_store( lvars->ctx );
|
|
list_next_store( lvars );
|
|
}
|
|
|
|
static void list_store_listed( int sts, string_list_t *boxes, void *aux );
|
|
|
|
static void
|
|
list_store_connected( int sts, void *aux )
|
|
{
|
|
list_vars_t *lvars = (list_vars_t *)aux;
|
|
|
|
switch (sts) {
|
|
case DRV_CANCELED:
|
|
return;
|
|
case DRV_OK:
|
|
lvars->drv->list_store( lvars->ctx, LIST_INBOX | LIST_PATH_MAYBE, list_store_listed, lvars );
|
|
break;
|
|
default:
|
|
lvars->cvars->ret = 1;
|
|
list_done_store( lvars );
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
list_store_listed( int sts, string_list_t *boxes, void *aux )
|
|
{
|
|
list_vars_t *lvars = (list_vars_t *)aux;
|
|
string_list_t *box;
|
|
|
|
switch (sts) {
|
|
case DRV_CANCELED:
|
|
return;
|
|
case DRV_OK:
|
|
printf( "===== %s:\n", lvars->ctx->conf->name );
|
|
for (box = boxes; box; box = box->next)
|
|
puts( box->string );
|
|
break;
|
|
default:
|
|
lvars->cvars->ret = 1;
|
|
break;
|
|
}
|
|
list_done_store( lvars );
|
|
}
|