static int do_synclogfile(const char *synclogfile) { strarray_t *folders = NULL; sync_log_reader_t *slr; int nskipped = 0; int i; int r; slr = sync_log_reader_create_with_filename(synclogfile); r = sync_log_reader_begin(slr); if (r) goto out; folders = read_sync_log_items(slr); sync_log_reader_end(slr); /* sort folders for locality of reference in file processing mode */ strarray_sort(folders, cmpstringp_raw); signals_poll(); /* have some due items in the queue, try to index them */ rx = search_begin_update(verbose); for (i = 0; i < folders->count; i++) { const char *mboxname = strarray_nth(folders, i); if (verbose > 1) syslog(LOG_INFO, "do_synclogfile: indexing %s", mboxname); r = index_one(mboxname, /*blocking*/1); if (r == IMAP_MAILBOX_NONEXISTENT) r = 0; if (r == IMAP_MAILBOX_LOCKED || r == IMAP_AGAIN) { nskipped++; if (nskipped > 10000) { syslog(LOG_ERR, "IOERROR: skipped too many times at %s", mboxname); break; } r = 0; /* try again at the end */ strarray_append(folders, mboxname); } if (r) { syslog(LOG_ERR, "IOERROR: failed to index %s: %s", mboxname, error_message(r)); break; } if (sleepmicroseconds) usleep(sleepmicroseconds); } search_end_update(rx); rx = NULL; out: strarray_free(folders); sync_log_reader_free(slr); return r; }
static void do_rolling(const char *channel) { strarray_t *folders = NULL; sync_log_reader_t *slr; int i; int r; slr = sync_log_reader_create_with_channel(channel); for (;;) { signals_poll(); if (shutdown_file(NULL, 0)) shut_down(EC_TEMPFAIL); r = sync_log_reader_begin(slr); if (r) { /* including IMAP_AGAIN */ usleep(100000); /* 1/10th second */ continue; } folders = read_sync_log_items(slr); if (folders->count) { /* have some due items in the queue, try to index them */ rx = search_begin_update(verbose); for (i = 0; i < folders->count; i++) { const char *mboxname = strarray_nth(folders, i); if (verbose > 1) syslog(LOG_INFO, "do_rolling: indexing %s", mboxname); r = index_one(mboxname, /*blocking*/0); if (r == IMAP_AGAIN || r == IMAP_MAILBOX_LOCKED) { /* XXX: alternative, just append to strarray_t *folders ... */ sync_log_channel(channel, "APPEND %s", mboxname); } if (sleepmicroseconds) usleep(sleepmicroseconds); } search_end_update(rx); rx = NULL; } strarray_free(folders); folders = NULL; } /* XXX - we don't really get here... */ strarray_free(folders); sync_log_reader_free(slr); }
/* * mboxlist_findall() callback function to examine a mailbox */ static int do_timestamp(char *name) { unsigned recno; int r = 0; char ext_name_buf[MAX_MAILBOX_PATH+1]; struct mailbox *mailbox = NULL; struct index_record record; char olddate[RFC822_DATETIME_MAX+1]; char newdate[RFC822_DATETIME_MAX+1]; signals_poll(); /* Convert internal name to external */ (*recon_namespace.mboxname_toexternal)(&recon_namespace, name, "cyrus", ext_name_buf); printf("Working on %s...\n", ext_name_buf); /* Open/lock header */ r = mailbox_open_iwl(name, &mailbox); if (r) return r; for (recno = 1; recno <= mailbox->i.num_records; recno++) { r = mailbox_read_index_record(mailbox, recno, &record); if (r) goto done; if (record.system_flags & FLAG_EXPUNGED) continue; /* 1 day is close enough */ if (abs(record.internaldate - record.gmtime) < 86400) continue; time_to_rfc822(record.internaldate, olddate, sizeof(olddate)); time_to_rfc822(record.gmtime, newdate, sizeof(newdate)); printf(" %u: %s => %s\n", record.uid, olddate, newdate); /* switch internaldate */ record.internaldate = record.gmtime; r = mailbox_rewrite_index_record(mailbox, &record); if (r) goto done; } done: mailbox_close(&mailbox); return r; }
int begin_handling(void) { struct sockaddr_storage sfrom; socklen_t sfromsiz = sizeof(sfrom); int r; char buf[MAXLOGNAME + MAXDOMNAME + MAX_MAILBOX_BUFFER]; char username[MAXLOGNAME + MAXDOMNAME + 1]; char mbox[MAX_MAILBOX_BUFFER]; char *q; int off; int maxuserlen = MAXLOGNAME; if (config_virtdomains) maxuserlen += MAXDOMNAME + 1; /* @ + DOM */ while(1) { /* For safety */ memset(buf, 0, sizeof(buf)); memset(username, 0, sizeof(username)); memset(mbox, 0, sizeof(mbox)); if (signals_poll() == SIGHUP) { /* caught a SIGHUP, return */ return 0; } r = recvfrom(soc, buf, 511, 0, (struct sockaddr *) &sfrom, &sfromsiz); if (r == -1) { return(errno); } for(off = 0; buf[off] != '|' && off < maxuserlen; off++); if(off > 0 && off < maxuserlen) { strncpy(username,buf,off); username[off] = '\0'; } else { continue; } /* Copy what is past the | to the mailbox name */ q = buf + off + 1; strlcpy(mbox, q, sizeof(mbox)); handle_request(username,mbox,sfrom,sfromsiz); } /* never reached */ }
/* * mboxlist_findall() callback function to examine a mailbox */ static int do_timestamp(const char *name) { int r = 0; char ext_name_buf[MAX_MAILBOX_PATH+1]; struct mailbox *mailbox = NULL; const struct index_record *record; char olddate[RFC822_DATETIME_MAX+1]; char newdate[RFC822_DATETIME_MAX+1]; signals_poll(); /* Convert internal name to external */ (*recon_namespace.mboxname_toexternal)(&recon_namespace, name, "cyrus", ext_name_buf); printf("Working on %s...\n", ext_name_buf); /* Open/lock header */ r = mailbox_open_iwl(name, &mailbox); if (r) return r; struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, ITER_SKIP_EXPUNGED); while ((record = mailbox_iter_step(iter))) { /* 1 day is close enough */ if (labs(record->internaldate - record->gmtime) < 86400) continue; struct index_record copyrecord = *record; time_to_rfc822(copyrecord.internaldate, olddate, sizeof(olddate)); time_to_rfc822(copyrecord.gmtime, newdate, sizeof(newdate)); printf(" %u: %s => %s\n", copyrecord.uid, olddate, newdate); /* switch internaldate */ copyrecord.internaldate = copyrecord.gmtime; r = mailbox_rewrite_index_record(mailbox, ©record); if (r) goto done; } done: mailbox_iter_done(&iter); mailbox_close(&mailbox); return r; }
static int wait_for_child(const char *argv0, pid_t pid) { int r = 0; if (pid) { for (;;) { int status; pid_t pr = waitpid(pid, &status, 0); if (pr < 0) { if (errno == EINTR) { signals_poll(); continue; } else if (errno == ECHILD || errno == ESRCH) { r = 0; break; /* someone else reaped the child */ } else { syslog(LOG_ERR, "waitpid() failed: %m"); r = IMAP_SYS_ERROR; break; } } if (WIFEXITED(status)) { r = 0; if (WEXITSTATUS(status)) { syslog(LOG_ERR, "Program %s (pid %d) exited with status %d", argv0, (int)pid, WEXITSTATUS(status)); r = IMAP_SYS_ERROR; } break; } if (WIFSIGNALED(status)) { syslog(LOG_ERR, "Program %s (pid %d) died with signal %d", argv0, (int)pid, WTERMSIG(status)); r = IMAP_SYS_ERROR; break; } } } return r; }
/* * Run a search daemon in such a way that the natural shutdown * mechanism for Cyrus (sending a SIGTERM to the master process) * will cleanly shut down the search daemon too. For Sphinx * this currently means running a loop in a forked process whose * job it is to live in the master process' process group and thus * receive the SIGTERM that master re-sends. */ static void do_run_daemon(void) { int r; /* We start the daemon before forking. This eliminates a * race condition during slot startup by ensuring that * Sphinx is fully running before the rolling squatter * tries to use it. */ r = search_start_daemon(verbose); if (r) exit(EC_TEMPFAIL); /* tell shut_down() to shut down the searchd too */ running_daemon = 1; become_daemon(); signals_set_shutdown(&shut_down); signals_add_handlers(0); for (;;) { signals_poll(); /* will call shut_down() after SIGTERM */ poll(NULL, 0, -1); /* sleeps until signalled */ } }
int main(int argc, char **argv) { int opt; pid_t pid; char *alt_config = NULL; time_t runattime = 0; int upgrade = 0; if ((geteuid()) == 0 && (become_cyrus(/*is_master*/0) != 0)) { fatal("must run as the Cyrus user", EC_USAGE); } while ((opt = getopt(argc, argv, "C:dt:U")) != EOF) { switch (opt) { case 'C': /* alt config file */ alt_config = optarg; break; case 'd': /* don't fork. debugging mode */ debugmode = 1; break; case 't': /* run a single scan at this time */ runattime = atoi(optarg); break; case 'U': upgrade = 1; break; default: fprintf(stderr, "invalid argument\n"); exit(EC_USAGE); break; } } cyrus_init(alt_config, "calalarmd", 0, 0); mboxlist_init(0); mboxlist_open(NULL); quotadb_init(0); quotadb_open(NULL); annotatemore_open(); caldav_init(); mboxevent_init(); if (upgrade) { caldav_alarm_upgrade(); shut_down(0); } if (runattime) { caldav_alarm_process(runattime); shut_down(0); } signals_set_shutdown(shut_down); signals_add_handlers(0); /* fork unless we were given the -d option or we're running as a daemon */ if (debugmode == 0 && !getenv("CYRUS_ISDAEMON")) { pid = fork(); if (pid == -1) { perror("fork"); exit(1); } if (pid != 0) { /* parent */ exit(0); } } /* child */ for (;;) { struct timeval start, end; double totaltime; int tosleep; signals_poll(); gettimeofday(&start, 0); caldav_alarm_process(0); gettimeofday(&end, 0); signals_poll(); totaltime = timesub(&start, &end); tosleep = 10 - (int) (totaltime + 0.5); /* round to nearest int */ if (tosleep > 0) sleep(tosleep); } /* NOTREACHED */ shut_down(1); }
/* Add all ZONEs and LINKs in the given directory to the hash table */ void do_zonedir(const char *dir, struct hash_table *tzentries, struct zoneinfo *info) { DIR *dirp; struct dirent *dirent; signals_poll(); if (verbose) printf("Rebuilding %s\n", dir); dirp = opendir(dir); if (!dirp) { fprintf(stderr, "can't open zoneinfo directory %s\n", dir); } while ((dirent = readdir(dirp))) { char path[2048], *tzid; int plen; struct stat sbuf; struct zoneinfo *zi; if (*dirent->d_name == '.') continue; plen = snprintf(path, sizeof(path), "%s/%s", dir, dirent->d_name); lstat(path, &sbuf); if (S_ISDIR(sbuf.st_mode)) { /* Path is a directory (region) */ do_zonedir(path, tzentries, info); } else if (S_ISLNK(sbuf.st_mode)) { /* Path is a symlink (alias) */ char link[1024], *alias; ssize_t llen; /* Isolate tzid in path */ if ((llen = readlink(path, link, sizeof(link))) < 0) continue; link[llen-4] = '\0'; /* Trim ".ics" */ for (tzid = link; !strncmp(tzid, "../", 3); tzid += 3); /* Isolate alias in path */ path[plen-4] = '\0'; /* Trim ".ics" */ alias = path + strlen(config_dir) + strlen("zoneinfo") + 2; if (verbose) printf("\tLINK: %s -> %s\n", alias, tzid); /* Create hash entry for alias */ if (!(zi = hash_lookup(alias, tzentries))) { zi = xzmalloc(sizeof(struct zoneinfo)); hash_insert(alias, zi, tzentries); } zi->type = ZI_LINK; appendstrlist(&zi->data, tzid); /* Create/update hash entry for tzid */ if (!(zi = hash_lookup(tzid, tzentries))) { zi = xzmalloc(sizeof(struct zoneinfo)); hash_insert(tzid, zi, tzentries); } zi->type = ZI_ZONE; appendstrlist(&zi->data, alias); } else if (S_ISREG(sbuf.st_mode)) { /* Path is a regular file (zone) */ int fd; const char *base = NULL; size_t len = 0; icalcomponent *ical, *comp; icalproperty *prop; /* Parse the iCalendar file for important properties */ if ((fd = open(path, O_RDONLY)) == -1) continue; map_refresh(fd, 1, &base, &len, MAP_UNKNOWN_LEN, path, NULL); close(fd); ical = icalparser_parse_string(base); map_free(&base, &len); if (!ical) continue; /* skip non-iCalendar files */ comp = icalcomponent_get_first_component(ical, ICAL_VTIMEZONE_COMPONENT); prop = icalcomponent_get_first_property(comp, ICAL_TZID_PROPERTY); tzid = (char *) icalproperty_get_value_as_string(prop); if (verbose) printf("\tZONE: %s\n", tzid); /* Create/update hash entry for tzid */ if (!(zi = hash_lookup(tzid, tzentries))) { zi = xzmalloc(sizeof(struct zoneinfo)); hash_insert(tzid, zi, tzentries); } zi->type = ZI_ZONE; prop = icalcomponent_get_first_property(comp, ICAL_LASTMODIFIED_PROPERTY); zi->dtstamp = icaltime_as_timet(icalproperty_get_lastmodified(prop)); icalcomponent_free(ical); /* Check overall lastmod */ if (zi->dtstamp > info->dtstamp) info->dtstamp = zi->dtstamp; } else { fprintf(stderr, "unknown path type %s\n", path); } } closedir(dirp); }
static int do_notify(void) { struct sockaddr_un sun_data; socklen_t sunlen = sizeof(sun_data); char buf[NOTIFY_MAXSIZE+1], *cp, *tail; int r, i; char *method, *class, *priority, *user, *mailbox, *message; strarray_t options = STRARRAY_INITIALIZER; long nopt; char *reply; char *fname; notifymethod_t *nmethod; while (1) { method = class = priority = user = mailbox = message = reply = NULL; nopt = 0; if (signals_poll() == SIGHUP) { /* caught a SIGHUP, return */ return 0; } r = recvfrom(soc, buf, NOTIFY_MAXSIZE, 0, (struct sockaddr *) &sun_data, &sunlen); if (r == -1) { return (errno); } buf[r] = '\0'; tail = buf + r - 1; /* * parse request of the form: * * method NUL class NUL priority NUL user NUL mailbox NUL * nopt NUL N(option NUL) message NUL */ method = (cp = buf); if (cp) class = (cp = fetch_arg(cp, tail)); if (cp) priority = (cp = fetch_arg(cp, tail)); if (cp) user = (cp = fetch_arg(cp, tail)); if (cp) mailbox = (cp = fetch_arg(cp, tail)); if (cp) cp = fetch_arg(cp, tail); /* skip to nopt */ if (cp) nopt = strtol(cp, NULL, 10); if (nopt < 0 || errno == ERANGE) cp = NULL; for (i = 0; cp && i < nopt; i++) strarray_appendm(&options, cp = fetch_arg(cp, tail)); if (cp) message = (cp = fetch_arg(cp, tail)); if (cp) fname = (cp = fetch_arg(cp, tail)); if (!message) { syslog(LOG_ERR, "malformed notify request"); strarray_fini(&options); return 0; } if (!*method) nmethod = default_method; else { nmethod = methods; while (nmethod->name) { if (!strcasecmp(nmethod->name, method)) break; nmethod++; } } syslog(LOG_DEBUG, "do_notify using method '%s'", nmethod->name ? nmethod->name: "unknown"); if (nmethod->name) { reply = nmethod->notify(class, priority, user, mailbox, nopt, options.data, message, fname); } #if 0 /* we don't care about responses right now */ else {
static int do_daemon_work(const char *channel, const char *sync_shutdown_file, unsigned long timeout, unsigned long min_delta, int *restartp) { int r = 0; time_t session_start; time_t single_start; int delta; struct stat sbuf; sync_log_reader_t *slr; *restartp = RESTART_NONE; slr = sync_log_reader_create_with_channel(channel); session_start = time(NULL); while (1) { single_start = time(NULL); signals_poll(); /* Check for shutdown file */ if (sync_shutdown_file && !stat(sync_shutdown_file, &sbuf)) { unlink(sync_shutdown_file); break; } /* See if its time to RESTART */ if ((timeout > 0) && ((single_start - session_start) > (time_t) timeout)) { *restartp = RESTART_NORMAL; break; } r = sync_log_reader_begin(slr); if (r) { /* including specifically r == IMAP_AGAIN */ if (min_delta > 0) { sleep(min_delta); } else { usleep(100000); /* 1/10th second */ } continue; } /* Process the work log */ if ((r=do_sync(slr))) { syslog(LOG_ERR, "Processing sync log file %s failed: %s", sync_log_reader_get_file_name(slr), error_message(r)); break; } r = sync_log_reader_end(slr); if (r) break; delta = time(NULL) - single_start; if (((unsigned) delta < min_delta) && ((min_delta-delta) > 0)) sleep(min_delta-delta); } sync_log_reader_free(slr); if (*restartp == RESTART_NORMAL) { r = do_restart(); if (r) { syslog(LOG_ERR, "sync_client RESTART failed: %s", error_message(r)); } else { syslog(LOG_INFO, "sync_client RESTART succeeded"); } r = 0; } return(r); }
/* * mboxlist_findall() callback function to reconstruct a mailbox */ static int do_reconstruct(struct findall_data *data, void *rock) { if (!data) return 0; strarray_t *discovered = (strarray_t *)rock; int r; static char lastname[MAX_MAILBOX_NAME] = ""; char *other; struct mailbox *mailbox = NULL; char outpath[MAX_MAILBOX_PATH]; const char *name = mbname_intname(data->mbname); signals_poll(); /* don't repeat */ if (!strcmp(name, lastname)) return 0; strncpy(lastname, name, sizeof(lastname)); lastname[sizeof(lastname)-1] = '\0'; r = mailbox_reconstruct(lastname, reconstruct_flags); if (r) { com_err(lastname, r, "%s", (r == IMAP_IOERROR) ? error_message(errno) : "Failed to reconstruct mailbox"); return 0; } r = mailbox_open_iwl(lastname, &mailbox); if (r) { com_err(lastname, r, "Failed to open after reconstruct"); return 0; } other = hash_lookup(mailbox->uniqueid, &unqid_table); if (other) { syslog (LOG_ERR, "uniqueid clash with %s for %s - changing %s", other, mailbox->uniqueid, mailbox->name); /* uniqueid change required! */ mailbox_make_uniqueid(mailbox); } hash_insert(mailbox->uniqueid, xstrdup(mailbox->name), &unqid_table); /* Convert internal name to external */ char *extname = mboxname_to_external(lastname, &recon_namespace, NULL); if (!(reconstruct_flags & RECONSTRUCT_QUIET)) printf("%s\n", extname); strncpy(outpath, mailbox_meta_fname(mailbox, META_HEADER), MAX_MAILBOX_NAME); if (setversion) { /* need to re-set the version! */ int r = mailbox_setversion(mailbox, setversion); if (r) { printf("FAILED TO REPACK %s with new version %s\n", extname, error_message(r)); } else { printf("Repacked %s to version %d\n", extname, setversion); } } mailbox_close(&mailbox); free(extname); if (discovered) { char fnamebuf[MAX_MAILBOX_PATH]; char *ptr; DIR *dirp; struct dirent *dirent; struct stat sbuf; ptr = strstr(outpath, "cyrus.header"); if (!ptr) return 0; *ptr = 0; r = chdir(outpath); if (r) return 0; /* we recurse down this directory to see if there's any mailboxes under this not in the mailboxes database */ dirp = opendir("."); if (!dirp) return 0; while ((dirent = readdir(dirp)) != NULL) { /* mailbox directories never have a dot in them */ if (strchr(dirent->d_name, '.')) continue; if (stat(dirent->d_name, &sbuf) < 0) continue; if (!S_ISDIR(sbuf.st_mode)) continue; /* ok, we found a directory that doesn't have a dot in it; is there a cyrus.header file? */ snprintf(fnamebuf, MAX_MAILBOX_PATH, "%s%s", dirent->d_name, FNAME_HEADER); if (stat(fnamebuf, &sbuf) < 0) continue; /* ok, we have a real mailbox directory */ char buf[MAX_MAILBOX_NAME]; snprintf(buf, MAX_MAILBOX_NAME, "%s.%s", name, dirent->d_name); /* does fnamebuf exist as a mailbox in mboxlist? */ do { r = mboxlist_lookup(buf, NULL, NULL); } while (r == IMAP_AGAIN); if (!r) continue; /* mailbox exists; it'll be reconstructed with a -r */ if (r != IMAP_MAILBOX_NONEXISTENT) break; /* erg? */ else r = 0; /* reset error condition */ printf("discovered %s\n", buf); strarray_append(discovered, buf); } closedir(dirp); } return 0; }