+
+/* Order of preference: readdir64(), readdir(). */
+#if HAVE_DECL_READDIR64
+# define USE_DIRENT64
+# define USE_READDIR64
+#elif HAVE_DECL_READDIR
+# define USE_READDIR
+#else
+# error No readdir() or readdir64() available!
+#endif
+
+char * portable_readdir(DIR* handle) {
+
+#ifdef USE_DIRENT64
+ struct dirent64 *entry_p;
+#else
+ struct dirent *entry_p;
+#endif
+
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ g_static_mutex_lock(&mutex);
+
+#ifdef USE_READDIR
+ entry_p = readdir(handle);
+#endif
+#ifdef USE_READDIR64
+ entry_p = readdir64(handle);
+#endif
+
+ g_static_mutex_unlock(&mutex);
+
+ if (entry_p == NULL)
+ return NULL;
+
+ /* FIXME: According to glibc documentation, d_name may not be
+ null-terminated in some cases on some very old platforms. Not
+ sure what to do about that case. */
+ return strdup(entry_p->d_name);
+}
+
+int search_directory(DIR * handle, const char * regex,
+ SearchDirectoryFunctor functor, gpointer user_data) {
+ int rval = 0;
+ regex_t compiled_regex;
+ gboolean done = FALSE;
+
+ if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
+ regfree(&compiled_regex);
+ return -1;
+ }
+
+ rewinddir(handle);
+
+ while (!done) {
+ char * read_name;
+ int result;
+ read_name = portable_readdir(handle);
+ if (read_name == NULL) {
+ regfree(&compiled_regex);
+ return rval;
+ }
+ result = regexec(&compiled_regex, read_name, 0, NULL, 0);
+ if (result == 0) {
+ rval ++;
+ done = !functor(read_name, user_data);
+ }
+ amfree(read_name);
+ }
+ regfree(&compiled_regex);
+ return rval;
+}
+
+char* find_regex_substring(const char* base_string, const regmatch_t match) {
+ char * rval;
+ int size;
+
+ size = match.rm_eo - match.rm_so;
+ rval = malloc(size+1);
+ memcpy(rval, base_string + match.rm_so, size);
+ rval[size] = '\0';
+
+ return rval;
+}
+
+int compare_possibly_null_strings(const char * a, const char * b) {
+ if (a == b) {
+ /* NULL or otherwise, they're the same. */
+ return 0;
+ } else if (a == NULL) {
+ /* b != NULL */
+ return -1;
+ } else if (b == NULL) {
+ /* a != NULL */
+ return 1;
+ } else {
+ /* a != NULL != b */
+ return strcmp(a, b);
+ }
+}
+
+gboolean amanda_thread_init(void) {
+ gboolean success = FALSE;
+#ifdef HAVE_LIBCURL
+ static gboolean did_curl_init = FALSE;
+ if (!did_curl_init) {
+# ifdef G_THREADS_ENABLED
+ g_assert(!g_thread_supported());
+# endif
+ g_assert(curl_global_init(CURL_GLOBAL_ALL) == 0);
+ did_curl_init = TRUE;
+ }
+#endif
+#if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
+ if (g_thread_supported()) {
+ return TRUE;
+ }
+ g_thread_init(NULL);
+ success = TRUE;
+#endif
+ return success;
+}
+
+int
+resolve_hostname(const char *hostname,
+ int socktype,
+ struct addrinfo **res,
+ char **canonname)
+{
+ struct addrinfo hints;
+ struct addrinfo *myres;
+ int flags = 0;
+ int result;
+
+ if (res) *res = NULL;
+ if (canonname) {
+ *canonname = NULL;
+ flags = AI_CANONNAME;
+ }
+
+#ifdef AI_ADDRCONFIG
+ flags |= AI_ADDRCONFIG;
+#endif
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = flags;
+ hints.ai_socktype = socktype;
+ result = getaddrinfo(hostname, NULL, &hints, &myres);
+ if (result != 0) {
+ return result;
+ }
+
+ if (canonname && myres && myres->ai_canonname) {
+ *canonname = stralloc(myres->ai_canonname);
+ }
+
+ if (res) {
+ *res = myres;
+ } else {
+ freeaddrinfo(myres);
+ }
+
+ return result;
+}
+
+char *
+_str_exit_status(
+ char *subject,
+ amwait_t status)
+{
+ if (WIFEXITED(status)) {
+ int exitstatus = WEXITSTATUS(status);
+ if (exitstatus == 0)
+ return vstrallocf(_("%s exited normally"), subject);
+ else
+ return vstrallocf(_("%s exited with status %d"), subject, exitstatus);
+ }
+
+ if (WIFSIGNALED(status)) {
+ int signal = WTERMSIG(status);
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status))
+ return vstrallocf(_("%s exited after receiving signal %d (core dumped)"),
+ subject, signal);
+ else
+#endif
+ return vstrallocf(_("%s exited after receiving signal %d"),
+ subject, signal);
+ }
+
+ if (WIFSTOPPED(status)) {
+ int signal = WSTOPSIG(status);
+ return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
+ subject, signal);
+ }
+
+#ifdef WIFCONTINUED
+ if (WIFCONTINUED(status)) {
+ return vstrallocf(_("%s was resumed"), subject);
+ }
+#endif
+
+ return vstrallocf(_("%s exited in unknown circumstances"), subject);
+}
+
+void
+check_running_as(running_as_flags who)
+{
+#ifdef CHECK_USERID
+ struct passwd *pw;
+ uid_t uid_me;
+ uid_t uid_target;
+ char *uname_me = NULL;
+ char *uname_target = NULL;
+ char *dumpuser;
+
+ uid_me = getuid();
+ if ((pw = getpwuid(uid_me)) == NULL) {
+ error(_("current userid %ld not found in password database"), (long)uid_me);
+ /* NOTREACHED */
+ }
+ uname_me = stralloc(pw->pw_name);
+
+#ifndef SINGLE_USERID
+ if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
+ error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
+ (long long int)geteuid(), (long long int)uid_me);
+ /* NOTREACHED */
+ }
+#endif
+
+ switch (who & RUNNING_AS_USER_MASK) {
+ case RUNNING_AS_ROOT:
+ uid_target = 0;
+ uname_target = "root";
+ break;
+
+ case RUNNING_AS_DUMPUSER_PREFERRED:
+ dumpuser = getconf_str(CNF_DUMPUSER);
+ if ((pw = getpwnam(dumpuser)) != NULL &&
+ uid_me != pw->pw_uid) {
+ if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
+ uid_me == pw->pw_uid) {
+ /* uid == CLIENT_LOGIN: not ideal, but OK */
+ dbprintf(_("NOTE: running as '%s', which is the client"
+ " user, not the dumpuser ('%s'); forging"
+ " on anyway\n"),
+ CLIENT_LOGIN, dumpuser);
+ uid_target = uid_me; /* force success below */
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+
+ case RUNNING_AS_DUMPUSER:
+ uname_target = getconf_str(CNF_DUMPUSER);
+ if ((pw = getpwnam(uname_target)) == NULL) {
+ error(_("cannot look up dumpuser \"%s\""), uname_target);
+ /*NOTREACHED*/
+ }
+ uid_target = pw->pw_uid;
+ break;
+
+ case RUNNING_AS_CLIENT_LOGIN:
+ uname_target = CLIENT_LOGIN;
+ if ((pw = getpwnam(uname_target)) == NULL) {
+ error(_("cannot look up client user \"%s\""), uname_target);
+ /*NOTREACHED*/
+ }
+ uid_target = pw->pw_uid;
+ break;
+
+ default:
+ error(_("Unknown check_running_as() call"));
+ /* NOTREACHED */
+ }
+
+ if (uid_me != uid_target) {
+ error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
+ /*NOTREACHED*/
+ }
+ amfree(uname_me);
+
+#else
+ /* Quiet unused variable warning */
+ (void)who;
+#endif
+}
+
+int
+set_root_privs(int need_root)
+{
+#ifndef SINGLE_USERID
+ if (need_root) {
+ if (seteuid(0) == -1) return 0;
+ /* (we don't switch the group back) */
+ } else {
+ if (geteuid() != 0) return 0;
+ if (seteuid(getuid()) == -1) return 0;
+ if (setegid(getgid()) == -1) return 0;
+ }
+#else
+ (void)need_root; /* Quiet unused variable warning */
+#endif
+ return 1;
+}
+
+int
+become_root(void)
+{
+#ifndef SINGLE_USERID
+ if (setuid(0) == -1) return 0;
+#endif
+ return 1;
+}
+
+/*
+ * Process parameters
+ */
+
+/* current process name */
+#define MAX_PNAME 128
+static char pname[MAX_PNAME] = "unknown";
+
+void
+set_pname(char *p)
+{
+ g_strlcpy(pname, p, sizeof(pname));
+}
+
+char *
+get_pname(void)
+{
+ return pname;
+}
+