int reusable_tape( tape_t *tp) { int count = 0; if(tp == NULL) return 0; if(tp->reuse == 0) return 0; if( g_str_equal(tp->datestamp, "0")) return 1; while(tp != NULL) { if(tp->reuse == 1) count++; tp = tp->prev; } return (count >= getconf_int(CNF_TAPECYCLE)); }
tape_t * lookup_last_reusable_tape( int skip) { tape_t *tp, **tpsave; int count=0; int s; int tapecycle = getconf_int(CNF_TAPECYCLE); labelstr_t *labelstr = getconf_labelstr(CNF_LABELSTR); autolabel_t *autolabel = getconf_autolabel(CNF_AUTOLABEL); /* * The idea here is we keep the last "several" reusable tapes we * find in a stack and then return the n-th oldest one to the * caller. If skip is zero, the oldest is returned, if it is * one, the next oldest, two, the next to next oldest and so on. */ tpsave = g_malloc((skip + 1) * sizeof(*tpsave)); for(s = 0; s <= skip; s++) { tpsave[s] = NULL; } for(tp = tape_list; tp != NULL; tp = tp->next) { if (tp->reuse == 1 && !g_str_equal(tp->datestamp, "0") && match_labelstr(labelstr, autolabel, tp->label, tp->barcode, tp->meta)) { count++; for(s = skip; s > 0; s--) { tpsave[s] = tpsave[s - 1]; } tpsave[0] = tp; } } s = tapecycle - count; if(s < 0) s = 0; if(count < tapecycle - skip) tp = NULL; else tp = tpsave[skip - s]; amfree(tpsave); return tp; }
int connect_to_ndmp_proxy(char **errmsg) { int i; int proxy_port; int fd; *errmsg = NULL; proxy_port = getconf_int(CNF_NDMP_PROXY_PORT); if (proxy_port == 0) { *errmsg = g_strdup("no NDMP-PROXY-PORT configured; cannot start NDMP proxy"); } /* we loop until getting a successful connection, either from a proxy we * launched or a proxy another process launched. We only do this a few * times, though, in case there's some problem starting the proxy, or * something already running on that port. */ for (i = 0; i < 3; i++) { g_debug("openning a connection to ndmp-proxy on port %d", proxy_port); fd = stream_client("localhost", proxy_port, 32768, 32768, NULL, 0); if (fd >= 0) { g_debug("connected to ndmp-proxy"); return fd; } g_debug("Could not connect to ndmp-proxy: %s; trying to start a new instance", strerror(errno)); *errmsg = start_ndmp_proxy(); if (*errmsg) { return -1; } } *errmsg = stralloc(_("failed to open a connection to ndmp-proxy")); return -1; }
int main( int argc, char ** argv) { config_overrides_t *cfg_ovr; char *hostname; char *auth; char *service; int opt; extern int optind; extern char *optarg; FILE *input_file; int use_connect = 0; int got_input_file = 0; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amservice"); /* drop root privileges */ if (!set_root_privs(0)) { error(_("amservice must be run setuid root")); } /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); add_amanda_log_handler(amanda_log_stderr); our_features = am_init_feature_set(); our_feature_string = am_feature_to_string(our_features); /* process arguments */ cfg_ovr = new_config_overrides(argc/2); input_file = stdin; while((opt = getopt_long(argc, argv, "o:f:s", long_options, NULL)) != EOF) { switch(opt) { case 1: printf("amservice-%s\n", VERSION); return(0); break; case 'o': add_config_override_opt(cfg_ovr, optarg); break; case 'f': if (got_input_file == 1) { g_critical("Invalid two -f argument"); exit(1); } got_input_file = 1; if (*optarg == '/') { input_file = fopen(optarg, "r"); } else { char *name = g_strjoin(NULL, get_original_cwd(), "/", optarg, NULL); input_file = fopen(name, "r"); amfree(name); } if (!input_file) { g_critical("Cannot open output file '%s': %s", optarg, strerror(errno)); exit(1); } break; case 's': use_connect = 1; break; } } if (use_connect && !got_input_file) { g_critical("The -s option require -f"); exit(1); } argc -= optind, argv += optind; if(argc < 3) usage(); /* set a default config */ set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_CLIENT, NULL); dbrename(get_config_name(), DBG_SUBDIR_SERVER); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT); hostname = argv[0]; auth = argv[1]; service = argv[2]; /* start client side checks */ copy_stream = use_connect && got_input_file; client_protocol(hostname, auth, service, input_file); amfree(our_feature_string); am_release_feature_set(our_features); our_features = NULL; if (got_input_file) fclose(input_file); dbclose(); return(remote_errors != 0); }
/* * The reply wait state. We enter here much like we do with s_ackwait. */ static p_action_t s_repwait( proto_t * p, p_action_t action, pkt_t * pkt) { pkt_t ack; /* * Timeout waiting for a reply. */ if (action == PA_TIMEOUT) { assert(pkt == NULL); /* * If we've blown our timeout limit, free up this packet and * return. */ if (p->resettries == 0 || DROP_DEAD_TIME(p->origtime)) { security_seterror(p->security_handle, _("timeout waiting for REP")); return (PA_ABORT); } /* * We still have some tries left. Resend the request. */ p->resettries--; p->state = s_sendreq; p->reqtries = getconf_int(CNF_REQ_TRIES); return (PA_CONTINUE); } assert(action == PA_RCVDATA); /* Finish if we get a NAK */ if (pkt->type == P_NAK) return (PA_FINISH); /* * We've received some data. If we didn't get a reply, * requeue the packet and retry. Otherwise, acknowledge * the reply, cleanup this packet, and return. */ if (pkt->type != P_REP && pkt->type != P_PREP) return (PA_PENDING); if(pkt->type == P_REP) { pkt_init_empty(&ack, P_ACK); if (security_sendpkt(p->security_handle, &ack) < 0) { /* XXX should retry */ amfree(ack.body); security_seterror(p->security_handle, _("error sending ACK: %s"), security_geterror(p->security_handle)); return (PA_ABORT); } amfree(ack.body); return (PA_FINISH); } else if(pkt->type == P_PREP) { p->timeout = p->repwait - CURTIME + p->curtime + 1; if (p->timeout <= 0) p->timeout = 1; return (PA_CONTPEND); } /* should never go here, shut up compiler warning */ return (PA_FINISH); }
/* * Generate a request packet, and submit it to the state machine * for transmission. */ void protocol_sendreq( const char * hostname, const security_driver_t * security_driver, char * (*conf_fn)(char *, void *), const char * req, time_t repwait, protocol_sendreq_callback continuation, void * datap) { proto_t *p; static char *platform = NULL; static char *distro = NULL; p = g_malloc(sizeof(proto_t)); p->state = s_sendreq; p->hostname = g_strdup(hostname); p->security_driver = security_driver; /* p->security_handle set in connect_callback */ p->repwait = repwait; p->origtime = CURTIME; /* p->curtime set in the sendreq state */ p->connecttries = getconf_int(CNF_CONNECT_TRIES); p->resettries = RESET_TRIES; p->reqtries = getconf_int(CNF_REQ_TRIES); p->conf_fn = conf_fn; pkt_init(&p->req, P_REQ, "%s", req); /* * These are here for the caller * We call the continuation function after processing is complete. * We pass the datap on through untouched. It is here so the caller * has a way to keep state with each request. */ p->continuation = continuation; p->datap = datap; p->event_handle = NULL; proto_debug(1, _("protocol: security_connect: host %s -> p %p\n"), hostname, p); if (!platform && !distro) { get_platform_and_distro(&platform, &distro); } if (distro != NULL && !g_str_equal(distro, "mac") && #if defined HAVE_FUNC_GETSERVBYNAME_R_4 || defined HAVE_FUNC_GETSERVBYNAME_R_5 || defined HAVE_FUNC_GETSERVBYNAME_R_6 1 && #else 0 && #endif ( #ifdef BSDTCP_SECURITY security_driver == &bsdtcp_security_driver || #endif security_driver == &local_security_driver || #ifdef RSH_SECURITY security_driver == &rsh_security_driver || #endif #ifdef SSL_SECURITY security_driver == &ssl_security_driver || #endif #ifdef SSH_SECURITY security_driver == &ssh_security_driver || #endif 0)) { g_thread_create(connect_thread, (gpointer)p, TRUE, NULL); g_mutex_lock(protocol_mutex); nb_thread++; g_mutex_unlock(protocol_mutex); } else { // bsd_security_driver no connect,all use same socket // bsdudp_security_driver no connect,all use same socket // krb5_security_driver untested security_connect(p->security_driver, p->hostname, p->conf_fn, connect_callbackX, p, p->datap); } }
void update_info_dumper( disk_t *dp, off_t origsize, off_t dumpsize, time_t dumptime) { int level, i; info_t info; stats_t *infp; perf_t *perfp; char *conf_infofile; level = sched(dp)->level; conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE)); if (open_infofile(conf_infofile)) { error(_("could not open info db \"%s\""), conf_infofile); /*NOTREACHED*/ } amfree(conf_infofile); get_info(dp->host->hostname, dp->name, &info); /* Clean up information about this and higher-level dumps. This assumes that update_info_dumper() is always run before update_info_taper(). */ for (i = level; i < DUMP_LEVELS; ++i) { infp = &info.inf[i]; infp->size = (off_t)-1; infp->csize = (off_t)-1; infp->secs = (time_t)-1; infp->date = (time_t)-1; infp->label[0] = '\0'; infp->filenum = 0; } /* now store information about this dump */ infp = &info.inf[level]; infp->size = origsize; infp->csize = dumpsize; infp->secs = dumptime; if (sched(dp)->timestamp == 0) { infp->date = 0; } else { infp->date = get_time_from_timestamp(sched(dp)->datestamp); } if(level == 0) perfp = &info.full; else perfp = &info.incr; /* Update the stats, but only if the new values are meaningful */ if(dp->compress != COMP_NONE && origsize > (off_t)0) { newperf(perfp->comp, (double)dumpsize/(double)origsize); } if(dumptime > (time_t)0) { if((off_t)dumptime >= dumpsize) newperf(perfp->rate, 1); else newperf(perfp->rate, (double)dumpsize/(double)dumptime); } if(origsize >= (off_t)0 && getconf_int(CNF_RESERVE)<100) { info.command = NO_COMMAND; } if (origsize >= (off_t)0 && level == info.last_level) { info.consecutive_runs++; } else if (origsize >= (off_t)0) { info.last_level = level; info.consecutive_runs = 1; } if(origsize >= (off_t)0 && dumpsize >= (off_t)0) { for(i=NB_HISTORY-1;i>0;i--) { info.history[i] = info.history[i-1]; } info.history[0].level = level; info.history[0].size = origsize; info.history[0].csize = dumpsize; if (sched(dp)->timestamp == 0) { info.history[0].date = 0; } else { info.history[0].date = get_time_from_timestamp(sched(dp)->datestamp); } info.history[0].secs = dumptime; } if (put_info(dp->host->hostname, dp->name, &info)) { int save_errno = errno; g_fprintf(stderr, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); log_add(L_ERROR, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); error(_("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); /*NOTREACHED*/ } close_infofile(); }
/* Link up the TaperSource with the Device, including retries etc. */ static void run_device_output(taper_state_t * taper_state, dump_info_t * dump_info) { GValue val; guint file_number; dump_info->current_part = 1; dump_info->total_time.tv_sec = 0; dump_info->total_time.tv_usec = 0; dump_info->total_bytes = 0; for (;;) { GTimeVal start_time, end_time, run_time; StreamingRequirement streaming_mode; queue_result_flags queue_result; CountingConsumerData consumer_data; dumpfile_t *this_header; size_t max_memory; this_header = munge_headers(dump_info); if (this_header == NULL) { char * qdiskname = quote_string(dump_info->diskname); char * errstr = taper_source_get_errmsg(dump_info->source); if (!errstr) errstr = "Failed reading dump header."; errstr = quote_string(errstr); putresult(FAILED, "%s INPUT-ERROR TAPE-GOOD %s \"\"\n", dump_info->handle, errstr); log_add(L_FAIL, "%s %s %s %d %s", dump_info->hostname, qdiskname, dump_info->timestamp, dump_info->level, errstr); amfree(qdiskname); amfree(errstr); return; } if (!find_and_label_new_tape(taper_state, dump_info)) { bail_no_volume(dump_info, taper_state->last_errmsg); dumpfile_free(this_header); return; } while (!device_start_file(taper_state->device, this_header)) { /* Close the device. */ device_finish(taper_state->device); g_object_unref(taper_state->device); taper_state->device = NULL; if (!find_and_label_new_tape(taper_state, dump_info)) { bail_no_volume(dump_info, taper_state->last_errmsg); dumpfile_free(this_header); return; } } dumpfile_free(this_header); bzero(&val, sizeof(val)); if (!device_property_get(taper_state->device, PROPERTY_STREAMING, &val) || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) { g_fprintf(stderr, "taper: Couldn't get streaming type!\n"); streaming_mode = STREAMING_REQUIREMENT_REQUIRED; } else { streaming_mode = g_value_get_enum(&val); } file_number = taper_state->device->file; consumer_data.next_consumer = device_write_consumer; consumer_data.next_consumer_data = taper_state->device; consumer_data.bytes_written = 0; g_get_current_time(&start_time); if (getconf_seen(CNF_DEVICE_OUTPUT_BUFFER_SIZE)) { max_memory = getconf_size(CNF_DEVICE_OUTPUT_BUFFER_SIZE); if (getconf_seen(CNF_TAPEBUFS)) { g_fprintf(stderr, "Configuration directives 'device_output_buffer_size' " "and \n" "'tapebufs' are incompatible; using former.\n"); } } else if (getconf_seen(CNF_TAPEBUFS)) { max_memory = getconf_int(CNF_TAPEBUFS) * taper_state->device->block_size; } else { /* Use default. */ max_memory = getconf_size(CNF_DEVICE_OUTPUT_BUFFER_SIZE); } queue_result = do_consumer_producer_queue_full (taper_source_producer, dump_info->source, counting_consumer, &consumer_data, taper_state->device->block_size, max_memory, streaming_mode); g_get_current_time(&end_time); run_time = timesub(end_time, start_time); /* The device_write_consumer leaves the file open, so close it now. */ if (!device_finish_file(taper_state->device)) { queue_result = queue_result | QUEUE_CONSUMER_ERROR; } if (!finish_part_attempt(taper_state, dump_info, queue_result, run_time, consumer_data.bytes_written)) { break; } } }
int main( int argc, char ** argv) { int foreground; int batch; int redirect; char **datearg = NULL; int nb_datearg = 0; char *conf_diskfile; char *conf_tapelist; char *conf_logfile; int conf_usetimestamps; disklist_t diskq; disk_t *dp; pid_t pid; pid_t driver_pid, reporter_pid; amwait_t exitcode; int opt; GSList *holding_list=NULL, *holding_file; int driver_pipe[2]; char date_string[100]; char date_string_standard[100]; time_t today; char *errstr; struct tm *tm; char *tapedev; char *tpchanger; char *qdisk, *qhname; GSList *datestamp_list = NULL; config_overrides_t *cfg_ovr; char **config_options; find_result_t *holding_files; disklist_t holding_disklist = { NULL, NULL }; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amflush"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); add_amanda_log_handler(amanda_log_stderr); foreground = 0; batch = 0; redirect = 1; /* process arguments */ cfg_ovr = new_config_overrides(argc/2); while((opt = getopt(argc, argv, "bfso:D:")) != EOF) { switch(opt) { case 'b': batch = 1; break; case 'f': foreground = 1; break; case 's': redirect = 0; break; case 'o': add_config_override_opt(cfg_ovr, optarg); break; case 'D': if (datearg == NULL) datearg = g_malloc(21*sizeof(char *)); if(nb_datearg == 20) { g_fprintf(stderr,_("maximum of 20 -D arguments.\n")); exit(1); } datearg[nb_datearg++] = g_strdup(optarg); datearg[nb_datearg] = NULL; break; } } argc -= optind, argv += optind; if(!foreground && !redirect) { g_fprintf(stderr,_("Can't redirect to stdout/stderr if not in forground.\n")); exit(1); } if(argc < 1) { error(_("Usage: amflush [-b] [-f] [-s] [-D date]* [-o configoption]* <confdir> [host [disk]* ]*")); /*NOTREACHED*/ } set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_EXPLICIT_NAME, argv[0]); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskq); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); /* load DLEs from the holding disk, in case there's anything to flush there */ search_holding_disk(&holding_files, &holding_disklist); /* note that the dumps are added to the global disklist, so we need not * consult holding_files or holding_disklist after this. The holding-only * dumps will be filtered properly by match_disklist, setting the dp->todo * flag appropriately. */ errstr = match_disklist(&diskq, argc-1, argv+1); if (errstr) { g_printf(_("%s"),errstr); amfree(errstr); } conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); conf_usetimestamps = getconf_boolean(CNF_USETIMESTAMPS); amflush_datestamp = get_datestamp_from_time(0); if(conf_usetimestamps == 0) { amflush_timestamp = g_strdup(amflush_datestamp); } else { amflush_timestamp = get_timestamp_from_time(0); } conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); conf_logfile = g_strjoin(NULL, conf_logdir, "/log", NULL); if (access(conf_logfile, F_OK) == 0) { run_amcleanup(get_config_name()); } if (access(conf_logfile, F_OK) == 0) { char *process_name = get_master_process(conf_logfile); error(_("%s exists: %s is already running, or you must run amcleanup"), conf_logfile, process_name); /*NOTREACHED*/ } driver_program = g_strjoin(NULL, amlibexecdir, "/", "driver", NULL); reporter_program = g_strjoin(NULL, sbindir, "/", "amreport", NULL); logroll_program = g_strjoin(NULL, amlibexecdir, "/", "amlogroll", NULL); tapedev = getconf_str(CNF_TAPEDEV); tpchanger = getconf_str(CNF_TPCHANGER); if (tapedev == NULL && tpchanger == NULL) { error(_("No tapedev or tpchanger specified")); } /* if dates were specified (-D), then use match_datestamp * against the list of all datestamps to turn that list * into a set of existing datestamps (basically, evaluate the * expressions into actual datestamps) */ if(datearg) { GSList *all_datestamps; GSList *datestamp; int i, ok; all_datestamps = holding_get_all_datestamps(); for(datestamp = all_datestamps; datestamp != NULL; datestamp = datestamp->next) { ok = 0; for(i=0; i<nb_datearg && ok==0; i++) { ok = match_datestamp(datearg[i], (char *)datestamp->data); } if (ok) datestamp_list = g_slist_insert_sorted(datestamp_list, g_strdup((char *)datestamp->data), g_compare_strings); } slist_free_full(all_datestamps, g_free); } else { /* otherwise, in batch mode, use all datestamps */ if(batch) { datestamp_list = holding_get_all_datestamps(); } /* or allow the user to pick datestamps */ else { datestamp_list = pick_datestamp(); } } if(!datestamp_list) { g_printf(_("Could not find any Amanda directories to flush.\n")); exit(1); } holding_list = holding_get_files_for_flush(datestamp_list); if (holding_list == NULL) { g_printf(_("Could not find any valid dump image, check directory.\n")); exit(1); } if (access(conf_logfile, F_OK) == 0) { char *process_name = get_master_process(conf_logfile); error(_("%s exists: someone started %s"), conf_logfile, process_name); /*NOTREACHED*/ } log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid()); if(!batch) confirm(datestamp_list); for(dp = diskq.head; dp != NULL; dp = dp->next) { if(dp->todo) { char *qname; qname = quote_string(dp->name); log_add(L_DISK, "%s %s", dp->host->hostname, qname); amfree(qname); } } if(!foreground) { /* write it before redirecting stdout */ puts(_("Running in background, you can log off now.")); puts(_("You'll get mail when amflush is finished.")); } if(redirect) redirect_stderr(); if(!foreground) detach(); add_amanda_log_handler(amanda_log_stderr); add_amanda_log_handler(amanda_log_trace_log); today = time(NULL); tm = localtime(&today); if (tm) { strftime(date_string, 100, "%a %b %e %H:%M:%S %Z %Y", tm); strftime(date_string_standard, 100, "%Y-%m-%d %H:%M:%S %Z", tm); } else { error(_("BAD DATE")); /* should never happen */ } g_fprintf(stderr, _("amflush: start at %s\n"), date_string); g_fprintf(stderr, _("amflush: datestamp %s\n"), amflush_timestamp); g_fprintf(stderr, _("amflush: starttime %s\n"), amflush_timestamp); g_fprintf(stderr, _("amflush: starttime-locale-independent %s\n"), date_string_standard); log_add(L_START, _("date %s"), amflush_timestamp); /* START DRIVER */ if(pipe(driver_pipe) == -1) { error(_("error [opening pipe to driver: %s]"), strerror(errno)); /*NOTREACHED*/ } if((driver_pid = fork()) == 0) { /* * This is the child process. */ dup2(driver_pipe[0], 0); close(driver_pipe[1]); config_options = get_config_options(3); config_options[0] = "driver"; config_options[1] = get_config_name(); config_options[2] = "nodump"; safe_fd(-1, 0); execve(driver_program, config_options, safe_env()); error(_("cannot exec %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } else if(driver_pid == -1) { error(_("cannot fork for %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } driver_stream = fdopen(driver_pipe[1], "w"); if (!driver_stream) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } g_fprintf(driver_stream, "DATE %s\n", amflush_timestamp); for(holding_file=holding_list; holding_file != NULL; holding_file = holding_file->next) { dumpfile_t file; holding_file_get_dumpfile((char *)holding_file->data, &file); if (holding_file_size((char *)holding_file->data, 1) <= 0) { g_debug("%s is empty - ignoring", (char *)holding_file->data); log_add(L_INFO, "%s: removing file with no data.", (char *)holding_file->data); holding_file_unlink((char *)holding_file->data); dumpfile_free_data(&file); continue; } /* search_holding_disk should have already ensured that every * holding dumpfile has an entry in the dynamic disklist */ dp = lookup_disk(file.name, file.disk); assert(dp != NULL); /* but match_disklist may have indicated we should not flush it */ if (dp->todo == 0) continue; qdisk = quote_string(file.disk); qhname = quote_string((char *)holding_file->data); g_fprintf(stderr, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); g_debug("flushing '%s'", (char *)holding_file->data); g_fprintf(driver_stream, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); amfree(qdisk); amfree(qhname); dumpfile_free_data(&file); } g_fprintf(stderr, "ENDFLUSH\n"); fflush(stderr); g_fprintf(driver_stream, "ENDFLUSH\n"); fflush(driver_stream); fclose(driver_stream); /* WAIT DRIVER */ while(1) { if((pid = wait(&exitcode)) == -1) { if(errno == EINTR) { continue; } else { error(_("wait for %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } } else if (pid == driver_pid) { break; } } slist_free_full(datestamp_list, g_free); datestamp_list = NULL; slist_free_full(holding_list, g_free); holding_list = NULL; if(redirect) { /* rename errfile */ char *errfile, *errfilex, *nerrfilex, number[100]; int tapecycle; int maxdays, days; struct stat stat_buf; errfile = g_strjoin(NULL, conf_logdir, "/amflush", NULL); errfilex = NULL; nerrfilex = NULL; tapecycle = getconf_int(CNF_TAPECYCLE); maxdays = tapecycle + 2; days = 1; /* First, find out the last existing errfile, */ /* to avoid ``infinite'' loops if tapecycle is infinite */ g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); while ( days < maxdays && stat(errfilex,&stat_buf)==0) { days++; g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); } g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); nerrfilex = NULL; while (days > 1) { amfree(nerrfilex); nerrfilex = errfilex; days--; g_snprintf(number,100,"%d",days); errfilex = g_strjoin(NULL, errfile, ".", number, NULL); if (rename(errfilex, nerrfilex) != 0) { error(_("cannot rename \"%s\" to \"%s\": %s"), errfilex, nerrfilex, strerror(errno)); /*NOTREACHED*/ } } errfilex = newvstralloc(errfilex, errfile, ".1", NULL); if (rename(errfile,errfilex) != 0) { error(_("cannot rename \"%s\" to \"%s\": %s"), errfilex, nerrfilex, strerror(errno)); /*NOTREACHED*/ } amfree(errfile); amfree(errfilex); amfree(nerrfilex); } /* * Have amreport generate report and send mail. Note that we do * not bother checking the exit status. If it does not work, it * can be rerun. */ if((reporter_pid = fork()) == 0) { /* * This is the child process. */ config_options = get_config_options(3); config_options[0] = "amreport"; config_options[1] = get_config_name(); config_options[2] = "--from-amdump"; safe_fd(-1, 0); execve(reporter_program, config_options, safe_env()); error(_("cannot exec %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } else if(reporter_pid == -1) { error(_("cannot fork for %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } while(1) { if((pid = wait(&exitcode)) == -1) { if(errno == EINTR) { continue; } else { error(_("wait for %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } } else if (pid == reporter_pid) { break; } } log_add(L_INFO, "pid-done %ld", (long)getpid()); /* * Call amlogroll to rename the log file to its datestamped version. * Since we exec at this point, our exit code will be that of amlogroll. */ config_options = get_config_options(2); config_options[0] = "amlogroll"; config_options[1] = get_config_name(); safe_fd(-1, 0); execve(logroll_program, config_options, safe_env()); error(_("cannot exec %s: %s"), logroll_program, strerror(errno)); /*NOTREACHED*/ return 0; /* keep the compiler happy */ }
int main( int argc, char ** argv) { disklist_t diskl; int no_keep; /* files per system to keep */ char **output_find_log; DIR *dir; struct dirent *adir; char **name; int useful; char *olddir; char *oldfile = NULL, *newfile = NULL; time_t today, date_keep; char *logname = NULL; struct stat stat_log; struct stat stat_old; char *conf_diskfile; char *conf_tapelist; char *conf_logdir; int dumpcycle; config_overwrites_t *cfg_ovr = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amtrmlog"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); cfg_ovr = extract_commandline_config_overwrites(&argc, &argv); if (argc > 1 && strcmp(argv[1], "-t") == 0) { amtrmidx_debug = 1; argc--; argv++; } if (argc < 2) { g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]); return 1; } dbopen(DBG_SUBDIR_SERVER); dbprintf(_("%s: version %s\n"), argv[0], version()); config_init(CONFIG_INIT_EXPLICIT_NAME, argv[1]); apply_config_overwrites(cfg_ovr); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskl); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if (read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); today = time((time_t *)NULL); dumpcycle = getconf_int(CNF_DUMPCYCLE); if(dumpcycle > 5000) dumpcycle = 5000; date_keep = today - (dumpcycle * 86400); output_find_log = find_log(); /* determine how many log to keep */ no_keep = getconf_int(CNF_TAPECYCLE) * 2; dbprintf(plural(_("Keeping %d log file\n"), _("Keeping %d log files\n"), no_keep), no_keep); conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); olddir = vstralloc(conf_logdir, "/oldlog", NULL); if (mkpdir(olddir, 0700, (uid_t)-1, (gid_t)-1) != 0) { error(_("could not create parents of %s: %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (mkdir(olddir, 0700) != 0 && errno != EEXIST) { error(_("could not create %s: %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (stat(olddir,&stat_old) == -1) { error(_("can't stat oldlog directory \"%s\": %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (!S_ISDIR(stat_old.st_mode)) { error(_("Oldlog directory \"%s\" is not a directory"), olddir); /*NOTREACHED*/ } if ((dir = opendir(conf_logdir)) == NULL) { error(_("could not open log directory \"%s\": %s"), conf_logdir,strerror(errno)); /*NOTREACHED*/ } while ((adir=readdir(dir)) != NULL) { if(strncmp(adir->d_name,"log.",4)==0) { useful=0; for (name=output_find_log;*name !=NULL; name++) { if((strlen(adir->d_name) >= 13 && strlen(*name) >= 13 && adir->d_name[12] == '.' && (*name)[12] == '.' && strncmp(adir->d_name,*name,12)==0) || strncmp(adir->d_name,*name,18)==0) { useful=1; break; } } logname=newvstralloc(logname, conf_logdir, "/" ,adir->d_name, NULL); if(stat(logname,&stat_log)==0) { if((time_t)stat_log.st_mtime > date_keep) { useful = 1; } } if(useful == 0) { oldfile = newvstralloc(oldfile, conf_logdir, "/", adir->d_name, NULL); newfile = newvstralloc(newfile, olddir, "/", adir->d_name, NULL); if (rename(oldfile,newfile) != 0) { error(_("could not rename \"%s\" to \"%s\": %s"), oldfile, newfile, strerror(errno)); /*NOTREACHED*/ } } } } closedir(dir); for (name = output_find_log; *name != NULL; name++) { amfree(*name); } amfree(output_find_log); amfree(logname); amfree(oldfile); amfree(newfile); amfree(olddir); amfree(conf_logdir); clear_tapelist(); free_disklist(&diskl); dbclose(); return 0; }
int main( int argc, char ** argv) { config_overrides_t *cfg_ovr; char *hostname; char *auth; char *service; char *config = NULL; int opt; extern int optind; extern char *optarg; FILE *input_file; int use_connect = 0; int got_input_file = 0; int i; unsigned char gfd[32768]; glib_init(); /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); // safe_fd(-1, 0); safe_cd(); set_pname("amservice"); /* drop root privileges */ if (!set_root_privs(0)) { error(_("amservice must be run setuid root")); } /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); add_amanda_log_handler(amanda_log_stderr); our_features = am_init_feature_set(); our_feature_string = am_feature_to_string(our_features); /* process arguments */ for (i=0; i<argc; i++) { g_debug("argv[%d] = %s", i, argv[i]); } for (i = 0;i < 32768; i++) { gfd[i] = 0; } cfg_ovr = new_config_overrides(argc/2); input_file = stdin; while((opt = getopt_long(argc, argv, "o:f:s", long_options, NULL)) != EOF) { switch(opt) { case 1: printf("amservice-%s\n", VERSION); return(0); break; case 2: g_free(our_feature_string); g_free(our_features); our_feature_string = g_strdup(optarg); our_features = am_string_to_feature(our_feature_string); break; case 3: { gchar *copy_optarg = g_strdup(optarg); gchar *coma = strchr(copy_optarg, ','); gchar *stream_in; if (nb_lstream == DATA_FD_COUNT) { g_critical("Too many --stream, maximum is %d", DATA_FD_COUNT); exit(1); } else if (coma) { *coma++ = '\0'; stream_in = coma; coma = strchr(coma, ','); if (coma) { *coma++ = '\0'; lstreams[nb_lstream].name = g_strdup(copy_optarg); lstreams[nb_lstream].fd_in = atoi(stream_in); lstreams[nb_lstream].fd_out = atoi(coma); gfd[lstreams[nb_lstream].fd_in] = 1; gfd[lstreams[nb_lstream].fd_out] = 1; nb_lstream++; } } if (!coma) { g_critical("Invalid --stream option (%s)", optarg); exit(1); } g_free(copy_optarg); break; } case 4: g_free(config); config = g_strdup(optarg); break; case 'o': add_config_override_opt(cfg_ovr, optarg); break; case 'f': if (got_input_file == 1) { g_critical("Invalid two -f argument"); exit(1); } got_input_file = 1; if (*optarg == '/') { input_file = fopen(optarg, "r"); } else { char *name = g_strjoin(NULL, get_original_cwd(), "/", optarg, NULL); input_file = fopen(name, "r"); amfree(name); } if (!input_file) { g_critical("Cannot open input file '%s': %s", optarg, strerror(errno)); exit(1); } break; case 's': use_connect = 1; break; } } if (use_connect && !got_input_file) { g_critical("The -s option require -f"); exit(1); } /* close all unused fd */ for (i = 3;i < 32768; i++) { if (gfd[i] == 0 && i != dbfd() && (!got_input_file || i != fileno(input_file))) { close(i); } } argc -= optind, argv += optind; if(argc < 3) usage(); /* set a default config */ set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_CLIENT|CONFIG_INIT_GLOBAL, NULL); if (config) { config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY, config); } dbrename(get_config_name(), DBG_SUBDIR_SERVER); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT); hostname = argv[0]; auth = argv[1]; if (g_str_equal(auth,"NULL")) { auth = getconf_str(CNF_AUTH); } service = argv[2]; /* start client side checks */ copy_stream = use_connect && got_input_file; client_protocol(hostname, auth, service, config, input_file); amfree(our_feature_string); am_release_feature_set(our_features); our_features = NULL; if (got_input_file) fclose(input_file); dbclose(); return(remote_errors != 0); }
/* return == NULL: correct * != NULL: error message * * The ndmp-proxy is assumed to take a configuration name and a port number * on its command line, and to immediately attempt to bind to that port. If * the bind operation succeeds, it should print "OK\n" to stdout and close the * file descriptor. If the operation fails because the address is already * in use (and thus, most likely, there's another proxy running already), then * it should print "INUSE\n", close the file descriptor, and exit. For any other * failure, it should print a suitable error message and exit. */ static char * start_ndmp_proxy(void) { char *ndmp_proxy; GPtrArray *proxy_argv; char buffer[32769]; int proxy_in, proxy_out, proxy_err; int rc; pid_t pid; char *errmsg; amwait_t wait_status; proxy_argv = g_ptr_array_new(); g_ptr_array_add(proxy_argv, g_strdup("ndmp-proxy")); g_ptr_array_add(proxy_argv, g_strdup(get_config_name())); g_ptr_array_add(proxy_argv, g_strdup_printf("%d", getconf_int(CNF_NDMP_PROXY_PORT))); g_ptr_array_add(proxy_argv, NULL); ndmp_proxy = g_strdup_printf("%s/ndmp-proxy", amlibexecdir); proxy_in = open("/dev/null", O_RDONLY); proxy_err = debug_fd(); pid = pipespawnv(ndmp_proxy, STDOUT_PIPE, 0, &proxy_in, &proxy_out, &proxy_err, (char **)proxy_argv->pdata); close(proxy_in); g_ptr_array_free_full(proxy_argv); g_debug("started ndmp-proxy with pid %d", pid); /* wait for the proxy to say "OK" */ rc = full_read(proxy_out, buffer, sizeof(buffer)-1); if (rc == -1) { errmsg = g_strdup_printf("Error reading from ndmp-proxy: %s", strerror(errno)); /* clean up the PID if possible */ waitpid(pid, NULL, WNOHANG); return errmsg; } else if (rc == 0) { if (waitpid(pid, &wait_status, WNOHANG)) { errmsg = str_exit_status("ndmp-proxy", wait_status); } else { errmsg = g_strdup_printf("unexpected EOF from ndmp-proxy"); } return errmsg; } aclose(proxy_out); /* process the output */ buffer[rc] = '\0'; if (0 == strcmp(buffer, "OK\n")) { return NULL; } else if (0 == strcmp(buffer, "INUSE\n")) { g_warning("overlapping attempts to start ndmp-proxy; ignoring this attempt"); /* clean up the pid */ waitpid(pid, NULL, 0); return NULL; } else { errmsg = g_strdup_printf("ndmp-proxy failed: %s", buffer); return errmsg; } }
void edit_value(int curr) { struct passwd *pw = NULL; char ctdluidname[256]; char buf[SIZ]; char *default_value = NULL; int ctdluid = 0; int portnum = 0; int auth = 0; int lportnum = 0; if (setup_type == UI_SILENT) { default_value = getenv(EnvNames[curr]); } if (default_value == NULL) { default_value = ""; } switch (curr) { case eSysAdminName: getconf_str(admin_name, "c_sysadm"); set_str_val(curr, admin_name, default_value); setconf_str("c_sysadm", admin_name); break; case eSysAdminPW: set_str_val(curr, admin_pass, default_value); break; case eUID: if (setup_type == UI_SILENT) { if (default_value) { ctdluid = atoi(default_value); } } else { #ifdef __CYGWIN__ ctdluid = 0; /* work-around for Windows */ #else pw = getpwuid(ctdluid); if (pw == NULL) { set_int_val(curr, &ctdluid, default_value); } else { strcpy(ctdluidname, pw->pw_name); set_str_val(curr, ctdluidname, default_value); pw = getpwnam(ctdluidname); if (pw != NULL) { ctdluid = pw->pw_uid; } else if (atoi(ctdluidname) > 0) { ctdluid = atoi(ctdluidname); } } #endif } setconf_int("c_ctdluid", ctdluid); break; case eIP_ADDR: getconf_str(buf, "c_ip_addr"); set_str_val(curr, buf, default_value); setconf_str("c_ip_addr", buf); break; case eCTDL_Port: portnum = getconf_int("c_port_number"); set_int_val(curr, &portnum, default_value); setconf_int("c_port_number", portnum); break; case eAuthType: auth = getconf_int("c_auth_mode"); if (setup_type == UI_SILENT) { if ( (default_value) && (!strcasecmp(default_value, "yes")) ) auth = AUTHMODE_HOST; if ( (default_value) && (!strcasecmp(default_value, "host")) ) auth = AUTHMODE_HOST; if ( (default_value) && (!strcasecmp(default_value, "ldap")) ) auth = AUTHMODE_LDAP; if ( (default_value) && (!strcasecmp(default_value, "ldap_ad")) ) auth = AUTHMODE_LDAP_AD; if ( (default_value) && (!strcasecmp(default_value, "active directory")) ) auth = AUTHMODE_LDAP_AD; } else { set_int_val(curr, &auth, default_value); } setconf_int("c_auth_mode", auth); break; case eLDAP_Host: getconf_str(buf, "c_ldap_host"); if (IsEmptyStr(buf)) { strcpy(buf, "localhost"); } set_str_val(curr, buf, default_value); setconf_str("c_ldap_host", buf); break; case eLDAP_Port: lportnum = getconf_int("c_ldap_port"); if (lportnum == 0) { lportnum = 389; } set_int_val(curr, &lportnum, default_value); setconf_int("c_ldap_port", lportnum); break; case eLDAP_Base_DN: getconf_str(buf, "c_ldap_base_dn"); set_str_val(curr, buf, default_value); setconf_str("c_ldap_base_dn", buf); break; case eLDAP_Bind_DN: getconf_str(buf, "c_ldap_bind_dn"); set_str_val(curr, buf, default_value); setconf_str("c_ldap_bind_dn", buf); break; case eLDAP_Bind_PW: getconf_str(buf, "c_ldap_bind_pw"); set_str_val(curr, buf, default_value); setconf_str("c_ldap_bind_pw", buf); break; } }
int main(int argc, char *argv[]) { int a, i; int curr; char buf[1024]; char aaa[128]; int relh = 0; int home = 0; int nRetries = 0; char relhome[PATH_MAX]=""; char ctdldir[PATH_MAX]=CTDLDIR; struct passwd *pw; gid_t gid; char *activity = NULL; /* Keep a mild groove on */ program_title = _("Citadel setup program"); /* set an invalid setup type */ setup_type = (-1); /* parse command line args */ for (a = 0; a < argc; ++a) { if (!strncmp(argv[a], "-u", 2)) { strcpy(aaa, argv[a]); strcpy(aaa, &aaa[2]); setup_type = atoi(aaa); } else if (!strcmp(argv[a], "-q")) { setup_type = UI_SILENT; } else if (!strncmp(argv[a], "-h", 2)) { relh=argv[a][2]!='/'; if (!relh) { safestrncpy(ctdl_home_directory, &argv[a][2], sizeof ctdl_home_directory); } else { safestrncpy(relhome, &argv[a][2], sizeof relhome); } home = 1; } } calc_dirs_n_files(relh, home, relhome, ctdldir, 0); SetTitles(); /* If a setup type was not specified, try to determine automatically * the best one to use out of all available types. */ if (setup_type < 0) { setup_type = discover_ui(); } enable_home = ( relh | home ); if (chdir(ctdl_run_dir) != 0) { display_error("%s: [%s]\n", _("The directory you specified does not exist"), ctdl_run_dir); exit(errno); } /* * Connect to the running Citadel server. */ while ((serv_sock < 0) && (nRetries < 10)) { serv_sock = uds_connectsock(file_citadel_admin_socket); nRetries ++; if (serv_sock < 0) sleep(1); } if (serv_sock < 0) { display_error( "%s: %s %s\n", _("Setup could not connect to a running Citadel server."), strerror(errno), file_citadel_admin_socket ); exit(1); } /* * read the server greeting */ serv_gets(buf); if (buf[0] != '2') { display_error("%s\n", buf); exit(2); } /* * Are we connected to the correct Citadel server? */ serv_puts("INFO"); serv_gets(buf); if (buf[0] != '1') { display_error("%s\n", buf); exit(3); } a = 0; while (serv_gets(buf), strcmp(buf, "000")) { if (a == 5) { if (atoi(buf) != REV_LEVEL) { display_error("%s\n", _("Your setup program and Citadel server are from different versions.") ); exit(4); } } ++a; } /* * Now begin. */ if (setup_type == UI_TEXT) { printf("\n\n\n *** %s ***\n\n", program_title); } if (setup_type == UI_DIALOG) { system("clear 2>/dev/null"); } /* Go through a series of dialogs prompting for config info */ for (curr = 1; curr < eMaxQuestions; ++curr) { edit_value(curr); if ( (curr == eAuthType) && (getconf_int("c_auth_mode") != AUTHMODE_LDAP) && (getconf_int("c_auth_mode") != AUTHMODE_LDAP_AD) ) { curr += 5; /* skip LDAP questions if we're not authenticating against LDAP */ } if (curr == eSysAdminName) { if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) { /* for native auth mode, fetch the admin's existing pw */ snprintf(buf, sizeof buf, "AGUP %s", admin_name); serv_puts(buf); serv_gets(buf); if (buf[0] == '2') { extract_token(admin_pass, &buf[4], 1, '|', sizeof admin_pass); } } else { ++curr; /* skip the password question for non-native auth modes */ } } } if ((pw = getpwuid( getconf_int("c_ctdluid") )) == NULL) { gid = getgid(); } else { gid = pw->pw_gid; } if (create_run_directories(getconf_int("c_ctdluid"), gid) != 0) { display_error("%s\n", _("failed to create directories")); } activity = _("Reconfiguring Citadel server"); progress(activity, 0, 5); sleep(1); /* Let the message appear briefly */ /* * Create the administrator account. It's ok if the command fails if this user already exists. */ progress(activity, 1, 5); snprintf(buf, sizeof buf, "CREU %s|%s", admin_name, admin_pass); serv_puts(buf); progress(activity, 2, 5); serv_gets(buf); progress(activity, 3, 5); /* * Assign the desired password and access level to the administrator account. */ snprintf(buf, sizeof buf, "AGUP %s", admin_name); serv_puts(buf); progress(activity, 4, 5); serv_gets(buf); if (buf[0] == '2') { int admin_flags = extract_int(&buf[4], 2); int admin_times_called = extract_int(&buf[4], 3); int admin_msgs_posted = extract_int(&buf[4], 4); snprintf(buf, sizeof buf, "ASUP %s|%s|%d|%d|%d|6", admin_name, admin_pass, admin_flags, admin_times_called, admin_msgs_posted ); serv_puts(buf); serv_gets(buf); } progress(activity, 5, 5); #ifndef __CYGWIN__ check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */ disable_other_mtas(); /* Offer to disable other MTAs */ fixnss(); /* Check for the 'db' nss and offer to disable it */ #endif /* * Restart citserver */ activity = _("Restarting Citadel server to apply changes"); progress(activity, 0, 41); serv_puts("TIME"); serv_gets(buf); long original_start_time = extract_long(&buf[4], 3); progress(activity, 1, 41); serv_puts("DOWN 1"); progress(activity, 2, 41); serv_gets(buf); if (buf[0] != '2') { display_error("%s\n", buf); exit(6); } close(serv_sock); serv_sock = (-1); for (i=3; i<=6; ++i) { /* wait for server to shut down */ progress(activity, i, 41); sleep(1); } for (i=7; ((i<=38) && (serv_sock < 0)) ; ++i) { /* wait for server to start up */ progress(activity, i, 41); serv_sock = uds_connectsock(file_citadel_admin_socket); sleep(1); } progress(activity, 39, 41); serv_gets(buf); progress(activity, 40, 41); serv_puts("TIME"); serv_gets(buf); long new_start_time = extract_long(&buf[4], 3); close(serv_sock); progress(activity, 41, 41); if ( (original_start_time == new_start_time) || (new_start_time <= 0) ) { display_error("%s\n", _("Setup failed to restart Citadel server. Please restart it manually.")); exit(7); } exit(0); return 0; }