PHP_FUNCTION(iconv_mime_encode)
{
	const char *field_name = NULL;
	int field_name_len;
	const char *field_value = NULL;
	int field_value_len;
	zval *pref = NULL;
	zval tmp_zv, *tmp_zv_p = NULL;
	smart_str retval = {0};
	php_iconv_err_t err;

	const char *in_charset = get_internal_encoding(TSRMLS_C);
	const char *out_charset = in_charset;
	long line_len = 76;
	const char *lfchars = "\r\n";
	php_iconv_enc_scheme_t scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a",
		&field_name, &field_name_len, &field_value, &field_value_len,
		&pref) == FAILURE) {

		RETURN_FALSE;
	}

	if (pref != NULL) {
		zval **ppval;

		if (zend_hash_find(Z_ARRVAL_P(pref), "scheme", sizeof("scheme"), (void **)&ppval) == SUCCESS) {
			if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
				switch (Z_STRVAL_PP(ppval)[0]) {
					case 'B': case 'b':
						scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
						break;

					case 'Q': case 'q':
						scheme_id = PHP_ICONV_ENC_SCHEME_QPRINT;
						break;
				}
			}
		}

		if (zend_hash_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset"), (void **)&ppval) == SUCCESS) {
			if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
				RETURN_FALSE;
			}

			if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
				in_charset = Z_STRVAL_PP(ppval);
			}
		}

		if (zend_hash_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset"), (void **)&ppval) == SUCCESS) {
			if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
				RETURN_FALSE;
			}

			if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
				out_charset = Z_STRVAL_PP(ppval);
			}
		}

		if (zend_hash_find(Z_ARRVAL_P(pref), "line-length", sizeof("line-length"), (void **)&ppval) == SUCCESS) {
			zval val, *pval = *ppval;

			if (Z_TYPE_P(pval) != IS_LONG) {
				val = *pval;
				zval_copy_ctor(&val);
				convert_to_long(&val);
				pval = &val;
			}

			line_len = Z_LVAL_P(pval);

			if (pval == &val) {
				zval_dtor(&val);
			}
		}

		if (zend_hash_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars"), (void **)&ppval) == SUCCESS) {
			if (Z_TYPE_PP(ppval) != IS_STRING) {
				tmp_zv = **ppval;
				zval_copy_ctor(&tmp_zv);
				convert_to_string(&tmp_zv);

				lfchars = Z_STRVAL(tmp_zv);

				tmp_zv_p = &tmp_zv;
			} else {
				lfchars = Z_STRVAL_PP(ppval);
			}
		}
	}

	err = _php_iconv_mime_encode(&retval, field_name, field_name_len,
		field_value, field_value_len, line_len, lfchars, scheme_id,
		out_charset, in_charset);
	_php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);

	if (err == PHP_ICONV_ERR_SUCCESS) {
		if (retval.c != NULL) {
			RETVAL_STRINGL(retval.c, retval.len, 0);
		} else {
			RETVAL_EMPTY_STRING();
		}
	} else {
		smart_str_free(&retval);
		RETVAL_FALSE;
	}

	if (tmp_zv_p != NULL) {
		zval_dtor(tmp_zv_p);
	}
}


PHP_MINFO_FUNCTION(miconv)
{
	zval iconv_impl, iconv_ver;

	zend_get_constant("ICONV_IMPL", sizeof("ICONV_IMPL")-1, &iconv_impl TSRMLS_CC);
	zend_get_constant("ICONV_VERSION", sizeof("ICONV_VERSION")-1, &iconv_ver TSRMLS_CC);

	php_info_print_table_start();
	php_info_print_table_row(2, "iconv support", "enabled");
	php_info_print_table_row(2, "iconv implementation", Z_STRVAL(iconv_impl));
	php_info_print_table_row(2, "iconv library version", Z_STRVAL(iconv_ver));
	php_info_print_table_end();

	DISPLAY_INI_ENTRIES();

	zval_dtor(&iconv_impl);
	zval_dtor(&iconv_ver);
}


static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd)
{
	return _php_iconv_appendl(d, &c, 1, cd);
}


static char *get_internal_encoding(TSRMLS_D) {
	if (ICONVG(internal_encoding) && ICONVG(internal_encoding)[0]) {
		return ICONVG(internal_encoding);
	} else if (PG(internal_encoding) && PG(internal_encoding)[0]) {
		return PG(internal_encoding);
	} else if (SG(default_charset)) {
		return SG(default_charset);
	}
	return "";
}


static int php_iconv_stream_filter_append_bucket(
		php_iconv_stream_filter *self,
		php_stream *stream, php_stream_filter *filter,
		php_stream_bucket_brigade *buckets_out,
		const char *ps, size_t buf_len, size_t *consumed,
		int persistent TSRMLS_DC)
{
	php_stream_bucket *new_bucket;
	char *out_buf = NULL;
	size_t out_buf_size;
	char *pd, *pt;
	size_t ocnt, prev_ocnt, icnt, tcnt;
	size_t initial_out_buf_size;

	if (ps == NULL) {
		initial_out_buf_size = 64;
		icnt = 1;
	} else {
		initial_out_buf_size = buf_len;
		icnt = buf_len;
	}

	out_buf_size = ocnt = prev_ocnt = initial_out_buf_size;
	if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
		return FAILURE;
	}

	pd = out_buf;

	if (self->stub_len > 0) {
		pt = self->stub;
		tcnt = self->stub_len;

		while (tcnt > 0) {
			if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) {
#if ICONV_SUPPORTS_ERRNO
				switch (errno) {
					case EILSEQ:
						php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
						goto out_failure;

					case EINVAL:
						if (ps != NULL) {
							if (icnt > 0) {
								if (self->stub_len >= sizeof(self->stub)) {
									php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
									goto out_failure;
								}
								self->stub[self->stub_len++] = *(ps++);
								icnt--;
								pt = self->stub;
								tcnt = self->stub_len;
							} else {
								tcnt = 0;
								break;
							}
						} else {
						    php_error_docref(NULL, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
						    goto out_failure;
						}
						break;

					case E2BIG: {
						char *new_out_buf;
						size_t new_out_buf_size;

						new_out_buf_size = out_buf_size << 1;

						if (new_out_buf_size < out_buf_size) {
							/* whoa! no bigger buckets are sold anywhere... */
							if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
								goto out_failure;
							}

							php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);

							out_buf_size = ocnt = initial_out_buf_size;
							if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
								return FAILURE;
							}
							pd = out_buf;
						} else {
							if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
								if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
									goto out_failure;
								}

								php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
								return FAILURE;
							}
							pd = new_out_buf + (pd - out_buf);
							ocnt += (new_out_buf_size - out_buf_size);
							out_buf = new_out_buf;
							out_buf_size = new_out_buf_size;
						}
					} break;

					default:
						php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
						goto out_failure;
				}
#else
				if (ocnt == prev_ocnt) {
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
					goto out_failure;
				}
#endif
			}
			prev_ocnt = ocnt;
		}
		memmove(self->stub, pt, tcnt);
		self->stub_len = tcnt;
	}

	while (icnt > 0) {
		if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt):
					iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) {
#if ICONV_SUPPORTS_ERRNO
			switch (errno) {
				case EILSEQ:
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
					goto out_failure;

				case EINVAL:
					if (ps != NULL) {
						if (icnt > sizeof(self->stub)) {
							php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
							goto out_failure;
						}
						memcpy(self->stub, ps, icnt);
						self->stub_len = icnt;
						ps += icnt;
						icnt = 0;
					} else {
						php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unexpected octet values", self->from_charset, self->to_charset);
						goto out_failure;
					}
					break;

				case E2BIG: {
					char *new_out_buf;
					size_t new_out_buf_size;

					new_out_buf_size = out_buf_size << 1;

					if (new_out_buf_size < out_buf_size) {
						/* whoa! no bigger buckets are sold anywhere... */
						if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
							goto out_failure;
						}

						php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);

						out_buf_size = ocnt = initial_out_buf_size;
						if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
							return FAILURE;
						}
						pd = out_buf;
					} else {
						if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
							if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
								goto out_failure;
							}

							php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
							return FAILURE;
						}
						pd = new_out_buf + (pd - out_buf);
						ocnt += (new_out_buf_size - out_buf_size);
						out_buf = new_out_buf;
						out_buf_size = new_out_buf_size;
					}
				} break;

				default:
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
					goto out_failure;
			}
#else
			if (ocnt == prev_ocnt) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
				goto out_failure;
			}
#endif
		} else {
			if (ps == NULL) {
				break;
			}
		}
		prev_ocnt = ocnt;
	}

	if (out_buf_size - ocnt > 0) {
		if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
			goto out_failure;
		}
		php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
	} else {
		pefree(out_buf, persistent);
	}
	*consumed += buf_len - icnt;

	return SUCCESS;

out_failure:
	pefree(out_buf, persistent);
	return FAILURE;
}


static PHP_INI_MH(OnUpdateOutputEncoding)
{
	if(new_value_length >= ICONV_CSNMAXLEN) {
		return FAILURE;
	}
	if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
		php_error_docref("ref.iconv" TSRMLS_CC, E_DEPRECATED, "Use of iconv.output_encoding is deprecated");
	}
	OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
	return SUCCESS;
}


PHP_FUNCTION(ldap_get_option)
{
	zval *link, *retval;
	ldap_linkdata *ld;
	long option;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
		return;
	}

	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);

	switch (option) {
	/* options with int value */
	case LDAP_OPT_DEREF:
	case LDAP_OPT_SIZELIMIT:
	case LDAP_OPT_TIMELIMIT:
	case LDAP_OPT_PROTOCOL_VERSION:
	case LDAP_OPT_ERROR_NUMBER:
	case LDAP_OPT_REFERRALS:
#ifdef LDAP_OPT_RESTART
	case LDAP_OPT_RESTART:
#endif
		{
			int val;

			if (ldap_get_option(ld->link, option, &val)) {
				RETURN_FALSE;
			}
			zval_dtor(retval);
			ZVAL_LONG(retval, val);
		} break;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
	case LDAP_OPT_NETWORK_TIMEOUT:
		{
			struct timeval *timeout = NULL;

			if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
				if (timeout) {
					ldap_memfree(timeout);
				}
				RETURN_FALSE;
			}
			if (!timeout) {
				RETURN_FALSE;
			}
			zval_dtor(retval);
			ZVAL_LONG(retval, timeout->tv_sec);
			ldap_memfree(timeout);
		} break;
#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
	case LDAP_X_OPT_CONNECT_TIMEOUT:
		{
			int timeout;

			if (ldap_get_option(ld->link, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
				RETURN_FALSE;
			}
			zval_dtor(retval);
			ZVAL_LONG(retval, (timeout / 1000));
		} break;
#endif
#ifdef LDAP_OPT_TIMEOUT
	case LDAP_OPT_TIMEOUT:
		{
			struct timeval *timeout = NULL;

			if (ldap_get_option(ld->link, LDAP_OPT_TIMEOUT, (void *) &timeout)) {
				if (timeout) {
					ldap_memfree(timeout);
				}
				RETURN_FALSE;
			}
			if (!timeout) {
				RETURN_FALSE;
			}
			zval_dtor(retval);
			ZVAL_LONG(retval, timeout->tv_sec);
			ldap_memfree(timeout);
		} break;
#endif
	/* options with string value */
	case LDAP_OPT_ERROR_STRING:
#ifdef LDAP_OPT_HOST_NAME
	case LDAP_OPT_HOST_NAME:
#endif
#ifdef HAVE_LDAP_SASL
	case LDAP_OPT_X_SASL_MECH:
	case LDAP_OPT_X_SASL_REALM:
	case LDAP_OPT_X_SASL_AUTHCID:
	case LDAP_OPT_X_SASL_AUTHZID:
#endif
#ifdef LDAP_OPT_MATCHED_DN
	case LDAP_OPT_MATCHED_DN:
#endif
		{
			char *val = NULL;

			if (ldap_get_option(ld->link, option, &val) || val == NULL || *val == '\0') {
				if (val) {
					ldap_memfree(val);
				}
				RETURN_FALSE;
			}
			zval_dtor(retval);
			ZVAL_STRING(retval, val, 1);
			ldap_memfree(val);
		} break;
/* options not implemented
	case LDAP_OPT_SERVER_CONTROLS:
	case LDAP_OPT_CLIENT_CONTROLS:
	case LDAP_OPT_API_INFO:
	case LDAP_OPT_API_FEATURE_INFO:
*/
	default:
		RETURN_FALSE;
	}
	RETURN_TRUE;
}


PHP_FUNCTION(ldap_next_reference)
{
	zval *link, *result_entry;
	ldap_linkdata *ld;
	ldap_resultentry *resultentry, *resultentry_next;
	LDAPMessage *entry_next;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
		return;
	}

	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);

	if ((entry_next = ldap_next_reference(ld->link, resultentry->data)) == NULL) {
		RETVAL_FALSE;
	} else {
		resultentry_next = emalloc(sizeof(ldap_resultentry));
		ZEND_REGISTER_RESOURCE(return_value, resultentry_next, le_result_entry);
		resultentry_next->id = resultentry->id;
		zend_list_addref(resultentry->id);
		resultentry_next->data = entry_next;
		resultentry_next->ber = NULL;
	}
}


PHP_FUNCTION(ldap_8859_to_t61)
{
	php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}


static void _close_ldap_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
{
	ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;

	ldap_unbind_ext(ld->link, NULL, NULL);
#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)

	if (ld->rebindproc != NULL) {
		zval_dtor(ld->rebindproc);
		FREE_ZVAL(ld->rebindproc);
	}
#endif

	efree(ld);
	LDAPG(num_links)--;
}


PHP_FUNCTION(ldap_next_attribute)
{
	zval *link, *result_entry;
	ldap_linkdata *ld;
	ldap_resultentry *resultentry;
	char *attribute;
	long dummy_ber;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
		return;
	}

	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);

	if (resultentry->ber == NULL) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "called before calling ldap_first_attribute() or no attributes found in result entry");
		RETURN_FALSE;
	}

	if ((attribute = ldap_next_attribute(ld->link, resultentry->data, resultentry->ber)) == NULL) {
#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
		if (resultentry->ber != NULL) {
			ber_free(resultentry->ber, 0);
			resultentry->ber = NULL;
		}
#endif
		RETURN_FALSE;
	} else {
		RETVAL_STRING(attribute, 1);
#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
		ldap_memfree(attribute);
#endif
	}
}


static int proc_pid_instantiate(struct inode *dir,
				   struct dentry * dentry,
				   struct task_struct *task, const void *ptr)
{
	struct inode *inode;

	inode = proc_pid_make_inode(dir->i_sb, task, S_IFDIR | S_IRUGO | S_IXUGO);
	if (!inode)
		goto out;

	inode->i_op = &proc_tgid_base_inode_operations;
	inode->i_fop = &proc_tgid_base_operations;
	inode->i_flags|=S_IMMUTABLE;

	set_nlink(inode, nlink_tgid);

	d_set_d_op(dentry, &pid_dentry_operations);

	d_add(dentry, inode);
	/* Close the race of the process dying before we return the dentry */
	if (pid_revalidate(dentry, 0))
		return 0;
out:
	return -ENOENT;
}


static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
{
	struct task_struct *task;
	struct file *exe_file;

	task = get_proc_task(d_inode(dentry));
	if (!task)
		return -ENOENT;
	exe_file = get_task_exe_file(task);
	put_task_struct(task);
	if (exe_file) {
		*exe_path = exe_file->f_path;
		path_get(&exe_file->f_path);
		fput(exe_file);
		return 0;
	} else
		return -ENOENT;
}


static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
					size_t count, loff_t *offset)
{
	struct inode *inode = file_inode(file);
	struct task_struct *p;
	u64 slack_ns;
	int err;

	err = kstrtoull_from_user(buf, count, 10, &slack_ns);
	if (err < 0)
		return err;

	p = get_proc_task(inode);
	if (!p)
		return -ESRCH;

	if (p != current) {
		if (!capable(CAP_SYS_NICE)) {
			count = -EPERM;
			goto out;
		}

		err = security_task_setscheduler(p);
		if (err) {
			count = err;
			goto out;
		}
	}

	task_lock(p);
	if (slack_ns == 0)
		p->timer_slack_ns = p->default_timer_slack_ns;
	else
		p->timer_slack_ns = slack_ns;
	task_unlock(p);

out:
	put_task_struct(p);

	return count;
}


_archive_skip (struct archive *archive,
	       void           *data,
	       __LA_INT64_T    request)
{
	ZipArchive *zip = (ZipArchive *)data;

	if (!g_seekable_can_seek (G_SEEKABLE (zip->stream)))
		return 0;

	g_seekable_seek (G_SEEKABLE (zip->stream),
			 request,
			 G_SEEK_CUR,
			 NULL,
			 &zip->error);

	if (zip->error) {
		g_clear_error (&zip->error);
		request = 0;
	}

	return request;
}


parse_guid (gchar *string, unsigned short guid[16])
{
	// Maps bytes to positions in guidString
	static const int indexes[] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, 24, 26, 28, 30, 32, 34};
	int i;

	if (strlen (string) <= 35) {
		return FALSE;
	}

	for (i = 0; i < 16; i++) {
		guint hex1;
		guint hex2;

		if (!hex_int (string + indexes[i], 1, &hex1) ||
		    !hex_int (string + indexes[i] + 1, 1, &hex2))
			return FALSE;

		guid[i] = hex1 * 16 + hex2;
	}

	return TRUE;
}


get_ft_font_face_cache (void)
{
	if (g_once_init_enter (&ft_font_face_cache)) {
		GHashTable *h;

		h = g_hash_table_new_full (ft_font_face_hash,
					   ft_font_face_equal,
					   (GDestroyNotify)ft_font_face_free,
					   (GDestroyNotify)cairo_font_face_destroy);
		g_once_init_leave (&ft_font_face_cache, (gsize)h);
	}

	return (GHashTable *)ft_font_face_cache;
}


gxps_archive_finalize (GObject *object)
{
	GXPSArchive *archive = GXPS_ARCHIVE (object);

	g_clear_pointer (&archive->entries, g_hash_table_unref);
	g_clear_object (&archive->filename);
	g_clear_error (&archive->init_error);
	g_clear_object (&archive->resources);

	G_OBJECT_CLASS (gxps_archive_parent_class)->finalize (object);
}


__poll_t dccp_poll(struct file *file, struct socket *sock,
		       poll_table *wait)
{
	__poll_t mask;
	struct sock *sk = sock->sk;

	sock_poll_wait(file, sk_sleep(sk), wait);
	if (sk->sk_state == DCCP_LISTEN)
		return inet_csk_listen_poll(sk);

	/* Socket is not locked. We are protected from async events
	   by poll logic and correct handling of state changes
	   made by another threads is impossible in any case.
	 */

	mask = 0;
	if (sk->sk_err)
		mask = EPOLLERR;

	if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
		mask |= EPOLLHUP;
	if (sk->sk_shutdown & RCV_SHUTDOWN)
		mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;

	/* Connected? */
	if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
		if (atomic_read(&sk->sk_rmem_alloc) > 0)
			mask |= EPOLLIN | EPOLLRDNORM;

		if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
			if (sk_stream_is_writeable(sk)) {
				mask |= EPOLLOUT | EPOLLWRNORM;
			} else {  /* send SIGIO later */
				sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
				set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);

				/* Race breaker. If space is freed after
				 * wspace test but before the flags are set,
				 * IO signal will be lost.
				 */
				if (sk_stream_is_writeable(sk))
					mask |= EPOLLOUT | EPOLLWRNORM;
			}
		}
	}
	return mask;
}


static void gch_tr1(struct SYMBOL *s, int i, int i2)
{
	char *p = &s->text[i],
		*q = p + 1,
		*new_txt;
	int l, latin;
	int n, a, i1, i3, i4;
	static const char note_names[] = "CDEFGAB";
	static const char *latin_names[7] =
			{ "Do", "Ré", "Mi", "Fa", "Sol", "La", "Si" };
	static const char *acc_name[5] = {"bb", "b", "", "#", "##"};
	static const char note_pit[] = {0, 2, 4, 5, 7, 9, 11};
	static const char pit_note[] = {0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6};
	static const char pit_acc[] = {2, 3, 2, 1, 2, 2, 3, 2, 1, 2, 1, 2};

	/* main chord */
	latin = 0;
	switch (*p) {
	case 'A':
	case 'B':
		n = *p - 'A' + 5;
		break;
	case 'C':
	case 'E':
	case 'G':
		n = *p - 'C';
		break;
	case 'D':
		if (p[1] == 'o') {
			latin++;
			n = 0;		/* Do */
			break;
		}
		n = 1;
		break;
	case 'F':
		if (p[1] == 'a')
			latin++;	/* Fa */
		n = 3;
		break;
	case 'L':
		latin++;		/* La */
		n = 5;
		break;
	case 'M':
		latin++;		/* Mi */
		n = 2;
		break;
	case 'R':
		latin++;
		if (p[1] != 'e')
			latin++;	/* Ré */
		n = 1;			/* Re */
		break;
	case 'S':
		latin++;
		if (p[1] == 'o') {
			latin++;
			n = 4;		/* Sol */
		} else {
			n = 6;		/* Si */
		}
		break;
	case '/':			// bass only
		latin--;
		break;
	default:
		return;
	}
	q += latin;

	/* allocate a new string */
	new_txt = getarena(strlen(s->text) + 6);
	l = p - s->text;
	memcpy(new_txt, s->text, l);
	s->text = new_txt;
	new_txt += l;
	p = q;

	if (latin >= 0) {			// if some chord
		a = 0;
		while (*p == '#') {
			a++;
			p++;
		}
		while (*p == 'b') {
			a--;
			p++;
		}
		if (*p == '=')
			p++;
		i3 = (note_pit[n] + a + i2 + 12) % 12;
		i4 = pit_note[i3];
		if (latin == 0)
			*new_txt++ = note_names[i4];
		else
			new_txt += sprintf(new_txt, "%s", latin_names[i4]);
		i1 = pit_acc[i3];			// accidental
		new_txt += sprintf(new_txt, "%s", acc_name[i1]);
	}

	/* bass */
	while (*p != '\0' && *p != '\n' && *p != '/')	// skip 'm'/'dim'..
		*new_txt++ = *p++;
	if (*p == '/') {
		*new_txt++ = *p++;
//fixme: latin names not treated
		q = strchr(note_names, *p);
		if (q) {
			p++;
			n = q - note_names;
			if (*p == '#') {
				a = 1;
				p++;
			} else if (*p == 'b') {
				a = -1;
				p++;
			} else {
				a = 0;
			}
			i3 = (note_pit[n] + a + i2 + 12) % 12;
			i4 = pit_note[i3];
			*new_txt++ = note_names[i4];
			i1 = pit_acc[i3];
			new_txt += sprintf(new_txt, "%s", acc_name[i1]);
		}
	}
	strcpy(new_txt, p);
}


  void releaseID(uint16_t id)
  {
    d_available.push_back(id);
  }


void emitFlightTimes()
{
  uint64_t totals = countLessThan(flightTimes.size());
  unsigned int limits[]={1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 100, 200, 500, 1000, (unsigned int) flightTimes.size()};
  uint64_t sofar=0;
  cout.setf(std::ios::fixed);
  cout.precision(2);
  for(unsigned int i =0 ; i < sizeof(limits)/sizeof(limits[0]); ++i) {
    if(limits[i]!=flightTimes.size())
      cout<<"Within "<<limits[i]<<" msec: ";
    else
      cout<<"Beyond "<<limits[i]-2<<" msec: ";
    uint64_t here = countLessThan(limits[i]);
    cout<<100.0*here/totals<<"% ("<<100.0*(here-sofar)/totals<<"%)"<<endl;
    sofar=here;

  }
}


static void setSocketSendBuffer(int fd, uint32_t size)
{
  setSocketBuffer(fd, SO_SNDBUF, size);
}


read_byte (tga_source_ptr sinfo)
/* Read next byte from Targa file */
{
  register FILE *infile = sinfo->pub.input_file;
  register int c;

  if ((c = getc(infile)) == EOF)
    ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
  return c;
}


get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
/* This version is for reading raw-word-format PGM files with any maxval */
{
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
  register JSAMPROW ptr;
  register U_CHAR * bufferptr;
  register JSAMPLE *rescale = source->rescale;
  JDIMENSION col;

  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
    ERREXIT(cinfo, JERR_INPUT_EOF);
  ptr = source->pub.buffer[0];
  bufferptr = source->iobuffer;
  for (col = cinfo->image_width; col > 0; col--) {
    register int temp;
    temp  = UCH(*bufferptr++) << 8;
    temp |= UCH(*bufferptr++);
    *ptr++ = rescale[temp];
  }
  return 1;
}


int ldb_kv_index_delete(struct ldb_module *module,
			const struct ldb_message *msg)
{
	struct ldb_kv_private *ldb_kv = talloc_get_type(
	    ldb_module_get_private(module), struct ldb_kv_private);
	int ret;
	unsigned int i;

	if (ldb_dn_is_special(msg->dn)) {
		return LDB_SUCCESS;
	}

	ret = ldb_kv_index_onelevel(module, msg, 0);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	ret = ldb_kv_write_index_dn_guid(module, msg, 0);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	if (!ldb_kv->cache->attribute_indexes) {
		/* no indexed fields */
		return LDB_SUCCESS;
	}

	for (i = 0; i < msg->num_elements; i++) {
		ret = ldb_kv_index_del_element(
		    module, ldb_kv, msg, &msg->elements[i]);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	return LDB_SUCCESS;
}


int ldb_kv_reindex(struct ldb_module *module)
{
	struct ldb_kv_private *ldb_kv = talloc_get_type(
	    ldb_module_get_private(module), struct ldb_kv_private);
	int ret;
	struct ldb_kv_reindex_context ctx;

	/*
	 * Only triggered after a modification, but make clear we do
	 * not re-index a read-only DB
	 */
	if (ldb_kv->read_only) {
		return LDB_ERR_UNWILLING_TO_PERFORM;
	}

	if (ldb_kv_cache_reload(module) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/*
	 * Ensure we read (and so remove) the entries from the real
	 * DB, no values stored so far are any use as we want to do a
	 * re-index
	 */
	ldb_kv_index_transaction_cancel(module);

	ret = ldb_kv_index_transaction_start(module);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	/* first traverse the database deleting any @INDEX records by
	 * putting NULL entries in the in-memory tdb
	 */
	ret = ldb_kv->kv_ops->iterate(ldb_kv, delete_index, module);
	if (ret < 0) {
		struct ldb_context *ldb = ldb_module_get_ctx(module);
		ldb_asprintf_errstring(ldb, "index deletion traverse failed: %s",
				       ldb_errstring(ldb));
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ctx.module = module;
	ctx.error = 0;
	ctx.count = 0;

	ret = ldb_kv->kv_ops->iterate(ldb_kv, re_key, &ctx);
	if (ret < 0) {
		struct ldb_context *ldb = ldb_module_get_ctx(module);
		ldb_asprintf_errstring(ldb, "key correction traverse failed: %s",
				       ldb_errstring(ldb));
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (ctx.error != LDB_SUCCESS) {
		struct ldb_context *ldb = ldb_module_get_ctx(module);
		ldb_asprintf_errstring(ldb, "reindexing failed: %s", ldb_errstring(ldb));
		return ctx.error;
	}

	ctx.error = 0;
	ctx.count = 0;

	/* now traverse adding any indexes for normal LDB records */
	ret = ldb_kv->kv_ops->iterate(ldb_kv, re_index, &ctx);
	if (ret < 0) {
		struct ldb_context *ldb = ldb_module_get_ctx(module);
		ldb_asprintf_errstring(ldb, "reindexing traverse failed: %s",
				       ldb_errstring(ldb));
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (ctx.error != LDB_SUCCESS) {
		struct ldb_context *ldb = ldb_module_get_ctx(module);
		ldb_asprintf_errstring(ldb, "reindexing failed: %s", ldb_errstring(ldb));
		return ctx.error;
	}

	if (ctx.count > 10000) {
		ldb_debug(ldb_module_get_ctx(module),
			  LDB_DEBUG_WARNING,
			  "Reindexing: re_index successful on %s, "
			  "final index write-out will be in transaction commit",
			  ldb_kv->kv_ops->name(ldb_kv));
	}
	return LDB_SUCCESS;
}


int ldb_kv_index_del_element(struct ldb_module *module,
			     struct ldb_kv_private *ldb_kv,
			     const struct ldb_message *msg,
			     struct ldb_message_element *el)
{
	const char *dn_str;
	int ret;
	unsigned int i;

	if (!ldb_kv->cache->attribute_indexes) {
		/* no indexed fields */
		return LDB_SUCCESS;
	}

	dn_str = ldb_dn_get_linearized(msg->dn);
	if (dn_str == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (dn_str[0] == '@') {
		return LDB_SUCCESS;
	}

	if (!ldb_kv_is_indexed(module, ldb_kv, el->name)) {
		return LDB_SUCCESS;
	}
	for (i = 0; i < el->num_values; i++) {
		ret = ldb_kv_index_del_value(module, ldb_kv, msg, el, i);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	return LDB_SUCCESS;
}


static bool list_intersect(struct ldb_context *ldb,
			   struct ldb_kv_private *ldb_kv,
			   struct dn_list *list,
			   const struct dn_list *list2)
{
	const struct dn_list *short_list, *long_list;
	struct dn_list *list3;
	unsigned int i;

	if (list->count == 0) {
		/* 0 & X == 0 */
		return true;
	}
	if (list2->count == 0) {
		/* X & 0 == 0 */
		list->count = 0;
		list->dn = NULL;
		return true;
	}

	/* the indexing code is allowed to return a longer list than
	   what really matches, as all results are filtered by the
	   full expression at the end - this shortcut avoids a lot of
	   work in some cases */
	if (list->count < 2 && list2->count > 10 && list2->strict == false) {
		return true;
	}
	if (list2->count < 2 && list->count > 10 && list->strict == false) {
		list->count = list2->count;
		list->dn = list2->dn;
		/* note that list2 may not be the parent of list2->dn,
		   as list2->dn may be owned by ltdb->idxptr. In that
		   case we expect this reparent call to fail, which is
		   OK */
		talloc_reparent(list2, list, list2->dn);
		return true;
	}

	if (list->count > list2->count) {
		short_list = list2;
		long_list = list;
	} else {
		short_list = list;
		long_list = list2;
	}

	list3 = talloc_zero(list, struct dn_list);
	if (list3 == NULL) {
		return false;
	}

	list3->dn = talloc_array(list3, struct ldb_val,
				 MIN(list->count, list2->count));
	if (!list3->dn) {
		talloc_free(list3);
		return false;
	}
	list3->count = 0;

	for (i=0;i<short_list->count;i++) {
		/* For the GUID index case, this is a binary search */
		if (ldb_kv_dn_list_find_val(
			ldb_kv, long_list, &short_list->dn[i]) != -1) {
			list3->dn[list3->count] = short_list->dn[i];
			list3->count++;
		}
	}

	list->strict |= list2->strict;
	list->dn = talloc_steal(list, list3->dn);
	list->count = list3->count;
	talloc_free(list3);

	return true;
}


static struct dn_list *ldb_kv_index_idxptr(struct ldb_module *module,
					   TDB_DATA rec,
					   bool check_parent)
{
	struct dn_list *list;
	if (rec.dsize != sizeof(void *)) {
		ldb_asprintf_errstring(ldb_module_get_ctx(module),
				       "Bad data size for idxptr %u", (unsigned)rec.dsize);
		return NULL;
	}
	/* note that we can't just use a cast here, as rec.dptr may
	   not be aligned sufficiently for a pointer. A cast would cause
	   platforms like some ARM CPUs to crash */
	memcpy(&list, rec.dptr, sizeof(void *));
	list = talloc_get_type(list, struct dn_list);
	if (list == NULL) {
		ldb_asprintf_errstring(ldb_module_get_ctx(module),
				       "Bad type '%s' for idxptr",
				       talloc_get_name(list));
		return NULL;
	}
	if (check_parent && list->dn && talloc_parent(list->dn) != list) {
		ldb_asprintf_errstring(ldb_module_get_ctx(module),
				       "Bad parent '%s' for idxptr",
				       talloc_get_name(talloc_parent(list->dn)));
		return NULL;
	}
	return list;
}


static int ldb_kv_index_onelevel(struct ldb_module *module,
				 const struct ldb_message *msg,
				 int add)
{
	struct ldb_kv_private *ldb_kv = talloc_get_type(
	    ldb_module_get_private(module), struct ldb_kv_private);
	struct ldb_dn *pdn;
	int ret;

	/* We index for ONE Level only if requested */
	if (!ldb_kv->cache->one_level_indexes) {
		return LDB_SUCCESS;
	}

	pdn = ldb_dn_get_parent(module, msg->dn);
	if (pdn == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}
	ret =
	    ldb_kv_modify_index_dn(module, ldb_kv, msg, pdn, LDB_KV_IDXONE, add);

	talloc_free(pdn);

	return ret;
}


static int lsql_rename(struct lsql_context *ctx)
{
	struct ldb_module *module = ctx->module;
	struct ldb_request *req = ctx->req;
	struct lsqlite3_private *lsqlite3;
	struct ldb_context *ldb;
	char *new_dn, *new_cdn, *old_cdn;
	char *errmsg;
	char *query;
	int ret;

	ldb = ldb_module_get_ctx(module);
	lsqlite3 = talloc_get_type(ldb_module_get_private(module),
				   struct lsqlite3_private);

	/* create linearized and normalized dns */
	old_cdn = ldb_dn_alloc_casefold(ctx, req->op.rename.olddn);
	new_cdn = ldb_dn_alloc_casefold(ctx, req->op.rename.newdn);
	new_dn = ldb_dn_alloc_linearized(ctx, req->op.rename.newdn);
	if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* build the SQL query */
	query = lsqlite3_tprintf(ctx,
				 "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' "
				 "WHERE norm_dn = '%q';",
				 new_dn, new_cdn, old_cdn);
	if (query == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* execute */
	ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
	if (ret != SQLITE_OK) {
		if (errmsg) {
			ldb_set_errstring(ldb, errmsg);
			free(errmsg);
		}
		return LDB_ERR_OPERATIONS_ERROR;
	}

	return LDB_SUCCESS;
}


static char *parsetree_to_sql(struct ldb_module *module,
			      void *mem_ctx,
			      const struct ldb_parse_tree *t)
{
	struct ldb_context *ldb;
	const struct ldb_schema_attribute *a;
	struct ldb_val value, subval;
	char *wild_card_string;
	char *child, *tmp;
	char *ret = NULL;
	char *attr;
	unsigned int i;

	ldb = ldb_module_get_ctx(module);

	switch(t->operation) {
	case LDB_OP_AND:

		tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]);
		if (tmp == NULL) return NULL;

		for (i = 1; i < t->u.list.num_elements; i++) {

			child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]);
			if (child == NULL) return NULL;

			tmp = talloc_asprintf_append(tmp, " INTERSECT %s ", child);
			if (tmp == NULL) return NULL;
		}

		ret = talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )\n", tmp);

		return ret;

	case LDB_OP_OR:

		tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]);
		if (tmp == NULL) return NULL;

		for (i = 1; i < t->u.list.num_elements; i++) {

			child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]);
			if (child == NULL) return NULL;

			tmp = talloc_asprintf_append(tmp, " UNION %s ", child);
			if (tmp == NULL) return NULL;
		}

		return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s ) ", tmp);

	case LDB_OP_NOT:

		child = parsetree_to_sql(module, mem_ctx, t->u.isnot.child);
		if (child == NULL) return NULL;

		return talloc_asprintf(mem_ctx,
					"SELECT eid FROM ldb_entry "
					"WHERE eid NOT IN ( %s ) ", child);

	case LDB_OP_EQUALITY:
		/*
		 * For simple searches, we want to retrieve the list of EIDs that
		 * match the criteria.
		*/
		attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
		if (attr == NULL) return NULL;
		a = ldb_schema_attribute_by_name(ldb, attr);

		/* Get a canonicalised copy of the data */
		a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.equality.value), &value);
		if (value.data == NULL) {
			return NULL;
		}

		if (strcasecmp(t->u.equality.attr, "dn") == 0) {
			/* DN query is a special ldb case */
		 	const char *cdn = ldb_dn_get_casefold(
						ldb_dn_new(mem_ctx, ldb,
							      (const char *)value.data));
			if (cdn == NULL) {
				return NULL;
			}

			return lsqlite3_tprintf(mem_ctx,
						"SELECT eid FROM ldb_entry "
						"WHERE norm_dn = '%q'", cdn);

		} else {
			/* A normal query. */
			return lsqlite3_tprintf(mem_ctx,
						"SELECT eid FROM ldb_attribute_values "
						"WHERE norm_attr_name = '%q' "
						"AND norm_attr_value = '%q'",
						attr,
						value.data);

		}

	case LDB_OP_SUBSTRING:

		wild_card_string = talloc_strdup(mem_ctx,
					(t->u.substring.start_with_wildcard)?"*":"");
		if (wild_card_string == NULL) return NULL;

		for (i = 0; t->u.substring.chunks[i]; i++) {
			wild_card_string = talloc_asprintf_append(wild_card_string, "%s*",
							t->u.substring.chunks[i]->data);
			if (wild_card_string == NULL) return NULL;
		}

		if ( ! t->u.substring.end_with_wildcard ) {
			/* remove last wildcard */
			wild_card_string[strlen(wild_card_string) - 1] = '\0';
		}

		attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr);
		if (attr == NULL) return NULL;
		a = ldb_schema_attribute_by_name(ldb, attr);

		subval.data = (void *)wild_card_string;
		subval.length = strlen(wild_card_string) + 1;

		/* Get a canonicalised copy of the data */
		a->syntax->canonicalise_fn(ldb, mem_ctx, &(subval), &value);
		if (value.data == NULL) {
			return NULL;
		}

		return lsqlite3_tprintf(mem_ctx,
					"SELECT eid FROM ldb_attribute_values "
					"WHERE norm_attr_name = '%q' "
					"AND norm_attr_value GLOB '%q'",
					attr,
					value.data);

	case LDB_OP_GREATER:
		attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
		if (attr == NULL) return NULL;
		a = ldb_schema_attribute_by_name(ldb, attr);

		/* Get a canonicalised copy of the data */
		a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.equality.value), &value);
		if (value.data == NULL) {
			return NULL;
		}

		return lsqlite3_tprintf(mem_ctx,
					"SELECT eid FROM ldb_attribute_values "
					"WHERE norm_attr_name = '%q' "
					"AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ",
					attr,
					value.data,
					attr);

	case LDB_OP_LESS:
		attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
		if (attr == NULL) return NULL;
		a = ldb_schema_attribute_by_name(ldb, attr);

		/* Get a canonicalised copy of the data */
		a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.equality.value), &value);
		if (value.data == NULL) {
			return NULL;
		}

		return lsqlite3_tprintf(mem_ctx,
					"SELECT eid FROM ldb_attribute_values "
					"WHERE norm_attr_name = '%q' "
					"AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ",
					attr,
					value.data,
					attr);

	case LDB_OP_PRESENT:
		if (strcasecmp(t->u.present.attr, "dn") == 0) {
			return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry");
		}

		attr = ldb_attr_casefold(mem_ctx, t->u.present.attr);
		if (attr == NULL) return NULL;

		return lsqlite3_tprintf(mem_ctx,
					"SELECT eid FROM ldb_attribute_values "
					"WHERE norm_attr_name = '%q' ",
					attr);

	case LDB_OP_APPROX:
		attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
		if (attr == NULL) return NULL;
		a = ldb_schema_attribute_by_name(ldb, attr);

		/* Get a canonicalised copy of the data */
		a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.equality.value), &value);
		if (value.data == NULL) {
			return NULL;
		}

		return lsqlite3_tprintf(mem_ctx,
					"SELECT eid FROM ldb_attribute_values "
					"WHERE norm_attr_name = '%q' "
					"AND ldap_compare(norm_attr_value, '~%', 'q', '%q') ",
					attr,
					value.data,
					attr);

	case LDB_OP_EXTENDED:
#warning  "work out how to handle bitops"
		return NULL;

	default:
		break;
	};

	/* should never occur */
	abort();
	return NULL;
}


static void lsql_callback(struct tevent_context *ev,
			  struct tevent_timer *te,
			  struct timeval t,
			  void *private_data)
{
	struct lsql_context *ctx;
	int ret;

	ctx = talloc_get_type(private_data, struct lsql_context);

	switch (ctx->req->operation) {
	case LDB_SEARCH:
		ret = lsql_search(ctx);
		break;
	case LDB_ADD:
		ret = lsql_add(ctx);
		break;
	case LDB_MODIFY:
		ret = lsql_modify(ctx);
		break;
	case LDB_DELETE:
		ret = lsql_delete(ctx);
		break;
	case LDB_RENAME:
		ret = lsql_rename(ctx);
		break;
/* TODO:
	case LDB_EXTENDED:
		ret = lsql_extended(ctx);
		break;
 */
	default:
		/* no other op supported */
		ret = LDB_ERR_PROTOCOL_ERROR;
	}

	if (!ctx->callback_failed) {
		/* Once we are done, we do not need timeout events */
		talloc_free(ctx->timeout_event);
		lsql_request_done(ctx, ret);
	}
}


static int ldb_kv_sequence_number(struct ldb_kv_context *ctx,
				  struct ldb_extended **ext)
{
	struct ldb_context *ldb;
	struct ldb_module *module = ctx->module;
	struct ldb_request *req = ctx->req;
	void *data = ldb_module_get_private(module);
	struct ldb_kv_private *ldb_kv =
	    talloc_get_type(data, struct ldb_kv_private);
	TALLOC_CTX *tmp_ctx = NULL;
	struct ldb_seqnum_request *seq;
	struct ldb_seqnum_result *res;
	struct ldb_message *msg = NULL;
	struct ldb_dn *dn;
	const char *date;
	int ret = LDB_SUCCESS;

	ldb = ldb_module_get_ctx(module);

	seq = talloc_get_type(req->op.extended.data,
				struct ldb_seqnum_request);
	if (seq == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ldb_request_set_state(req, LDB_ASYNC_PENDING);

	if (ldb_kv->kv_ops->lock_read(module) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	res = talloc_zero(req, struct ldb_seqnum_result);
	if (res == NULL) {
		ret = LDB_ERR_OPERATIONS_ERROR;
		goto done;
	}

	tmp_ctx = talloc_new(req);
	if (tmp_ctx == NULL) {
		ret = LDB_ERR_OPERATIONS_ERROR;
		goto done;
	}

	dn = ldb_dn_new(tmp_ctx, ldb, LDB_KV_BASEINFO);
	if (dn == NULL) {
		ret = LDB_ERR_OPERATIONS_ERROR;
		goto done;
	}

	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		ret = LDB_ERR_OPERATIONS_ERROR;
		goto done;
	}

	ret = ldb_kv_search_dn1(module, dn, msg, 0);
	if (ret != LDB_SUCCESS) {
		goto done;
	}

	switch (seq->type) {
	case LDB_SEQ_HIGHEST_SEQ:
		res->seq_num = ldb_msg_find_attr_as_uint64(msg, LDB_KV_SEQUENCE_NUMBER, 0);
		break;
	case LDB_SEQ_NEXT:
		res->seq_num = ldb_msg_find_attr_as_uint64(msg, LDB_KV_SEQUENCE_NUMBER, 0);
		res->seq_num++;
		break;
	case LDB_SEQ_HIGHEST_TIMESTAMP:
		date = ldb_msg_find_attr_as_string(msg, LDB_KV_MOD_TIMESTAMP, NULL);
		if (date) {
			res->seq_num = ldb_string_to_time(date);
		} else {
			res->seq_num = 0;
			/* zero is as good as anything when we don't know */
		}
		break;
	}

	*ext = talloc_zero(req, struct ldb_extended);
	if (*ext == NULL) {
		ret = LDB_ERR_OPERATIONS_ERROR;
		goto done;
	}
	(*ext)->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
	(*ext)->data = talloc_steal(*ext, res);

done:
	talloc_free(tmp_ctx);

	ldb_kv->kv_ops->unlock_read(module);
	return ret;
}


static int ldb_kv_find_element(const struct ldb_message *msg, const char *name)
{
	unsigned int i;
	for (i=0;i<msg->num_elements;i++) {
		if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
			return i;
		}
	}
	return -1;
}


static int ldb_kv_lock_read(struct ldb_module *module)
{
	void *data = ldb_module_get_private(module);
	struct ldb_kv_private *ldb_kv =
	    talloc_get_type(data, struct ldb_kv_private);
	return ldb_kv->kv_ops->lock_read(module);
}


static int ldb_kv_msg_delete_element(struct ldb_module *module,
				     struct ldb_kv_private *ldb_kv,
				     struct ldb_message *msg,
				     const char *name,
				     const struct ldb_val *val)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	unsigned int i;
	int found, ret;
	struct ldb_message_element *el;
	const struct ldb_schema_attribute *a;

	found = ldb_kv_find_element(msg, name);
	if (found == -1) {
		return LDB_ERR_NO_SUCH_ATTRIBUTE;
	}

	i = (unsigned int) found;
	el = &(msg->elements[i]);

	a = ldb_schema_attribute_by_name(ldb, el->name);

	for (i=0;i<el->num_values;i++) {
		bool matched;
		if (a->syntax->operator_fn) {
			ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
						     &el->values[i], val, &matched);
			if (ret != LDB_SUCCESS) return ret;
		} else {
			matched = (a->syntax->comparison_fn(ldb, ldb,
							    &el->values[i], val) == 0);
		}
		if (matched) {
			if (el->num_values == 1) {
				return ldb_kv_msg_delete_attribute(
				    module, ldb_kv, msg, name);
			}

			ret =
			    ldb_kv_index_del_value(module, ldb_kv, msg, el, i);
			if (ret != LDB_SUCCESS) {
				return ret;
			}

			if (i<el->num_values-1) {
				memmove(&el->values[i], &el->values[i+1],
					sizeof(el->values[i])*
						(el->num_values-(i+1)));
			}
			el->num_values--;

			/* per definition we find in a canonicalised message an
			   attribute value only once. So we are finished here */
			return LDB_SUCCESS;
		}
	}

	/* Not found */
	return LDB_ERR_NO_SUCH_ATTRIBUTE;
}


static int ldb_kv_unlock_read(struct ldb_module *module)
{
	void *data = ldb_module_get_private(module);
	struct ldb_kv_private *ldb_kv =
	    talloc_get_type(data, struct ldb_kv_private);
	return ldb_kv->kv_ops->unlock_read(module);
}


struct ldb_val ldb_kv_key_msg(struct ldb_module *module,
			TALLOC_CTX *mem_ctx,
			const struct ldb_message *msg)
{
	void *data = ldb_module_get_private(module);
	struct ldb_kv_private *ldb_kv =
	    talloc_get_type(data, struct ldb_kv_private);
	struct ldb_val key;
	const struct ldb_val *guid_val;
	int ret;

	if (ldb_kv->cache->GUID_index_attribute == NULL) {
		return ldb_kv_key_dn(module, mem_ctx, msg->dn);
	}

	if (ldb_dn_is_special(msg->dn)) {
		return ldb_kv_key_dn(module, mem_ctx, msg->dn);
	}

	guid_val =
	    ldb_msg_find_ldb_val(msg, ldb_kv->cache->GUID_index_attribute);
	if (guid_val == NULL) {
		ldb_asprintf_errstring(ldb_module_get_ctx(module),
				       "Did not find GUID attribute %s "
				       "in %s, required for TDB record "
				       "key in " LDB_KV_IDXGUID " mode.",
				       ldb_kv->cache->GUID_index_attribute,
				       ldb_dn_get_linearized(msg->dn));
		errno = EINVAL;
		key.data = NULL;
		key.length = 0;
		return key;
	}

	/* In this case, allocate with talloc */
	key.data = talloc_size(mem_ctx, LDB_KV_GUID_KEY_SIZE);
	if (key.data == NULL) {
		errno = ENOMEM;
		key.data = NULL;
		key.length = 0;
		return key;
	}
	key.length = talloc_get_size(key.data);

	ret = ldb_kv_guid_to_key(module, ldb_kv, guid_val, &key);

	if (ret != LDB_SUCCESS) {
		errno = EINVAL;
		key.data = NULL;
		key.length = 0;
		return key;
	}
	return key;
}


static void ldb_kv_request_done(struct ldb_kv_context *ctx, int error)
{
	struct ldb_context *ldb;
	struct ldb_request *req;
	struct ldb_reply *ares;

	ldb = ldb_module_get_ctx(ctx->module);
	req = ctx->req;

	/* if we already returned an error just return */
	if (ldb_request_get_status(req) != LDB_SUCCESS) {
		return;
	}

	ares = talloc_zero(req, struct ldb_reply);
	if (!ares) {
		ldb_oom(ldb);
		req->callback(req, NULL);
		return;
	}
	ares->type = LDB_REPLY_DONE;
	ares->error = error;

	req->callback(req, ares);
}


static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv,
					 struct ldb_kv_context *ctx)
{
	struct ldb_message *msg, *filtered_msg;
	struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
	const char *dn_linearized;
	const char *msg_dn_linearlized;
	int ret;
	bool matched;

	msg = ldb_msg_new(ctx);
	if (!msg) {
		return LDB_ERR_OPERATIONS_ERROR;
	}
	ret = ldb_kv_search_dn1(ctx->module,
				ctx->base,
				msg,
				LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC |
				    LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);

	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		if (ldb_kv->check_base == false) {
			/*
			 * In this case, we are done, as no base
			 * checking is allowed in this DB
			 */
			talloc_free(msg);
			return LDB_SUCCESS;
		}
		ldb_asprintf_errstring(ldb,
				       "No such Base DN: %s",
				       ldb_dn_get_linearized(ctx->base));
	}
	if (ret != LDB_SUCCESS) {
		talloc_free(msg);
		return ret;
	}

	/*
	 * We use this, not ldb_match_msg_error() as we know
	 * we matched on the scope BASE, as we just fetched
	 * the base DN
	 */

	ret = ldb_match_message(ldb, msg,
				ctx->tree,
				ctx->scope,
				&matched);
	if (ret != LDB_SUCCESS) {
		talloc_free(msg);
		return ret;
	}
	if (!matched) {
		talloc_free(msg);
		return LDB_SUCCESS;
	}

	dn_linearized = ldb_dn_get_linearized(ctx->base);
	msg_dn_linearlized = ldb_dn_get_linearized(msg->dn);

	if (strcmp(dn_linearized, msg_dn_linearlized) == 0) {
		/*
		 * If the DN is exactly the same string, then
		 * re-use the full incoming DN for the
		 * returned result, as it has already been
		 * casefolded
		 */
		msg->dn = ctx->base;
	}

	/*
	 * filter the attributes that the user wants.
	 *
	 * This copies msg->dn including the casefolding, so the above
	 * assignment is safe
	 */
	ret = ldb_kv_filter_attrs(ctx, msg, ctx->attrs, &filtered_msg);

	/*
	 * Remove any extended components possibly copied in from
	 * msg->dn, we just want the casefold components
	 */
	ldb_dn_remove_extended_components(filtered_msg->dn);
	talloc_free(msg);

	if (ret == -1) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ret = ldb_module_send_entry(ctx->req, filtered_msg, NULL);
	if (ret != LDB_SUCCESS) {
		/* Regardless of success or failure, the msg
		 * is the callbacks responsiblity, and should
		 * not be talloc_free()'ed */
		ctx->request_terminated = true;
		return ret;
	}

	return LDB_SUCCESS;
}


static int msg_add_distinguished_name(struct ldb_message *msg)
{
	struct ldb_message_element el;
	struct ldb_val val;
	int ret;

	el.flags = 0;
	el.name = "distinguishedName";
	el.num_values = 1;
	el.values = &val;
	el.flags = 0;
	val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
	if (val.data == NULL) {
		return -1;
	}
	val.length = strlen((char *)val.data);

	ret = msg_add_element(msg, &el, 1);
	return ret;
}


bool ldb_kv_key_is_record(struct ldb_val key)
{
	if (key.length < 4) {
		return false;
	}

	if (memcmp(key.data, "DN=", 3) == 0) {
		return true;
	}

	if (memcmp(key.data, "ID=", 3) == 0) {
		return true;
	}

	if (key.length < sizeof(LDB_KV_GUID_KEY_PREFIX)) {
		return false;
	}

	if (memcmp(key.data, LDB_KV_GUID_KEY_PREFIX,
		   sizeof(LDB_KV_GUID_KEY_PREFIX) - 1) == 0) {
		return true;
	}

	return false;
}


void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
{
    fi->seek(0, SEEK_SET);
    fi->readx(&ehdri, sizeof(ehdri));
    assert(e_phoff == sizeof(Elf64_Ehdr));  // checked by canPack()
    sz_phdrs = e_phnum * get_te16(&ehdri.e_phentsize);

    Elf64_Phdr *phdr = phdri;
    note_size = 0;
    for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
        if (PT_NOTE64 == get_te32(&phdr->p_type)) {
            note_size += up4(get_te64(&phdr->p_filesz));
        }
    }
    if (note_size) {
        note_body = New(unsigned char, note_size);
        note_size = 0;
    }
    phdr = phdri;
    for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
        unsigned const type = get_te32(&phdr->p_type);
        if (PT_NOTE64 == type) {
            unsigned const len = get_te64(&phdr->p_filesz);
            fi->seek(get_te64(&phdr->p_offset), SEEK_SET);
            fi->readx(&note_body[note_size], len);
            note_size += up4(len);
        }
        if (PT_LOAD64 == type) {
            unsigned x = get_te64(&phdr->p_align) >> lg2_page;
            while (x>>=1) {
                ++lg2_page;
            }
        }
        if (PT_GNU_STACK64 == type) {
            gnu_stack = phdr;
        }
    }
    page_size =  1u  <<lg2_page;
    page_mask = ~0ull<<lg2_page;

    progid = 0;  // getRandomId();  not useful, so do not clutter
    sz_elf_hdrs = sizeof(ehdri) + sz_phdrs;
    if (0!=xct_off) {  // shared library
        sz_elf_hdrs = xct_off;
        lowmem.alloc(xct_off + (!opt->o_unix.android_shlib
            ? 0
            : e_shnum * sizeof(Elf64_Shdr)));
        memcpy(lowmem, file_image, xct_off);  // android omits Shdr here
        fo->write(lowmem, xct_off);  // < SHF_EXECINSTR (typ: in .plt or .init)
        if (opt->o_unix.android_shlib) {
            // In order to pacify the runtime linker on Android "O" ("Oreo"),
            // we will splice-in a 4KiB page that contains an "extra" copy
            // of the Shdr, any PT_NOTE above xct_off, and shstrtab.
            // File order: Ehdr, Phdr[], section contents below xct_off,
            //    Shdr_copy[], PT_NOTEs.hi, shstrtab.
            xct_va  += asl_delta;
            //xct_off += asl_delta;  // not yet

            // Relocate PT_DYNAMIC (in 2nd PT_LOAD)
            Elf64_Dyn *dyn = const_cast<Elf64_Dyn *>(dynseg);
            for (; dyn->d_tag; ++dyn) {
                upx_uint64_t d_tag = get_te64(&dyn->d_tag);
                if (Elf64_Dyn::DT_FINI       == d_tag
                ||  Elf64_Dyn::DT_FINI_ARRAY == d_tag
                ||  Elf64_Dyn::DT_INIT_ARRAY == d_tag
                ||  Elf64_Dyn::DT_PREINIT_ARRAY == d_tag
                ||  Elf64_Dyn::DT_PLTGOT      == d_tag) {
                    upx_uint64_t d_val = get_te64(&dyn->d_val);
                    set_te64(&dyn->d_val, asl_delta + d_val);
                }
            }

            // Relocate dynsym (DT_SYMTAB) which is below xct_va
            upx_uint64_t const off_dynsym = get_te64(&sec_dynsym->sh_offset);
            upx_uint64_t const sz_dynsym  = get_te64(&sec_dynsym->sh_size);
            Elf64_Sym *dyntym = (Elf64_Sym *)lowmem.subref(
                "bad dynsym", off_dynsym, sz_dynsym);
            Elf64_Sym *sym = dyntym;
            for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) {
                upx_uint64_t symval = get_te64(&sym->st_value);
                unsigned symsec = get_te16(&sym->st_shndx);
                if (Elf64_Sym::SHN_UNDEF != symsec
                &&  Elf64_Sym::SHN_ABS   != symsec
                &&  xct_off <= symval) {
                    set_te64(&sym->st_value, asl_delta + symval);
                }
            }

            // Relocate Phdr virtual addresses, but not physical offsets and sizes
            unsigned char buf_notes[512]; memset(buf_notes, 0, sizeof(buf_notes));
            unsigned len_notes = 0;
            phdr = (Elf64_Phdr *)lowmem.subref(
                "bad e_phoff", e_phoff, e_phnum * sizeof(Elf64_Phdr));
            for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
                upx_uint64_t offset = get_te64(&phdr->p_offset);
                if (xct_off <= offset) { // above the extra page
                    if (PT_NOTE64 == get_te32(&phdr->p_type)) {
                        upx_uint64_t memsz = get_te64(&phdr->p_memsz);
                        if (sizeof(buf_notes) < (memsz + len_notes)) {
                            throwCantPack("PT_NOTES too big");
                        }
                        set_te64(&phdr->p_vaddr,
                            len_notes + (e_shnum * sizeof(Elf64_Shdr)) + xct_off);
                        phdr->p_offset = phdr->p_paddr = phdr->p_vaddr;
                        memcpy(&buf_notes[len_notes], &file_image[offset], memsz);
                        len_notes += memsz;
                    }
                    else {
                        //set_te64(&phdr->p_offset, asl_delta + offset);  // physical
                        upx_uint64_t addr = get_te64(&phdr->p_paddr);
                        set_te64(&phdr->p_paddr, asl_delta + addr);
                                     addr = get_te64(&phdr->p_vaddr);
                        set_te64(&phdr->p_vaddr, asl_delta + addr);
                    }
                }
                // .p_filesz,.p_memsz are updated in ::pack3
            }

            Elf64_Ehdr *const ehdr = (Elf64_Ehdr *)&lowmem[0];
            upx_uint64_t e_entry = get_te64(&ehdr->e_entry);
            if (xct_off < e_entry) {
                set_te64(&ehdr->e_entry, asl_delta + e_entry);
            }
            // Relocate Shdr; and Rela, Rel (below xct_off)
            set_te64(&ehdr->e_shoff, xct_off);
            memcpy(&lowmem[xct_off], shdri, e_shnum * sizeof(Elf64_Shdr));
            Elf64_Shdr *const shdro = (Elf64_Shdr *)&lowmem[xct_off];
            Elf64_Shdr *shdr = shdro;
            upx_uint64_t sz_shstrtab  = get_te64(&sec_strndx->sh_size);
            for (unsigned j = 0; j < e_shnum; ++j, ++shdr) {
                unsigned sh_type = get_te32(&shdr->sh_type);
                upx_uint64_t sh_size = get_te64(&shdr->sh_size);
                upx_uint64_t sh_offset = get_te64(&shdr->sh_offset);
                upx_uint64_t sh_entsize = get_te64(&shdr->sh_entsize);

                if (xct_off <= sh_offset) {
                    upx_uint64_t addr = get_te64(&shdr->sh_addr);
                    set_te64(&shdr->sh_addr, asl_delta + addr);
                }
                if (Elf64_Shdr::SHT_RELA == sh_type) {
                    if (sizeof(Elf64_Rela) != sh_entsize) {
                        char msg[50];
                        snprintf(msg, sizeof(msg), "bad Rela.sh_entsize %lu", (long)sh_entsize);
                        throwCantPack(msg);
                    }
                    n_jmp_slot = 0;
                    plt_off = ~0ull;
                    Elf64_Rela *const relb = (Elf64_Rela *)lowmem.subref(
                         "bad Rela offset", sh_offset, sh_size);
                    Elf64_Rela *rela = relb;
                    for (int k = sh_size / sh_entsize; --k >= 0; ++rela) {
                        upx_uint64_t r_addend = get_te64(&rela->r_addend);
                        upx_uint64_t r_offset = get_te64(&rela->r_offset);
                        upx_uint64_t r_info   = get_te64(&rela->r_info);
                        unsigned r_type = ELF64_R_TYPE(r_info);
                        if (xct_off <= r_offset) {
                            set_te64(&rela->r_offset, asl_delta + r_offset);
                        }
                        if (Elf64_Ehdr::EM_AARCH64 == e_machine) {
                            if (R_AARCH64_RELATIVE == r_type) {
                                if (xct_off <= r_addend) {
                                    set_te64(&rela->r_addend, asl_delta + r_addend);
                                }
                            }
                            if (R_AARCH64_JUMP_SLOT == r_type) {
                                // .rela.plt contains offset of the "first time" target
                                if (plt_off > r_offset) {
                                    plt_off = r_offset;
                                }
                                upx_uint64_t d = elf_get_offset_from_address(r_offset);
                                upx_uint64_t w = get_te64(&file_image[d]);
                                if (xct_off <= w) {
                                    set_te64(&file_image[d], asl_delta + w);
                                }
                                ++n_jmp_slot;
                            }
                        }
                    }
                    fo->seek(sh_offset, SEEK_SET);
                    fo->rewrite(relb, sh_size);
                }
                if (Elf64_Shdr::SHT_REL == sh_type) {
                    if (sizeof(Elf64_Rel) != sh_entsize) {
                        char msg[50];
                        snprintf(msg, sizeof(msg), "bad Rel.sh_entsize %lu", (long)sh_entsize);
                        throwCantPack(msg);
                    }
                    Elf64_Rel *rel = (Elf64_Rel *)lowmem.subref(
                            "bad Rel sh_offset", sh_offset, sh_size);
                    for (int k = sh_size / sh_entsize; --k >= 0; ++rel) {
                        upx_uint64_t r_offset = get_te64(&rel->r_offset);
                        if (xct_off <= r_offset) {
                            set_te64(&rel->r_offset, asl_delta + r_offset);
                        }
                        // r_offset must be in 2nd PT_LOAD; .p_vaddr was already relocated
                        upx_uint64_t d = elf_get_offset_from_address(asl_delta + r_offset);
                        upx_uint64_t w = get_te64(&file_image[d]);
                        upx_uint64_t r_info = get_te64(&rel->r_info);
                        unsigned r_type = ELF64_R_TYPE(r_info);
                        if (xct_off <= w
                        &&  Elf64_Ehdr::EM_AARCH64 == e_machine
                        &&  (  R_AARCH64_RELATIVE  == r_type
                            || R_AARCH64_JUMP_SLOT == r_type)) {
                            set_te64(&file_image[d], asl_delta + w);
                        }
                    }
                }
                if (Elf64_Shdr::SHT_NOTE == sh_type) {
                    if (xct_off <= sh_offset) {
                        set_te64(&shdr->sh_offset,
                            (e_shnum * sizeof(Elf64_Shdr)) + xct_off);
                        shdr->sh_addr = shdr->sh_offset;
                    }
                }
            }
            // shstrndx will move
            set_te64(&shdro[get_te16(&ehdri.e_shstrndx)].sh_offset,
                len_notes + e_shnum * sizeof(Elf64_Shdr) + xct_off);

            // (Re-)write all changes below xct_off
            fo->seek(0, SEEK_SET);
            fo->rewrite(lowmem, xct_off);

            // New copy of Shdr
            Elf64_Shdr blank; memset(&blank, 0, sizeof(blank));
            set_te64(&blank.sh_offset, xct_off);  // hint for "upx -d"
            fo->write(&blank, sizeof(blank));
            fo->write(&shdro[1], (-1+ e_shnum) * sizeof(Elf64_Shdr));

            if (len_notes) {
                fo->write(buf_notes, len_notes);
            }

            // New copy of Shdr[.e_shstrndx].[ sh_offset, +.sh_size )
            fo->write(shstrtab,  sz_shstrtab);

            sz_elf_hdrs = fpad8(fo);
            //xct_off += asl_delta;  // wait until ::pack3
        }
        memset(&linfo, 0, sizeof(linfo));
        fo->write(&linfo, sizeof(linfo));
    }

    // only execute if option present
    if (opt->o_unix.preserve_build_id) {
        // set this so we can use elf_find_section_name
        e_shnum = get_te16(&ehdri.e_shnum);
        if (!shdri) {
            shdri = (Elf64_Shdr *)&file_image[get_te32(&ehdri.e_shoff)];
        }
        //set the shstrtab
        sec_strndx = &shdri[get_te16(&ehdri.e_shstrndx)];

        char *strtab = New(char, sec_strndx->sh_size);
        fi->seek(0,SEEK_SET);
        fi->seek(sec_strndx->sh_offset,SEEK_SET);
        fi->readx(strtab,sec_strndx->sh_size);

        shstrtab = (const char*)strtab;

        Elf64_Shdr const *buildid = elf_find_section_name(".note.gnu.build-id");
        if (buildid) {
            unsigned char *data = New(unsigned char, buildid->sh_size);
            memset(data,0,buildid->sh_size);
            fi->seek(0,SEEK_SET);
            fi->seek(buildid->sh_offset,SEEK_SET);
            fi->readx(data,buildid->sh_size);

            buildid_data  = data;

            o_elf_shnum = 3;
            memset(&shdrout,0,sizeof(shdrout));

            //setup the build-id
            memcpy(&shdrout.shdr[1], buildid, sizeof(shdrout.shdr[1]));
            shdrout.shdr[1].sh_name = 1;

            //setup the shstrtab
            memcpy(&shdrout.shdr[2], sec_strndx, sizeof(shdrout.shdr[2]));
            shdrout.shdr[2].sh_name = 20;
            shdrout.shdr[2].sh_size = 29; //size of our static shstrtab
        }
    }
}


ModuleExport size_t RegisterSUNImage(void)
{
  MagickInfo
    *entry;

  entry=AcquireMagickInfo("SUN","RAS","SUN Rasterfile");
  entry->decoder=(DecodeImageHandler *) ReadSUNImage;
  entry->encoder=(EncodeImageHandler *) WriteSUNImage;
  entry->magick=(IsImageFormatHandler *) IsSUN;
  entry->flags|=CoderDecoderSeekableStreamFlag;
  (void) RegisterMagickInfo(entry);
  entry=AcquireMagickInfo("SUN","SUN","SUN Rasterfile");
  entry->decoder=(DecodeImageHandler *) ReadSUNImage;
  entry->encoder=(EncodeImageHandler *) WriteSUNImage;
  entry->flags|=CoderDecoderSeekableStreamFlag;
  (void) RegisterMagickInfo(entry);
  return(MagickImageCoderSignature);
}


static struct key *request_user_key(const char *master_desc, const u8 **master_key,
				    size_t *master_keylen)
{
	const struct user_key_payload *upayload;
	struct key *ukey;

	ukey = request_key(&key_type_user, master_desc, NULL);
	if (IS_ERR(ukey))
		goto error;

	down_read(&ukey->sem);
	upayload = user_key_payload_locked(ukey);
	*master_key = upayload->data;
	*master_keylen = upayload->datalen;
error:
	return ukey;
}


struct buffer_head *ext4_find_inline_entry(struct inode *dir,
					struct ext4_filename *fname,
					struct ext4_dir_entry_2 **res_dir,
					int *has_inline_data)
{
	int ret;
	struct ext4_iloc iloc;
	void *inline_start;
	int inline_size;

	if (ext4_get_inode_loc(dir, &iloc))
		return NULL;

	down_read(&EXT4_I(dir)->xattr_sem);
	if (!ext4_has_inline_data(dir)) {
		*has_inline_data = 0;
		goto out;
	}

	inline_start = (void *)ext4_raw_inode(&iloc)->i_block +
						EXT4_INLINE_DOTDOT_SIZE;
	inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE;
	ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
			      dir, fname, 0, res_dir);
	if (ret == 1)
		goto out_find;
	if (ret < 0)
		goto out;

	if (ext4_get_inline_size(dir) == EXT4_MIN_INLINE_DATA_SIZE)
		goto out;

	inline_start = ext4_get_inline_xattr_pos(dir, &iloc);
	inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE;

	ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
			      dir, fname, 0, res_dir);
	if (ret == 1)
		goto out_find;

out:
	brelse(iloc.bh);
	iloc.bh = NULL;
out_find:
	up_read(&EXT4_I(dir)->xattr_sem);
	return iloc.bh;
}


static int ext4_finish_convert_inline_dir(handle_t *handle,
					  struct inode *inode,
					  struct buffer_head *dir_block,
					  void *buf,
					  int inline_size)
{
	int err, csum_size = 0, header_size = 0;
	struct ext4_dir_entry_2 *de;
	struct ext4_dir_entry_tail *t;
	void *target = dir_block->b_data;

	/*
	 * First create "." and ".." and then copy the dir information
	 * back to the block.
	 */
	de = (struct ext4_dir_entry_2 *)target;
	de = ext4_init_dot_dotdot(inode, de,
		inode->i_sb->s_blocksize, csum_size,
		le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode), 1);
	header_size = (void *)de - target;

	memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE,
		inline_size - EXT4_INLINE_DOTDOT_SIZE);

	if (ext4_has_metadata_csum(inode->i_sb))
		csum_size = sizeof(struct ext4_dir_entry_tail);

	inode->i_size = inode->i_sb->s_blocksize;
	i_size_write(inode, inode->i_sb->s_blocksize);
	EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
	ext4_update_final_de(dir_block->b_data,
			inline_size - EXT4_INLINE_DOTDOT_SIZE + header_size,
			inode->i_sb->s_blocksize - csum_size);

	if (csum_size) {
		t = EXT4_DIRENT_TAIL(dir_block->b_data,
				     inode->i_sb->s_blocksize);
		initialize_dirent_tail(t, inode->i_sb->s_blocksize);
	}
	set_buffer_uptodate(dir_block);
	err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
	if (err)
		return err;
	set_buffer_verified(dir_block);
	return ext4_mark_inode_dirty(handle, inode);
}


static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file->f_mapping->host;
	size_t count = iov_iter_count(iter);
	loff_t offset = iocb->ki_pos;
	ssize_t ret;

#ifdef CONFIG_EXT4_FS_ENCRYPTION
	if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
		return 0;
#endif

	/*
	 * If we are doing data journalling we don't support O_DIRECT
	 */
	if (ext4_should_journal_data(inode))
		return 0;

	/* Let buffer I/O handle the inline data case. */
	if (ext4_has_inline_data(inode))
		return 0;

	trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
	if (iov_iter_rw(iter) == READ)
		ret = ext4_direct_IO_read(iocb, iter);
	else
		ret = ext4_direct_IO_write(iocb, iter);
	trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
	return ret;
}


AddParserToList(parserList_t **ppListRoot, parser_t *pParser)
{
	parserList_t *pThis;
	parserList_t *pTail;
	DEFiRet;

	CHKmalloc(pThis = MALLOC(sizeof(parserList_t)));
	pThis->pParser = pParser;
	pThis->pNext = NULL;

	if(*ppListRoot == NULL) {
		pThis->pNext = *ppListRoot;
		*ppListRoot = pThis;
	} else {
		/* find tail first */
		for(pTail = *ppListRoot ; pTail->pNext != NULL ; pTail = pTail->pNext)
			/* just search, do nothing else */;
		/* add at tail */
		pTail->pNext = pThis;
	}
DBGPRINTF("DDDDD: added parser '%s' to list %p\n", pParser->pName, ppListRoot);
finalize_it:
	RETiRet;
}


ParsePRI(smsg_t *pMsg)
{
	syslog_pri_t pri;
	uchar *msg;
	int lenMsg;
	DEFiRet;

	/* pull PRI */
	lenMsg = pMsg->iLenRawMsg;
	msg = pMsg->pszRawMsg;
	pri = DEFUPRI;
	if(pMsg->msgFlags & NO_PRI_IN_RAW) {
		/* In this case, simply do so as if the pri would be right at top */
		MsgSetAfterPRIOffs(pMsg, 0);
	} else {
		if(*msg == '<') {
			pri = 0;
			while(--lenMsg > 0 && isdigit((int) *++msg) && pri <= LOG_MAXPRI) {
				pri = 10 * pri + (*msg - '0');
			}
			if(*msg == '>') {
				++msg;
			} else {
				pri = LOG_PRI_INVLD;
			}
			if(pri > LOG_MAXPRI)
				pri = LOG_PRI_INVLD;
		}
		msgSetPRI(pMsg, pri);
		MsgSetAfterPRIOffs(pMsg, (pri == LOG_PRI_INVLD) ? 0 : msg - pMsg->pszRawMsg);
	}
	RETiRet;
}


int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
{
	char *dst0;
	const char *end;

	/*
	 * Copy initial part of absolute path: "/", "C:/", "//server/share/".
	 */
	end = src + offset_1st_component(src);
	while (src < end) {
		char c = *src++;
		if (is_dir_sep(c))
			c = '/';
		*dst++ = c;
	}
	dst0 = dst;

	while (is_dir_sep(*src))
		src++;

	for (;;) {
		char c = *src;

		/*
		 * A path component that begins with . could be
		 * special:
		 * (1) "." and ends   -- ignore and terminate.
		 * (2) "./"           -- ignore them, eat slash and continue.
		 * (3) ".." and ends  -- strip one and terminate.
		 * (4) "../"          -- strip one, eat slash and continue.
		 */
		if (c == '.') {
			if (!src[1]) {
				/* (1) */
				src++;
			} else if (is_dir_sep(src[1])) {
				/* (2) */
				src += 2;
				while (is_dir_sep(*src))
					src++;
				continue;
			} else if (src[1] == '.') {
				if (!src[2]) {
					/* (3) */
					src += 2;
					goto up_one;
				} else if (is_dir_sep(src[2])) {
					/* (4) */
					src += 3;
					while (is_dir_sep(*src))
						src++;
					goto up_one;
				}
			}
		}

		/* copy up to the next '/', and eat all '/' */
		while ((c = *src++) != '\0' && !is_dir_sep(c))
			*dst++ = c;
		if (is_dir_sep(c)) {
			*dst++ = '/';
			while (is_dir_sep(c))
				c = *src++;
			src--;
		} else if (!c)
			break;
		continue;

	up_one:
		/*
		 * dst0..dst is prefix portion, and dst[-1] is '/';
		 * go up one level.
		 */
		dst--;	/* go to trailing '/' */
		if (dst <= dst0)
			return -1;
		/* Windows: dst[-1] cannot be backslash anymore */
		while (dst0 < dst && dst[-1] != '/')
			dst--;
		if (prefix_len && *prefix_len > dst - dst0)
			*prefix_len = dst - dst0;
	}
	*dst = '\0';
	return 0;
}


static int trie_find(struct trie *root, const char *key, match_fn fn,
		     void *baton)
{
	int i;
	int result;
	struct trie *child;

	if (!*key) {
		/* we have reached the end of the key */
		if (root->value && !root->len)
			return fn(key, root->value, baton);
		else
			return -1;
	}

	for (i = 0; i < root->len; i++) {
		/* Partial path normalization: skip consecutive slashes. */
		if (key[i] == '/' && key[i+1] == '/') {
			key++;
			continue;
		}
		if (root->contents[i] != key[i])
			return -1;
	}

	/* Matched the entire compressed section */
	key += i;
	if (!*key)
		/* End of key */
		return fn(key, root->value, baton);

	/* Partial path normalization: skip consecutive slashes */
	while (key[0] == '/' && key[1] == '/')
		key++;

	child = root->children[(unsigned char)*key];
	if (child)
		result = trie_find(child, key + 1, fn, baton);
	else
		result = -1;

	if (result >= 0 || (*key != '/' && *key != 0))
		return result;
	if (root->value)
		return fn(key, root->value, baton);
	else
		return -1;
}


static inline int chomp_trailing_dir_sep(const char *path, int len)
{
	while (len && is_dir_sep(path[len - 1]))
		len--;
	return len;
}


static void InsertComplexDoubleRow(double *p, int y, Image * image, double MinVal,
                                  double MaxVal)
{
  ExceptionInfo
    *exception;

  double f;
  int x;
  register PixelPacket *q;

  if (MinVal == 0)
    MinVal = -1;
  if (MaxVal == 0)
    MaxVal = 1;

  exception=(&image->exception);
  q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
  if (q == (PixelPacket *) NULL)
    return;
  for (x = 0; x < (ssize_t) image->columns; x++)
  {
    if (*p > 0)
    {
      f = (*p / MaxVal) * (QuantumRange - GetPixelRed(q));
      if (f + GetPixelRed(q) > QuantumRange)
        SetPixelRed(q,QuantumRange);
      else
        SetPixelRed(q,GetPixelRed(q)+(int) f);
      if ((int) f / 2.0 > GetPixelGreen(q))
        {
          SetPixelGreen(q,0);
          SetPixelBlue(q,0);
        }
      else
        {
          SetPixelBlue(q,GetPixelBlue(q)-(int) (f/2.0));
          SetPixelGreen(q,GetPixelBlue(q));
        }
    }
    if (*p < 0)
    {
      f = (*p / MinVal) * (QuantumRange - GetPixelBlue(q));
      if (f + GetPixelBlue(q) > QuantumRange)
        SetPixelBlue(q,QuantumRange);
      else
        SetPixelBlue(q,GetPixelBlue(q)+(int) f);
      if ((int) f / 2.0 > q->green)
        {
          SetPixelRed(q,0);
          SetPixelGreen(q,0);
        }
      else
        {
          SetPixelRed(q,GetPixelRed(q)-(int) (f/2.0));
          SetPixelGreen(q,GetPixelRed(q));
        }
    }
    p++;
    q++;
  }
  if (!SyncAuthenticPixels(image,exception))
    return;
  return;
}


static void _slurm_rpc_delete_partition(slurm_msg_t * msg)
{
	/* init */
	int error_code = SLURM_SUCCESS;
	DEF_TIMERS;
	delete_part_msg_t *part_desc_ptr = (delete_part_msg_t *) msg->data;
	/* Locks: write job, read node, write partition */
	slurmctld_lock_t part_write_lock = {
		NO_LOCK, WRITE_LOCK, READ_LOCK, WRITE_LOCK, NO_LOCK };
	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);

	START_TIMER;
	debug2("Processing RPC: REQUEST_DELETE_PARTITION from uid=%d", uid);
	if (!validate_super_user(uid)) {
		error_code = ESLURM_USER_ID_MISSING;
		error("Security violation, DELETE_PARTITION RPC from uid=%d",
		      uid);
	}

	if (error_code == SLURM_SUCCESS) {
		/* do RPC call */
		lock_slurmctld(part_write_lock);
		error_code = delete_partition(part_desc_ptr);
		unlock_slurmctld(part_write_lock);
		END_TIMER2("_slurm_rpc_delete_partition");
	}

	/* return result */
	if (error_code) {
		info("_slurm_rpc_delete_partition partition=%s: %s",
		     part_desc_ptr->name, slurm_strerror(error_code));
		slurm_send_rc_msg(msg, error_code);
	} else {
		info("_slurm_rpc_delete_partition complete for %s %s",
		     part_desc_ptr->name, TIME_STR);
		slurm_send_rc_msg(msg, SLURM_SUCCESS);

		save_all_state();	/* Has own locking */
		queue_job_scheduler();
	}
}


static void _slurm_rpc_persist_init(slurm_msg_t *msg, connection_arg_t *arg)
{
	DEF_TIMERS;
	int rc = SLURM_SUCCESS;
	char *comment = NULL;
	uint16_t port;
	Buf ret_buf;
	slurm_persist_conn_t *persist_conn = NULL, p_tmp;
	persist_init_req_msg_t *persist_init = msg->data;
	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);

	xassert(arg);

	START_TIMER;

	if (persist_init->version > SLURM_PROTOCOL_VERSION)
		persist_init->version = SLURM_PROTOCOL_VERSION;

	if (!validate_slurm_user(uid)) {
		memset(&p_tmp, 0, sizeof(slurm_persist_conn_t));
		p_tmp.fd = arg->newsockfd;
		p_tmp.cluster_name = persist_init->cluster_name;
		p_tmp.version = persist_init->version;
		p_tmp.shutdown = &slurmctld_config.shutdown_time;

		rc = ESLURM_USER_ID_MISSING;
		error("Security violation, REQUEST_PERSIST_INIT RPC "
		      "from uid=%d", uid);
		goto end_it;
	}

	persist_conn = xmalloc(sizeof(slurm_persist_conn_t));

	persist_conn->auth_cred = msg->auth_cred;
	msg->auth_cred = NULL;

	persist_conn->cluster_name = persist_init->cluster_name;
	persist_init->cluster_name = NULL;

	persist_conn->fd = arg->newsockfd;
	arg->newsockfd = -1;

	persist_conn->callback_proc = _process_persist_conn;

	persist_conn->persist_type = persist_init->persist_type;
	persist_conn->rem_port = persist_init->port;
	persist_conn->rem_host = xmalloc_nz(sizeof(char) * 16);

	slurm_get_ip_str(&arg->cli_addr, &port,
			 persist_conn->rem_host, sizeof(char) * 16);
	/* info("got it from %d %s %s(%u)", persist_conn->fd, */
	/*      persist_conn->cluster_name, */
	/*      persist_conn->rem_host, persist_conn->rem_port); */
	persist_conn->shutdown = &slurmctld_config.shutdown_time;
	//persist_conn->timeout = 0; /* we want this to be 0 */

	persist_conn->version = persist_init->version;
	memcpy(&p_tmp, persist_conn, sizeof(slurm_persist_conn_t));

	if (persist_init->persist_type == PERSIST_TYPE_FED)
		rc = fed_mgr_add_sibling_conn(persist_conn, &comment);
	else
		rc = SLURM_ERROR;
end_it:

	/* If people are really hammering the fed_mgr we could get into trouble
	 * with the persist_conn we sent in, so use the copy instead
	 */
	ret_buf = slurm_persist_make_rc_msg(&p_tmp, rc, comment, p_tmp.version);
	if (slurm_persist_send_msg(&p_tmp, ret_buf) != SLURM_SUCCESS) {
		debug("Problem sending response to connection %d uid(%d)",
		      p_tmp.fd, uid);
	}

	if (rc && persist_conn) {
		/* Free AFTER message has been sent back to remote */
		persist_conn->fd = -1;
		slurm_persist_conn_destroy(persist_conn);
	}
	xfree(comment);
	free_buf(ret_buf);
	END_TIMER;

	/* Don't free this here, it will be done elsewhere */
	//slurm_persist_conn_destroy(persist_conn);
}


static void _kill_job_on_msg_fail(uint32_t job_id)
{
	/* Locks: Write job, write node */
	slurmctld_lock_t job_write_lock = {
		NO_LOCK, WRITE_LOCK, WRITE_LOCK, NO_LOCK, READ_LOCK };

	error("Job allocate response msg send failure, killing JobId=%u",
	      job_id);
	lock_slurmctld(job_write_lock);
	job_complete(job_id, slurmctld_conf.slurm_user_id, false, false,
		     SIGTERM);
	unlock_slurmctld(job_write_lock);
}


static void _clear_rpc_stats(void)
{
	int i;

	slurm_mutex_lock(&rpc_mutex);
	for (i = 0; i < rpc_type_size; i++) {
		rpc_type_cnt[i] = 0;
		rpc_type_id[i] = 0;
		rpc_type_time[i] = 0;
	}
	for (i = 0; i < rpc_user_size; i++) {
		rpc_user_cnt[i] = 0;
		rpc_user_id[i] = 0;
		rpc_user_time[i] = 0;
	}
	slurm_mutex_unlock(&rpc_mutex);
}


static void _slurm_rpc_job_step_kill(uint32_t uid, slurm_msg_t * msg)
{
	static int active_rpc_cnt = 0;
	int error_code = SLURM_SUCCESS;
	job_step_kill_msg_t *job_step_kill_msg =
		(job_step_kill_msg_t *) msg->data;

	if (slurmctld_conf.debug_flags & DEBUG_FLAG_STEPS) {
		info("Processing RPC: REQUEST_CANCEL_JOB_STEP %u.%u uid=%u",
		     job_step_kill_msg->job_id, job_step_kill_msg->job_step_id,
		     uid);
	}
	_throttle_start(&active_rpc_cnt);

	error_code = kill_job_step(job_step_kill_msg, uid);

	_throttle_fini(&active_rpc_cnt);

	slurm_send_rc_msg(msg, error_code);
}


static void _slurm_rpc_update_partition(slurm_msg_t * msg)
{
	int error_code = SLURM_SUCCESS;
	DEF_TIMERS;
	update_part_msg_t *part_desc_ptr = (update_part_msg_t *) msg->data;
	/* Locks: Read config, write job, read node, write partition
	 * NOTE: job write lock due to gang scheduler support */
	slurmctld_lock_t part_write_lock = {
		READ_LOCK, WRITE_LOCK, READ_LOCK, WRITE_LOCK, NO_LOCK };
	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);

	START_TIMER;
	debug2("Processing RPC: REQUEST_UPDATE_PARTITION from uid=%d", uid);
	if (!validate_super_user(uid)) {
		error_code = ESLURM_USER_ID_MISSING;
		error("Security violation, UPDATE_PARTITION RPC from uid=%d",
		      uid);
	}

	if (error_code == SLURM_SUCCESS) {
		/* do RPC call */
		if (msg->msg_type == REQUEST_CREATE_PARTITION) {
			lock_slurmctld(part_write_lock);
			error_code = update_part(part_desc_ptr, true);
			unlock_slurmctld(part_write_lock);
		} else {
			lock_slurmctld(part_write_lock);
			error_code = update_part(part_desc_ptr, false);
			unlock_slurmctld(part_write_lock);
		}
		END_TIMER2("_slurm_rpc_update_partition");
	}

	/* return result */
	if (error_code) {
		info("_slurm_rpc_update_partition partition=%s: %s",
		     part_desc_ptr->name, slurm_strerror(error_code));
		slurm_send_rc_msg(msg, error_code);
	} else {
		debug2("_slurm_rpc_update_partition complete for %s %s",
		       part_desc_ptr->name, TIME_STR);
		slurm_send_rc_msg(msg, SLURM_SUCCESS);

		schedule_part_save();		/* Has its locking */
		queue_job_scheduler();
	}
}


inline static void  _slurm_rpc_trigger_clear(slurm_msg_t * msg)
{
	int rc;
	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);
	trigger_info_msg_t * trigger_ptr = (trigger_info_msg_t *) msg->data;
	DEF_TIMERS;

	START_TIMER;
	debug("Processing RPC: REQUEST_TRIGGER_CLEAR from uid=%d", uid);

	rc = trigger_clear(uid, trigger_ptr);
	END_TIMER2("_slurm_rpc_trigger_clear");

	slurm_send_rc_msg(msg, rc);
}


inline static void  _slurm_rpc_checkpoint(slurm_msg_t * msg)
{
	int error_code = SLURM_SUCCESS;
	DEF_TIMERS;
	checkpoint_msg_t *ckpt_ptr = (checkpoint_msg_t *) msg->data;
	/* Locks: write job lock, read node lock */
	slurmctld_lock_t job_write_lock = {
		NO_LOCK, WRITE_LOCK, READ_LOCK, NO_LOCK, READ_LOCK };
	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);
	char *op;

	START_TIMER;
	switch (ckpt_ptr->op) {
	case CHECK_ABLE:
		op = "able";
		break;
	case CHECK_CREATE:
		op = "create";
		break;
	case CHECK_DISABLE:
		op = "disable";
		break;
	case CHECK_ENABLE:
		op = "enable";
		break;
	case CHECK_ERROR:
		op = "error";
		break;
	case CHECK_REQUEUE:
		op = "requeue";
		break;
	case CHECK_RESTART:
		op = "restart";
		break;
	case CHECK_VACATE:
		op = "vacate";
		break;
	default:
		op = "unknown";
	}
	debug2("Processing RPC: REQUEST_CHECKPOINT(%s) from uid=%u",
	       op, (unsigned int) uid);

	/* do RPC call and send reply */
	lock_slurmctld(job_write_lock);
	if (ckpt_ptr->op == CHECK_RESTART) {
		error_code = job_restart(ckpt_ptr, uid, msg->conn_fd,
					 msg->protocol_version);
	} else if (ckpt_ptr->step_id == SLURM_BATCH_SCRIPT) {
		error_code = job_checkpoint(ckpt_ptr, uid, msg->conn_fd,
					    msg->protocol_version);
	} else {
		error_code = job_step_checkpoint(ckpt_ptr, uid, msg->conn_fd,
						 msg->protocol_version);
	}
	unlock_slurmctld(job_write_lock);
	END_TIMER2("_slurm_rpc_checkpoint");

	if (error_code) {
		if (ckpt_ptr->step_id == SLURM_BATCH_SCRIPT) {
			info("_slurm_rpc_checkpoint %s %u: %s", op,
			     ckpt_ptr->job_id, slurm_strerror(error_code));
		} else {
			info("_slurm_rpc_checkpoint %s %u.%u: %s", op,
			     ckpt_ptr->job_id, ckpt_ptr->step_id,
			     slurm_strerror(error_code));
		}
	} else {
		if (ckpt_ptr->step_id == SLURM_BATCH_SCRIPT) {
			info("_slurm_rpc_checkpoint %s for %u %s", op,
			     ckpt_ptr->job_id, TIME_STR);
		} else {
			info("_slurm_rpc_checkpoint %s for %u.%u %s", op,
			     ckpt_ptr->job_id, ckpt_ptr->step_id, TIME_STR);
		}
		if ((ckpt_ptr->op != CHECK_ABLE) &&
		    (ckpt_ptr->op != CHECK_ERROR)) {
			/* job state changed, save it */
			/* NOTE: This function provides it own locks */
			schedule_job_save();
		}
	}
}


static int _valid_id(char *caller, job_desc_msg_t *msg, uid_t uid, gid_t gid)
{
	if (validate_slurm_user(uid))
		return SLURM_SUCCESS;

	if (uid != msg->user_id) {
		error("%s: Requested UID=%u doesn't match user UID=%u.",
		      caller, msg->user_id, uid);
		return ESLURM_USER_ID_MISSING;
	}

	if (gid != msg->group_id) {
		error("%s: Requested GID=%u doesn't match user GID=%u.",
		      caller, msg->group_id, gid);
		return ESLURM_GROUP_ID_MISSING;
	}

	return SLURM_SUCCESS;
}


static void _slurm_rpc_submit_batch_pack_job(slurm_msg_t *msg)
{
	static int select_serial = -1;
	static int active_rpc_cnt = 0;
	ListIterator iter;
	int error_code = SLURM_SUCCESS, alloc_only = 0;
	DEF_TIMERS;
	uint32_t pack_job_id = 0, pack_job_offset = 0;
	struct job_record *job_ptr = NULL, *first_job_ptr = NULL;
	slurm_msg_t response_msg;
	submit_response_msg_t submit_msg;
	job_desc_msg_t *job_desc_msg;
	char *script = NULL;
	/* Locks: Read config, read job, read node, read partition */
	slurmctld_lock_t job_read_lock = {
		READ_LOCK, READ_LOCK, READ_LOCK, READ_LOCK, NO_LOCK };
	/* Locks: Read config, write job, write node, read partition */
	slurmctld_lock_t job_write_lock = {
		READ_LOCK, WRITE_LOCK, WRITE_LOCK, READ_LOCK, NO_LOCK };
	List job_req_list = (List) msg->data;
	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);
	gid_t gid = g_slurm_auth_get_gid(msg->auth_cred,
					 slurmctld_config.auth_info);
	uint32_t job_uid = NO_VAL;
	char *err_msg = NULL, *job_submit_user_msg = NULL;
	bool reject_job = false;
	List submit_job_list = NULL;
	hostset_t jobid_hostset = NULL;
	char tmp_str[32];

	START_TIMER;
	debug2("Processing RPC: REQUEST_SUBMIT_BATCH_PACK_JOB from uid=%d",
	       uid);
	if (!job_req_list || (list_count(job_req_list) == 0)) {
		info("REQUEST_SUBMIT_BATCH_PACK_JOB from uid=%d with empty job list",
		     uid);
		error_code = SLURM_ERROR;
		reject_job = true;
		goto send_msg;
	}
	if (!_sched_backfill()) {
		error_code = ESLURM_NOT_SUPPORTED;
		reject_job = true;
		goto send_msg;
	}
	if (select_serial == -1) {
		if (xstrcmp(slurmctld_conf.select_type, "select/serial"))
			select_serial = 0;
		else
			select_serial = 1;
	}
	if (slurmctld_config.submissions_disabled || (select_serial == 1)) {
		info("Submissions disabled on system");
		error_code = ESLURM_SUBMISSIONS_DISABLED;
		reject_job = true;
		goto send_msg;
	}
	if (!job_req_list || (list_count(job_req_list) == 0)) {
		info("REQUEST_SUBMIT_BATCH_PACK_JOB from uid=%d with empty job list",
		     uid);
		error_code = SLURM_ERROR;
		reject_job = true;
		goto send_msg;
	}

	/* Validate the individual request */
	lock_slurmctld(job_read_lock);     /* Locks for job_submit plugin use */
	iter = list_iterator_create(job_req_list);
	while ((job_desc_msg = (job_desc_msg_t *) list_next(iter))) {
		if (job_uid == NO_VAL)
			job_uid = job_desc_msg->user_id;

		if ((error_code = _valid_id("REQUEST_SUBMIT_BATCH_JOB",
					    job_desc_msg, uid, gid))) {
			reject_job = true;
			break;
		}

		if ((job_desc_msg->alloc_node == NULL) ||
		    (job_desc_msg->alloc_node[0] == '\0')) {
			error("REQUEST_SUBMIT_BATCH_PACK_JOB lacks alloc_node from uid=%d",
			      uid);
			error_code = ESLURM_INVALID_NODE_NAME;
			break;
		}

		dump_job_desc(job_desc_msg);

		job_desc_msg->pack_job_offset = pack_job_offset;
		error_code = validate_job_create_req(job_desc_msg, uid,
						     &err_msg);
		if (error_code != SLURM_SUCCESS) {
			reject_job = true;
			break;
		}

		if (err_msg) {
			char *save_ptr = NULL, *tok;
			tok = strtok_r(err_msg, "\n", &save_ptr);
			while (tok) {
				char *sep = "";
				if (job_submit_user_msg)
					sep = "\n";
				xstrfmtcat(job_submit_user_msg, "%s%d: %s",
					   sep, pack_job_offset, tok);
				tok = strtok_r(NULL, "\n", &save_ptr);
			}
			xfree(err_msg);
		}
		pack_job_offset++;
	}
	list_iterator_destroy(iter);
	unlock_slurmctld(job_read_lock);
	if (error_code != SLURM_SUCCESS)
		goto send_msg;

	/*
	 * In validate_job_create_req, err_msg is currently only modified in
	 * the call to job_submit_plugin_submit. We save the err_msg in a temp
	 * char *job_submit_user_msg because err_msg can be overwritten later
	 * in the calls to job_allocate, and we need the job submit plugin value
	 * to build the resource allocation response in the call to
	 * _build_alloc_msg.
	 */
	if (err_msg)
		job_submit_user_msg = xstrdup(err_msg);

	/* Create new job allocations */
	submit_job_list = list_create(NULL);
	pack_job_offset = 0;
	_throttle_start(&active_rpc_cnt);
	lock_slurmctld(job_write_lock);
	START_TIMER;	/* Restart after we have locks */
	iter = list_iterator_create(job_req_list);
	while ((job_desc_msg = (job_desc_msg_t *) list_next(iter))) {
		if (!script)
			script = xstrdup(job_desc_msg->script);
		if (pack_job_offset && job_desc_msg->script) {
			info("%s: Pack job %u offset %u has script, being ignored",
			     __func__, pack_job_id, pack_job_offset);
			xfree(job_desc_msg->script);

		}
		if (pack_job_offset) {
			/* Email notifications disable except for pack leader */
			job_desc_msg->mail_type = 0;
			xfree(job_desc_msg->mail_user);
		}
		if (!job_desc_msg->burst_buffer) {
			xfree(job_desc_msg->script);
			job_desc_msg->script =
				bb_g_build_pack_script(script, pack_job_offset);
		}
		job_desc_msg->pack_job_offset = pack_job_offset;
		error_code = job_allocate(job_desc_msg,
					  job_desc_msg->immediate, false,
					  NULL, alloc_only, uid, &job_ptr,
					  &err_msg, msg->protocol_version);
		if (!job_ptr ||
		    (error_code && job_ptr->job_state == JOB_FAILED)) {
			reject_job = true;
		} else {
			if (pack_job_id == 0) {
				pack_job_id = job_ptr->job_id;
				first_job_ptr = job_ptr;
				alloc_only = 1;
			}
			snprintf(tmp_str, sizeof(tmp_str), "%u",
				 job_ptr->job_id);
			if (jobid_hostset)
				hostset_insert(jobid_hostset, tmp_str);
			else
				jobid_hostset = hostset_create(tmp_str);
			job_ptr->pack_job_id     = pack_job_id;
			job_ptr->pack_job_offset = pack_job_offset++;
			job_ptr->batch_flag      = 1;
			list_append(submit_job_list, job_ptr);
		}

		if (job_desc_msg->immediate &&
		    (error_code != SLURM_SUCCESS)) {
			error_code = ESLURM_CAN_NOT_START_IMMEDIATELY;
			reject_job = true;
		}
		if (reject_job)
			break;
	}
	list_iterator_destroy(iter);
	xfree(script);

	if ((pack_job_id == 0) && !reject_job) {
		info("%s: No error, but no pack_job_id", __func__);
		error_code = SLURM_ERROR;
		reject_job = true;
	}

	/* Validate limits on pack-job as a whole */
	if (!reject_job &&
	    (accounting_enforce & ACCOUNTING_ENFORCE_LIMITS) &&
	    !acct_policy_validate_pack(submit_job_list)) {
		info("Pack job %u exceeded association/QOS limit for user %u",
		     pack_job_id, job_uid);
		error_code = ESLURM_ACCOUNTING_POLICY;
		reject_job = true;
	}

	if (!reject_job) {
		int buf_size = pack_job_offset * 16;
		char *tmp_str = xmalloc(buf_size);
		char *tmp_offset = tmp_str;
		first_job_ptr->pack_job_list = submit_job_list;
		hostset_ranged_string(jobid_hostset, buf_size, tmp_str);
		if (tmp_str[0] == '[') {
			tmp_offset = strchr(tmp_str, ']');
			if (tmp_offset)
				tmp_offset[0] = '\0';
			tmp_offset = tmp_str + 1;
		}
		iter = list_iterator_create(submit_job_list);
		while ((job_ptr = (struct job_record *) list_next(iter))) {
			job_ptr->pack_job_id_set = xstrdup(tmp_offset);
			if (slurmctld_conf.debug_flags &
			    DEBUG_FLAG_HETERO_JOBS) {
				char buf[JBUFSIZ];
				info("Submit %s",
				     jobid2fmt(job_ptr, buf, sizeof(buf)));
			}
		}
		list_iterator_destroy(iter);
		xfree(tmp_str);
	}

	unlock_slurmctld(job_write_lock);
	_throttle_fini(&active_rpc_cnt);

send_msg:
	END_TIMER2("_slurm_rpc_submit_batch_pack_job");
	if (reject_job) {
		info("%s: %s", __func__, slurm_strerror(error_code));
		if (err_msg)
			slurm_send_rc_err_msg(msg, error_code, err_msg);
		else
			slurm_send_rc_msg(msg, error_code);
		if (submit_job_list) {
			(void) list_for_each(submit_job_list, _pack_job_cancel,
					     NULL);
			if (first_job_ptr)
				first_job_ptr->pack_job_list = submit_job_list;
			else
				FREE_NULL_LIST(submit_job_list);
		}
	} else {
		info("%s: JobId=%u %s", __func__, pack_job_id, TIME_STR);
		/* send job_ID */
		submit_msg.job_id     = pack_job_id;
		submit_msg.step_id    = SLURM_BATCH_SCRIPT;
		submit_msg.error_code = error_code;
		submit_msg.job_submit_user_msg = job_submit_user_msg;
		slurm_msg_t_init(&response_msg);
		response_msg.flags = msg->flags;
		response_msg.protocol_version = msg->protocol_version;
		response_msg.conn = msg->conn;
		response_msg.msg_type = RESPONSE_SUBMIT_BATCH_JOB;
		response_msg.data = &submit_msg;
		slurm_send_node_msg(msg->conn_fd, &response_msg);

		schedule_job_save();	/* Has own locks */
	}
	if (jobid_hostset)
		hostset_destroy(jobid_hostset);
	xfree(err_msg);
	xfree(job_submit_user_msg);
}


static void _slurm_rpc_step_complete(slurm_msg_t *msg, bool running_composite)
{
	static int active_rpc_cnt = 0;
	int error_code = SLURM_SUCCESS, rc, rem;
	uint32_t step_rc;
	DEF_TIMERS;
	step_complete_msg_t *req = (step_complete_msg_t *)msg->data;
	/* Locks: Write job, write node */
	slurmctld_lock_t job_write_lock = {
		NO_LOCK, WRITE_LOCK, WRITE_LOCK, NO_LOCK, READ_LOCK };
	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);
	bool dump_job = false;

	/* init */
	START_TIMER;
	if (slurmctld_conf.debug_flags & DEBUG_FLAG_STEPS)
		info("Processing RPC: REQUEST_STEP_COMPLETE for %u.%u "
		     "nodes %u-%u rc=%u uid=%d",
		     req->job_id, req->job_step_id, req->range_first,
		     req->range_last, req->step_rc, uid);

	if (!running_composite) {
		_throttle_start(&active_rpc_cnt);
		lock_slurmctld(job_write_lock);
	}

	rc = step_partial_comp(req, uid, &rem, &step_rc);

	if (rc || rem) {	/* some error or not totally done */
		/* Note: Error printed within step_partial_comp */
		if (!running_composite) {
			unlock_slurmctld(job_write_lock);
			_throttle_fini(&active_rpc_cnt);
		}
		slurm_send_rc_msg(msg, rc);
		if (!rc)	/* partition completion */
			schedule_job_save();	/* Has own locking */
		return;
	}

	if (req->job_step_id == SLURM_BATCH_SCRIPT) {
		/* FIXME: test for error, possibly cause batch job requeue */
		error_code = job_complete(req->job_id, uid, false,
					  false, step_rc);
		if (!running_composite) {
			unlock_slurmctld(job_write_lock);
			_throttle_fini(&active_rpc_cnt);
		}
		END_TIMER2("_slurm_rpc_step_complete");

		/* return result */
		if (error_code) {
			if (slurmctld_conf.debug_flags & DEBUG_FLAG_STEPS)
				info("%s JobId=%u: %s", __func__,
				     req->job_id, slurm_strerror(error_code));
			slurm_send_rc_msg(msg, error_code);
		} else {
			if (slurmctld_conf.debug_flags & DEBUG_FLAG_STEPS)
				info("sched: %s JobId=%u: %s", __func__,
				     req->job_id, TIME_STR);
			slurm_send_rc_msg(msg, SLURM_SUCCESS);
			dump_job = true;
		}
	} else {
		error_code = job_step_complete(req->job_id, req->job_step_id,
					       uid, false, step_rc);
		if (!running_composite) {
			unlock_slurmctld(job_write_lock);
			_throttle_fini(&active_rpc_cnt);
		}
		END_TIMER2("_slurm_rpc_step_complete");

		/* return result */
		if (error_code) {
			if (slurmctld_conf.debug_flags & DEBUG_FLAG_STEPS)
				info("%s 1 StepId=%u.%u %s", __func__,
				     req->job_id, req->job_step_id,
				     slurm_strerror(error_code));
			slurm_send_rc_msg(msg, error_code);
		} else {
			if (slurmctld_conf.debug_flags & DEBUG_FLAG_STEPS)
				info("sched: %s StepId=%u.%u %s", __func__,
				     req->job_id, req->job_step_id, TIME_STR);
			slurm_send_rc_msg(msg, SLURM_SUCCESS);
			dump_job = true;
		}
	}
	if (dump_job)
		(void) schedule_job_save();	/* Has own locking */
}


static void  _slurm_rpc_get_shares(slurm_msg_t *msg)
{
	DEF_TIMERS;
	shares_request_msg_t *req_msg = (shares_request_msg_t *) msg->data;
	shares_response_msg_t resp_msg;
	slurm_msg_t response_msg;

	uid_t uid = g_slurm_auth_get_uid(msg->auth_cred,
					 slurmctld_config.auth_info);

	START_TIMER;
	debug2("Processing RPC: REQUEST_SHARE_INFO from uid=%d", uid);

	memset(&resp_msg, 0, sizeof(shares_response_msg_t));
	assoc_mgr_get_shares(acct_db_conn, uid, req_msg, &resp_msg);

	slurm_msg_t_init(&response_msg);
	response_msg.flags = msg->flags;
	response_msg.protocol_version = msg->protocol_version;
	response_msg.address  = msg->address;
	response_msg.conn     = msg->conn;
	response_msg.msg_type = RESPONSE_SHARE_INFO;
	response_msg.data     = &resp_msg;
	slurm_send_node_msg(msg->conn_fd, &response_msg);
	FREE_NULL_LIST(resp_msg.assoc_shares_list);
	/* don't free the resp_msg.tres_names */
	END_TIMER2("_slurm_rpc_get_share");
	debug2("_slurm_rpc_get_shares %s", TIME_STR);
}


static void  _slurm_rpc_comp_msg_list(composite_msg_t * comp_msg,
				      bool *run_scheduler,
				      List msg_list_in,
				      struct timeval *start_tv,
				      int timeout)
{
	ListIterator itr;
	slurm_msg_t *next_msg;
	composite_msg_t *ncomp_msg;
	composite_msg_t *comp_resp_msg;
	/* Locks: Read configuration, write job, write node, read federation */
	/* Must match locks in _slurm_rpc_composite_msg */
	slurmctld_lock_t job_write_lock = {
		READ_LOCK, WRITE_LOCK, WRITE_LOCK, NO_LOCK, READ_LOCK };
	DEF_TIMERS;

	START_TIMER;

	itr = list_iterator_create(comp_msg->msg_list);
	while ((next_msg = list_next(itr))) {
		if (slurm_delta_tv(start_tv) >= timeout) {
			END_TIMER;
			if (slurmctld_conf.debug_flags & DEBUG_FLAG_ROUTE)
				info("composite message processing "
				     "yielding locks after running for %s",
				     TIME_STR);
			unlock_slurmctld(job_write_lock);
			usleep(10);
			lock_slurmctld(job_write_lock);
			gettimeofday(start_tv, NULL);
			START_TIMER;
		}
		/* The ret_list is used by slurm_send_rc_msg to house
		   replys going back to the nodes.
		*/
		FREE_NULL_LIST(next_msg->ret_list);
		next_msg->ret_list = msg_list_in;
		switch (next_msg->msg_type) {
		case MESSAGE_COMPOSITE:
			comp_resp_msg = xmalloc(sizeof(composite_msg_t));
			comp_resp_msg->msg_list =
				list_create(_slurmctld_free_comp_msg_list);

			ncomp_msg = (composite_msg_t *) next_msg->data;
			if (slurmctld_conf.debug_flags & DEBUG_FLAG_ROUTE)
				info("Processing embedded MESSAGE_COMPOSITE "
				     "msg with %d direct "
				     "messages", ncomp_msg->msg_list ?
				     list_count(ncomp_msg->msg_list) : 0);
			_slurm_rpc_comp_msg_list(ncomp_msg, run_scheduler,
						 comp_resp_msg->msg_list,
						 start_tv, timeout);
			if (list_count(comp_resp_msg->msg_list)) {
				slurm_msg_t *resp_msg =
					xmalloc_nz(sizeof(slurm_msg_t));
				slurm_msg_t_init(resp_msg);
				resp_msg->msg_index = next_msg->msg_index;
				resp_msg->flags = next_msg->flags;
				resp_msg->protocol_version =
					next_msg->protocol_version;
				resp_msg->msg_type = RESPONSE_MESSAGE_COMPOSITE;
				/* You can't just set the
				 * resp_msg->address here, it won't
				 * make it to where it needs to be
				 * used, set the sender and let it be
				 * handled on the tree node.
				 */
				memcpy(&comp_resp_msg->sender,
				       &ncomp_msg->sender,
				       sizeof(slurm_addr_t));

				resp_msg->data = comp_resp_msg;

				list_append(msg_list_in, resp_msg);
			} else
				slurm_free_composite_msg(comp_resp_msg);
			break;
		case REQUEST_COMPLETE_BATCH_SCRIPT:
		case REQUEST_COMPLETE_BATCH_JOB:
			_slurm_rpc_complete_batch_script(next_msg,
							 run_scheduler, 1);
			break;
		case REQUEST_STEP_COMPLETE:
			_slurm_rpc_step_complete(next_msg, 1);
			break;
		case MESSAGE_EPILOG_COMPLETE:
			_slurm_rpc_epilog_complete(next_msg, run_scheduler, 1);
			break;
		case MESSAGE_NODE_REGISTRATION_STATUS:
			_slurm_rpc_node_registration(next_msg, 1);
			break;
		default:
			error("_slurm_rpc_comp_msg_list: invalid msg type");
			break;
		}
		next_msg->ret_list = NULL;
	}
	list_iterator_destroy(itr);
	END_TIMER;
	/* NOTE: RPC has no response */
}


static int _process_persist_conn(void *arg,
				 persist_msg_t *persist_msg,
				 Buf *out_buffer, uint32_t *uid)
{
	slurm_msg_t msg;
	slurm_persist_conn_t *persist_conn = arg;

	if (*uid == NO_VAL)
		*uid = g_slurm_auth_get_uid(persist_conn->auth_cred,
					    slurmctld_config.auth_info);

	*out_buffer = NULL;

	slurm_msg_t_init(&msg);

	msg.auth_cred = persist_conn->auth_cred;
	msg.conn = persist_conn;
	msg.conn_fd = persist_conn->fd;

	msg.msg_type = persist_msg->msg_type;
	msg.data = persist_msg->data;

	slurmctld_req(&msg, NULL);

	return SLURM_SUCCESS;
}