static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
	int r;
	bool req_int_win =
		dm_request_for_irq_injection(vcpu) &&
		kvm_cpu_accept_dm_intr(vcpu);

	bool req_immediate_exit = false;

	if (kvm_request_pending(vcpu)) {
		if (kvm_check_request(KVM_REQ_GET_VMCS12_PAGES, vcpu))
			kvm_x86_ops->get_vmcs12_pages(vcpu);
		if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu))
			kvm_mmu_unload(vcpu);
		if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
			__kvm_migrate_timers(vcpu);
		if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
			kvm_gen_update_masterclock(vcpu->kvm);
		if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu))
			kvm_gen_kvmclock_update(vcpu);
		if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
			r = kvm_guest_time_update(vcpu);
			if (unlikely(r))
				goto out;
		}
		if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu))
			kvm_mmu_sync_roots(vcpu);
		if (kvm_check_request(KVM_REQ_LOAD_CR3, vcpu))
			kvm_mmu_load_cr3(vcpu);
		if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
			kvm_vcpu_flush_tlb(vcpu, true);
		if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
			vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
			r = 0;
			goto out;
		}
		if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
			vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
			vcpu->mmio_needed = 0;
			r = 0;
			goto out;
		}
		if (kvm_check_request(KVM_REQ_APF_HALT, vcpu)) {
			/* Page is swapped out. Do synthetic halt */
			vcpu->arch.apf.halted = true;
			r = 1;
			goto out;
		}
		if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu))
			record_steal_time(vcpu);
		if (kvm_check_request(KVM_REQ_SMI, vcpu))
			process_smi(vcpu);
		if (kvm_check_request(KVM_REQ_NMI, vcpu))
			process_nmi(vcpu);
		if (kvm_check_request(KVM_REQ_PMU, vcpu))
			kvm_pmu_handle_event(vcpu);
		if (kvm_check_request(KVM_REQ_PMI, vcpu))
			kvm_pmu_deliver_pmi(vcpu);
		if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
			BUG_ON(vcpu->arch.pending_ioapic_eoi > 255);
			if (test_bit(vcpu->arch.pending_ioapic_eoi,
				     vcpu->arch.ioapic_handled_vectors)) {
				vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
				vcpu->run->eoi.vector =
						vcpu->arch.pending_ioapic_eoi;
				r = 0;
				goto out;
			}
		}
		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
			vcpu_scan_ioapic(vcpu);
		if (kvm_check_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu))
			vcpu_load_eoi_exitmap(vcpu);
		if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
			kvm_vcpu_reload_apic_access_page(vcpu);
		if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) {
			vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
			vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH;
			r = 0;
			goto out;
		}
		if (kvm_check_request(KVM_REQ_HV_RESET, vcpu)) {
			vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
			vcpu->run->system_event.type = KVM_SYSTEM_EVENT_RESET;
			r = 0;
			goto out;
		}
		if (kvm_check_request(KVM_REQ_HV_EXIT, vcpu)) {
			vcpu->run->exit_reason = KVM_EXIT_HYPERV;
			vcpu->run->hyperv = vcpu->arch.hyperv.exit;
			r = 0;
			goto out;
		}

		/*
		 * KVM_REQ_HV_STIMER has to be processed after
		 * KVM_REQ_CLOCK_UPDATE, because Hyper-V SynIC timers
		 * depend on the guest clock being up-to-date
		 */
		if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
			kvm_hv_process_stimers(vcpu);
	}

	if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
		++vcpu->stat.req_event;
		kvm_apic_accept_events(vcpu);
		if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
			r = 1;
			goto out;
		}

		if (inject_pending_event(vcpu, req_int_win) != 0)
			req_immediate_exit = true;
		else {
			/* Enable SMI/NMI/IRQ window open exits if needed.
			 *
			 * SMIs have three cases:
			 * 1) They can be nested, and then there is nothing to
			 *    do here because RSM will cause a vmexit anyway.
			 * 2) There is an ISA-specific reason why SMI cannot be
			 *    injected, and the moment when this changes can be
			 *    intercepted.
			 * 3) Or the SMI can be pending because
			 *    inject_pending_event has completed the injection
			 *    of an IRQ or NMI from the previous vmexit, and
			 *    then we request an immediate exit to inject the
			 *    SMI.
			 */
			if (vcpu->arch.smi_pending && !is_smm(vcpu))
				if (!kvm_x86_ops->enable_smi_window(vcpu))
					req_immediate_exit = true;
			if (vcpu->arch.nmi_pending)
				kvm_x86_ops->enable_nmi_window(vcpu);
			if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
				kvm_x86_ops->enable_irq_window(vcpu);
			WARN_ON(vcpu->arch.exception.pending);
		}

		if (kvm_lapic_enabled(vcpu)) {
			update_cr8_intercept(vcpu);
			kvm_lapic_sync_to_vapic(vcpu);
		}
	}

	r = kvm_mmu_reload(vcpu);
	if (unlikely(r)) {
		goto cancel_injection;
	}

	preempt_disable();

	kvm_x86_ops->prepare_guest_switch(vcpu);

	/*
	 * Disable IRQs before setting IN_GUEST_MODE.  Posted interrupt
	 * IPI are then delayed after guest entry, which ensures that they
	 * result in virtual interrupt delivery.
	 */
	local_irq_disable();
	vcpu->mode = IN_GUEST_MODE;

	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);

	/*
	 * 1) We should set ->mode before checking ->requests.  Please see
	 * the comment in kvm_vcpu_exiting_guest_mode().
	 *
	 * 2) For APICv, we should set ->mode before checking PIR.ON.  This
	 * pairs with the memory barrier implicit in pi_test_and_set_on
	 * (see vmx_deliver_posted_interrupt).
	 *
	 * 3) This also orders the write to mode from any reads to the page
	 * tables done while the VCPU is running.  Please see the comment
	 * in kvm_flush_remote_tlbs.
	 */
	smp_mb__after_srcu_read_unlock();

	/*
	 * This handles the case where a posted interrupt was
	 * notified with kvm_vcpu_kick.
	 */
	if (kvm_lapic_enabled(vcpu) && vcpu->arch.apicv_active)
		kvm_x86_ops->sync_pir_to_irr(vcpu);

	if (vcpu->mode == EXITING_GUEST_MODE || kvm_request_pending(vcpu)
	    || need_resched() || signal_pending(current)) {
		vcpu->mode = OUTSIDE_GUEST_MODE;
		smp_wmb();
		local_irq_enable();
		preempt_enable();
		vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
		r = 1;
		goto cancel_injection;
	}

	kvm_load_guest_xcr0(vcpu);

	if (req_immediate_exit) {
		kvm_make_request(KVM_REQ_EVENT, vcpu);
		kvm_x86_ops->request_immediate_exit(vcpu);
	}

	trace_kvm_entry(vcpu->vcpu_id);
	if (lapic_timer_advance_ns)
		wait_lapic_expire(vcpu);
	guest_enter_irqoff();

	if (unlikely(vcpu->arch.switch_db_regs)) {
		set_debugreg(0, 7);
		set_debugreg(vcpu->arch.eff_db[0], 0);
		set_debugreg(vcpu->arch.eff_db[1], 1);
		set_debugreg(vcpu->arch.eff_db[2], 2);
		set_debugreg(vcpu->arch.eff_db[3], 3);
		set_debugreg(vcpu->arch.dr6, 6);
		vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD;
	}

	kvm_x86_ops->run(vcpu);

	/*
	 * Do this here before restoring debug registers on the host.  And
	 * since we do this before handling the vmexit, a DR access vmexit
	 * can (a) read the correct value of the debug registers, (b) set
	 * KVM_DEBUGREG_WONT_EXIT again.
	 */
	if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) {
		WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP);
		kvm_x86_ops->sync_dirty_debug_regs(vcpu);
		kvm_update_dr0123(vcpu);
		kvm_update_dr6(vcpu);
		kvm_update_dr7(vcpu);
		vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD;
	}

	/*
	 * If the guest has used debug registers, at least dr7
	 * will be disabled while returning to the host.
	 * If we don't have active breakpoints in the host, we don't
	 * care about the messed up debug address registers. But if
	 * we have some of them active, restore the old state.
	 */
	if (hw_breakpoint_active())
		hw_breakpoint_restore();

	vcpu->arch.last_guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());

	vcpu->mode = OUTSIDE_GUEST_MODE;
	smp_wmb();

	kvm_put_guest_xcr0(vcpu);

	kvm_before_interrupt(vcpu);
	kvm_x86_ops->handle_external_intr(vcpu);
	kvm_after_interrupt(vcpu);

	++vcpu->stat.exits;

	guest_exit_irqoff();

	local_irq_enable();
	preempt_enable();

	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);

	/*
	 * Profile KVM exit RIPs:
	 */
	if (unlikely(prof_on == KVM_PROFILING)) {
		unsigned long rip = kvm_rip_read(vcpu);
		profile_hit(KVM_PROFILING, (void *)rip);
	}

	if (unlikely(vcpu->arch.tsc_always_catchup))
		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);

	if (vcpu->arch.apic_attention)
		kvm_lapic_sync_from_vapic(vcpu);

	vcpu->arch.gpa_available = false;
	r = kvm_x86_ops->handle_exit(vcpu);
	return r;

cancel_injection:
	kvm_x86_ops->cancel_injection(vcpu);
	if (unlikely(vcpu->arch.apic_attention))
		kvm_lapic_sync_from_vapic(vcpu);
out:
	return r;
}


int handle_ud(struct kvm_vcpu *vcpu)
{
	int emul_type = EMULTYPE_TRAP_UD;
	enum emulation_result er;
	char sig[5]; /* ud2; .ascii "kvm" */
	struct x86_exception e;

	if (force_emulation_prefix &&
	    kvm_read_guest_virt(vcpu, kvm_get_linear_rip(vcpu),
				sig, sizeof(sig), &e) == 0 &&
	    memcmp(sig, "\xf\xbkvm", sizeof(sig)) == 0) {
		kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(sig));
		emul_type = 0;
	}

	er = kvm_emulate_instruction(vcpu, emul_type);
	if (er == EMULATE_USER_EXIT)
		return 0;
	if (er != EMULATE_DONE)
		kvm_queue_exception(vcpu, UD_VECTOR);
	return 1;
}


static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
{
	if (!list_empty_careful(&vcpu->async_pf.done))
		return true;

	if (kvm_apic_has_events(vcpu))
		return true;

	if (vcpu->arch.pv.pv_unhalted)
		return true;

	if (vcpu->arch.exception.pending)
		return true;

	if (kvm_test_request(KVM_REQ_NMI, vcpu) ||
	    (vcpu->arch.nmi_pending &&
	     kvm_x86_ops->nmi_allowed(vcpu)))
		return true;

	if (kvm_test_request(KVM_REQ_SMI, vcpu) ||
	    (vcpu->arch.smi_pending && !is_smm(vcpu)))
		return true;

	if (kvm_arch_interrupt_allowed(vcpu) &&
	    (kvm_cpu_has_interrupt(vcpu) ||
	    kvm_guest_apic_has_interrupt(vcpu)))
		return true;

	if (kvm_hv_has_stimer_pending(vcpu))
		return true;

	return false;
}


static int com_property_exists(zval *object, zval *member, int check_empty, void **cache_slot)
{
	DISPID dispid;
	php_com_dotnet_object *obj;

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		convert_to_string_ex(member);
		if (SUCCEEDED(php_com_get_id_of_name(obj, Z_STRVAL_P(member), Z_STRLEN_P(member), &dispid))) {
			/* TODO: distinguish between property and method! */
			return 1;
		}
	} else {
		/* TODO: check for safearray */
	}

	return 0;
}


static void com_property_write(zval *object, zval *member, zval *value, void **cache_slot)
{
	php_com_dotnet_object *obj;
	VARIANT v;

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		VariantInit(&v);

		convert_to_string_ex(member);
		if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
				DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &v, 1, value, 0)) {
			VariantClear(&v);
		}
	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant has no properties");
	}
}


PHP_RSHUTDOWN_FUNCTION(com_dotnet)
{
#if HAVE_MSCOREE_H
	if (COMG(dotnet_runtime_stuff)) {
		php_com_dotnet_rshutdown();
	}
#endif
	COMG(rshutdown_started) = 1;
	return SUCCESS;
}


static zval *com_object_get(zval *property)
{
	/* Not yet implemented in the engine */
	return NULL;
}


static union _zend_function *com_method_get(zend_object **object_ptr, zend_string *name, const zval *key)
{
	zend_internal_function f, *fptr = NULL;
	union _zend_function *func;
	DISPID dummy;
	php_com_dotnet_object *obj = (php_com_dotnet_object*)*object_ptr;

	if (V_VT(&obj->v) != VT_DISPATCH) {
		return NULL;
	}

	if (FAILED(php_com_get_id_of_name(obj, name->val, name->len, &dummy))) {
		return NULL;
	}

	/* check cache */
	if (obj->method_cache == NULL || NULL == (fptr = zend_hash_find_ptr(obj->method_cache, name))) {
		f.type = ZEND_OVERLOADED_FUNCTION;
		f.num_args = 0;
		f.arg_info = NULL;
		f.scope = obj->ce;
		f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
		f.function_name = zend_string_copy(name);
		f.handler = PHP_FN(com_method_handler);

		fptr = &f;

		if (obj->typeinfo) {
			/* look for byref params */
			ITypeComp *comp;
			ITypeInfo *TI = NULL;
			DESCKIND kind;
			BINDPTR bindptr;
			OLECHAR *olename;
			ULONG lhash;
			int i;

			if (SUCCEEDED(ITypeInfo_GetTypeComp(obj->typeinfo, &comp))) {
				olename = php_com_string_to_olestring(name->val, name->len, obj->code_page);
				lhash = LHashValOfNameSys(SYS_WIN32, LOCALE_SYSTEM_DEFAULT, olename);

				if (SUCCEEDED(ITypeComp_Bind(comp, olename, lhash, INVOKE_FUNC, &TI, &kind, &bindptr))) {
					switch (kind) {
						case DESCKIND_FUNCDESC:
							f.arg_info = ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info));

							for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) {
								f.arg_info[i].type = ZEND_TYPE_ENCODE(0,1);
								if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) {
									f.arg_info[i].pass_by_reference = ZEND_SEND_BY_REF;
								}
							}

							f.num_args = bindptr.lpfuncdesc->cParams;

							ITypeInfo_ReleaseFuncDesc(TI, bindptr.lpfuncdesc);
							break;

							/* these should not happen, but *might* happen if the user
							 * screws up; lets avoid a leak in that case */
						case DESCKIND_VARDESC:
							ITypeInfo_ReleaseVarDesc(TI, bindptr.lpvardesc);
							break;
						case DESCKIND_TYPECOMP:
							ITypeComp_Release(bindptr.lptcomp);
							break;

						case DESCKIND_NONE:
							break;
					}
					if (TI) {
						ITypeInfo_Release(TI);
					}
				}
				ITypeComp_Release(comp);
				efree(olename);
			}
		}

		zend_set_function_arg_flags((zend_function*)&f);
		/* save this method in the cache */
		if (!obj->method_cache) {
			ALLOC_HASHTABLE(obj->method_cache);
			zend_hash_init(obj->method_cache, 2, NULL, function_dtor, 0);
		}

		zend_hash_update_mem(obj->method_cache, name, &f, sizeof(f));
	}

	if (fptr) {
		/* duplicate this into a new chunk of emalloc'd memory,
		 * since the engine will efree it */
		func = emalloc(sizeof(*fptr));
		memcpy(func, fptr, sizeof(*fptr));

		return func;
	}

	return NULL;
}


static zval *com_read_dimension(zval *object, zval *offset, int type, zval *rv)
{
	php_com_dotnet_object *obj;
	VARIANT v;

	ZVAL_NULL(rv);

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		VariantInit(&v);

		if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
				DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 1, offset, 0, 0)) {
			php_com_zval_from_variant(rv, &v, obj->code_page);
			VariantClear(&v);
		}
	} else if (V_ISARRAY(&obj->v)) {
		convert_to_long(offset);

		if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {
			if (php_com_safearray_get_elem(&obj->v, &v, (LONG)Z_LVAL_P(offset))) {
				php_com_wrap_variant(rv, &v, obj->code_page);
				VariantClear(&v);
			}
		} else {
			php_com_saproxy_create(object, rv, offset);
		}

	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant is not an array type");
	}

	return rv;
}


void guess_sa_name(char *sa_dir, struct tm *rectime, int *sa_name)
{
	char filename[MAX_FILE_LEN];
	struct stat sb;
	time_t sa_mtime;

	/* Use saDD by default */
	*sa_name = 0;

	/* Look for saYYYYMMDD */
	snprintf(filename, MAX_FILE_LEN,
		 "%s/sa%04d%02d%02d", sa_dir,
		 rectime->tm_year + 1900,
		 rectime->tm_mon + 1,
		 rectime->tm_mday);
	filename[MAX_FILE_LEN - 1] = '\0';

	if (stat(filename, &sb) < 0)
		/* Cannot find or access saYYYYMMDD, so use saDD */
		return;
	sa_mtime = sb.st_mtime;

	/* Look for saDD */
	snprintf(filename, MAX_FILE_LEN,
		 "%s/sa%02d", sa_dir,
		 rectime->tm_mday);
	filename[MAX_FILE_LEN - 1] = '\0';

	if (stat(filename, &sb) < 0) {
		/* Cannot find or access saDD, so use saYYYYMMDD */
		*sa_name = 1;
		return;
	}

	if (sa_mtime > sb.st_mtime) {
		/* saYYYYMMDD is more recent than saDD, so use it */
		*sa_name = 1;
	}
}


int read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
			 struct file_activity *file_actlst, int endian_mismatch,
			 int arch_64, char *dfile, struct file_magic *file_magic,
			 int oneof)
{
	int i, j, p;
	struct file_activity *fal = file_actlst;
	off_t offset;
	__nr_t nr_value;

	for (i = 0; i < act_nr; i++, fal++) {

		/* Read __nr_t value preceding statistics structures if it exists */
		if (fal->has_nr) {
			nr_value = read_nr_value(ifd, dfile, file_magic,
						 endian_mismatch, arch_64, FALSE);
		}
		else {
			nr_value = fal->nr;
		}

		if (nr_value > NR_MAX) {
#ifdef DEBUG
			fprintf(stderr, "%s: Value=%d Max=%d\n", __FUNCTION__, nr_value, NR_MAX);
#endif
			handle_invalid_sa_file(ifd, file_magic, dfile, 0);
		}

		if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
		    (act[p]->magic != fal->magic)) {
			/*
			 * Ignore current activity in file, which is unknown to
			 * current sysstat version or has an unknown format.
			 */
			if (nr_value) {
				offset = (off_t) fal->size * (off_t) nr_value * (off_t) fal->nr2;
				if (lseek(ifd, offset, SEEK_CUR) < offset) {
					close(ifd);
					perror("lseek");
					if (oneof == UEOF_CONT)
						return 2;
					exit(2);
				}
			}
			continue;
		}

		if (nr_value > act[p]->nr_max) {
#ifdef DEBUG
			fprintf(stderr, "%s: %s: Value=%d Max=%d\n",
				__FUNCTION__, act[p]->name, nr_value, act[p]->nr_max);
#endif
			handle_invalid_sa_file(ifd, file_magic, dfile, 0);
		}
		act[p]->nr[curr] = nr_value;

		/* Reallocate buffers if needed */
		if (nr_value > act[p]->nr_allocated) {
			reallocate_all_buffers(act[p], nr_value);
		}

		/*
                 * For persistent activities, we must make sure that no statistics
                 * from a previous iteration remain, especially if the number
                 * of structures read is smaller than @nr_ini.
                 */
		if (HAS_PERSISTENT_VALUES(act[p]->options)) {
                    memset(act[p]->buf[curr], 0,
                           (size_t) act[p]->msize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
                }

		/* OK, this is a known activity: Read the stats structures */
		if ((nr_value > 0) &&
		    ((nr_value > 1) || (act[p]->nr2 > 1)) &&
		    (act[p]->msize > act[p]->fsize)) {

			for (j = 0; j < (nr_value * act[p]->nr2); j++) {
				if (sa_fread(ifd, (char *) act[p]->buf[curr] + j * act[p]->msize,
					 (size_t) act[p]->fsize, HARD_SIZE, oneof) > 0)
					/* Unexpected EOF */
					return 2;
			}
		}
		else if (nr_value > 0) {
			/*
			 * Note: If msize was smaller than fsize,
			 * then it has been set to fsize in check_file_actlst().
			 */
			if (sa_fread(ifd, act[p]->buf[curr],
				 (size_t) act[p]->fsize * (size_t) nr_value * (size_t) act[p]->nr2,
				 HARD_SIZE, oneof) > 0)
				/* Unexpected EOF */
				return 2;
		}
		else {
			/* nr_value == 0: Nothing to read */
			continue;
		}

		/* Normalize endianness for current activity's structures */
		if (endian_mismatch) {
			for (j = 0; j < (nr_value * act[p]->nr2); j++) {
				swap_struct(act[p]->ftypes_nr, (char *) act[p]->buf[curr] + j * act[p]->msize,
					    arch_64);
			}
		}

		/* Remap structure's fields to those known by current sysstat version */
		for (j = 0; j < (nr_value * act[p]->nr2); j++) {
			remap_struct(act[p]->gtypes_nr, act[p]->ftypes_nr,
				     (char *) act[p]->buf[curr] + j * act[p]->msize,
				     act[p]->fsize, act[p]->msize, act[p]->msize);
		}
	}

	return 0;
}


int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic,
		     struct file_activity *file_actlst, struct tm *rectime,
		     struct tm *loctime, int *views_per_row, int *nr_act_dispd)
{
	int i, n, p, tot_g_nr = 0;

	*nr_act_dispd = 0;

	/* Count items in file */
	if (!count_file_items(ifd, file, file_magic, file_actlst, rectime, loctime))
		/* No record to display => No graph */
		return 0;

	for (i = 0; i < NR_ACT; i++) {
		if (!id_seq[i])
			continue;

		p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
		if (!IS_SELECTED(act[p]->options) || !act[p]->g_nr)
			continue;

		(*nr_act_dispd)++;

		if (PACK_VIEWS(flags)) {
			/*
			 * One activity = one row with multiple views.
			 * Exception is A_MEMORY, for which one activity may be
			 * displayed in two rows if both memory *and* swap utilization
			 * have been selected.
			 */
			if ((act[p]->id == A_MEMORY) &&
			    (DISPLAY_MEMORY(act[p]->opt_flags) && DISPLAY_SWAP(act[p]->opt_flags))) {
				n = 2;
			}
			else {
				n = 1;
			}
		}
		else {
			/* One activity = multiple rows with only one view */
			n = act[p]->g_nr;
		}
		if (ONE_GRAPH_PER_ITEM(act[p]->options)) {
			 n = n * act[p]->item_list_sz;
		}
		if (act[p]->g_nr > *views_per_row) {
			*views_per_row = act[p]->g_nr;
		}

		tot_g_nr += n;
	}

	if (*views_per_row > MAX_VIEWS_ON_A_ROW) {
		*views_per_row = MAX_VIEWS_ON_A_ROW;
	}

	return tot_g_nr;
}


void check_format_options(void)
{
	if (!format) {
		/* Select output format if none has been selected */
		if (DISPLAY_HDR_ONLY(flags)) {
			format = F_HEADER_OUTPUT;
		}
		else {
			format = F_PPC_OUTPUT;
		}
	}

	/* Get format position in array */
	f_position = get_format_position(fmt, format);

	/* Check options consistency wrt output format */
	if (!ACCEPT_HEADER_ONLY(fmt[f_position]->options)) {
		/* Remove option -H */
		flags &= ~S_F_HDR_ONLY;
	}
	if (!ACCEPT_HORIZONTALLY(fmt[f_position]->options)) {
		/* Remove option -h */
		flags &= ~S_F_HORIZONTALLY;
	}
	if (!ACCEPT_LOCAL_TIME(fmt[f_position]->options)) {
		/* Remove options -T and -t */
		flags &= ~(S_F_LOCAL_TIME + S_F_TRUE_TIME);
	}
	if (!ACCEPT_SEC_EPOCH(fmt[f_position]->options)) {
		/* Remove option -U */
		flags &= ~S_F_SEC_EPOCH;
	}
	if (REJECT_TRUE_TIME(fmt[f_position]->options)) {
		/* Remove option -t */
		flags &= ~S_F_TRUE_TIME;
	}
}


int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
		  unsigned int *flags, int caller)
{
	int i, p;

	for (i = 1; *(argv[*opt] + i); i++) {
		/*
		 * Note: argv[*opt] contains something like "-BruW"
		 *     *(argv[*opt] + i) will contain 'B', 'r', etc.
		 */

		switch (*(argv[*opt] + i)) {

		case 'A':
			select_all_activities(act);

			/*
			 * Force '-P ALL -I ALL -r ALL -u ALL -F'.
			 * Setting -F is compulsory because corresponding activity
			 * has AO_MULTIPLE_OUTPUTS flag set.
			 */
			p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
			act[p]->opt_flags |= AO_F_MEMORY + AO_F_SWAP + AO_F_MEM_ALL;

			p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
			memset(act[p]->bitmap->b_array, ~0,
			       BITMAP_SIZE(act[p]->bitmap->b_size));
			p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
			memset(act[p]->bitmap->b_array, ~0,
			       BITMAP_SIZE(act[p]->bitmap->b_size));
			act[p]->opt_flags = AO_F_CPU_ALL;

			p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
			act[p]->opt_flags = AO_F_FILESYSTEM;
			break;

		case 'B':
			SELECT_ACTIVITY(A_PAGE);
			break;

		case 'b':
			SELECT_ACTIVITY(A_IO);
			break;

		case 'C':
			*flags |= S_F_COMMENT;
			break;

		case 'd':
			SELECT_ACTIVITY(A_DISK);
			break;

		case 'F':
			p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
			act[p]->options |= AO_SELECTED;
			if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
				(*opt)++;
				act[p]->opt_flags |= AO_F_MOUNT;
				return 0;
			}
			else {
				act[p]->opt_flags |= AO_F_FILESYSTEM;
			}
			break;

		case 'H':
			SELECT_ACTIVITY(A_HUGE);
			break;

		case 'h':
			/*
			 * Make output easier to read by a human.
			 * Option -h implies --human and -p (pretty-print).
			 */
			*flags |= S_F_HUMAN_READ + S_F_UNIT + S_F_DEV_PRETTY;
			break;

		case 'j':
			if (!argv[*opt + 1]) {
				return 1;
			}
			(*opt)++;
			if (strnlen(argv[*opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1)
				return 1;

			strncpy(persistent_name_type, argv[*opt], MAX_FILE_LEN - 1);
			persistent_name_type[MAX_FILE_LEN - 1] = '\0';
			strtolower(persistent_name_type);
			if (!get_persistent_type_dir(persistent_name_type)) {
				fprintf(stderr, _("Invalid type of persistent device name\n"));
				return 2;
			}
			/*
			 * If persistent device name doesn't exist for device, use
			 * its pretty name.
			 */
			*flags |= S_F_PERSIST_NAME + S_F_DEV_PRETTY;
			return 0;
			break;

		case 'p':
			*flags |= S_F_DEV_PRETTY;
			break;

		case 'q':
			SELECT_ACTIVITY(A_QUEUE);
			break;

		case 'r':
			p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
			act[p]->options   |= AO_SELECTED;
			act[p]->opt_flags |= AO_F_MEMORY;
			if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
				(*opt)++;
				act[p]->opt_flags |= AO_F_MEM_ALL;
				return 0;
			}
			break;

		case 'S':
			p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
			act[p]->options   |= AO_SELECTED;
			act[p]->opt_flags |= AO_F_SWAP;
			break;

		case 't':
			/*
			 * Check sar option -t here (as it can be combined
			 * with other ones, eg. "sar -rtu ..."
			 * But sadf option -t is checked in sadf.c as it won't
			 * be entered as a sar option after "--".
			 */
			if (caller != C_SAR) {
				return 1;
			}
			*flags |= S_F_TRUE_TIME;
			break;

		case 'u':
			p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
			act[p]->options |= AO_SELECTED;
			if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
				(*opt)++;
				act[p]->opt_flags = AO_F_CPU_ALL;
				return 0;
			}
			else {
				act[p]->opt_flags = AO_F_CPU_DEF;
			}
			break;

		case 'v':
			SELECT_ACTIVITY(A_KTABLES);
			break;

		case 'w':
			SELECT_ACTIVITY(A_PCSW);
			break;

		case 'W':
			SELECT_ACTIVITY(A_SWAP);
			break;

		case 'y':
			SELECT_ACTIVITY(A_SERIAL);
			break;

		case 'z':
			*flags |= S_F_ZERO_OMIT;
			break;

		case 'V':
			print_version();
			break;

		default:
			return 1;
		}
	}
	return 0;
}


int search_list_item(struct sa_item *list, char *item_name)
{
	while (list != NULL) {
		if (!strcmp(list->item_name, item_name))
			return 1;	/* Item found in list */
		list = list->next;
	}

	/* Item not found */
	return 0;
}


static const char **prepare_shell_cmd(struct argv_array *out, const char **argv)
{
	if (!argv[0])
		die("BUG: shell command is empty");

	if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
#ifndef GIT_WINDOWS_NATIVE
		argv_array_push(out, SHELL_PATH);
#else
		argv_array_push(out, "sh");
#endif
		argv_array_push(out, "-c");

		/*
		 * If we have no extra arguments, we do not even need to
		 * bother with the "$@" magic.
		 */
		if (!argv[1])
			argv_array_push(out, argv[0]);
		else
			argv_array_pushf(out, "%s \"$@\"", argv[0]);
	}

	argv_array_pushv(out, argv);
	return out->argv;
}


static void child_close(int fd)
{
	if (close(fd))
		child_die(CHILD_ERR_CLOSE);
}


static void NORETURN child_die_fn(const char *err, va_list params)
{
	const char msg[] = "die() should not be called in child\n";
	xwrite(2, msg, sizeof(msg) - 1);
	_exit(2);
}


void child_process_init(struct child_process *child)
{
	memset(child, 0, sizeof(*child));
	argv_array_init(&child->args);
	argv_array_init(&child->env_array);
}


int pipe_command(struct child_process *cmd,
		 const char *in, size_t in_len,
		 struct strbuf *out, size_t out_hint,
		 struct strbuf *err, size_t err_hint)
{
	struct io_pump io[3];
	int nr = 0;

	if (in)
		cmd->in = -1;
	if (out)
		cmd->out = -1;
	if (err)
		cmd->err = -1;

	if (start_command(cmd) < 0)
		return -1;

	if (in) {
		io[nr].fd = cmd->in;
		io[nr].type = POLLOUT;
		io[nr].u.out.buf = in;
		io[nr].u.out.len = in_len;
		nr++;
	}
	if (out) {
		io[nr].fd = cmd->out;
		io[nr].type = POLLIN;
		io[nr].u.in.buf = out;
		io[nr].u.in.hint = out_hint;
		nr++;
	}
	if (err) {
		io[nr].fd = cmd->err;
		io[nr].type = POLLIN;
		io[nr].u.in.buf = err;
		io[nr].u.in.hint = err_hint;
		nr++;
	}

	if (pump_io(io, nr) < 0) {
		finish_command(cmd); /* throw away exit code */
		return -1;
	}

	return finish_command(cmd);
}


ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
        uint8_t *p = buf;
        ssize_t n = 0;

        assert(fd >= 0);
        assert(buf);

        /* If called with nbytes == 0, let's call read() at least
         * once, to validate the operation */

        if (nbytes > (size_t) SSIZE_MAX)
                return -EINVAL;

        do {
                ssize_t k;

                k = read(fd, p, nbytes);
                if (k < 0) {
                        if (errno == EINTR)
                                continue;

                        if (errno == EAGAIN && do_poll) {

                                /* We knowingly ignore any return value here,
                                 * and expect that any error/EOF is reported
                                 * via read() */

                                (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
                                continue;
                        }

                        return n > 0 ? n : -errno;
                }

                if (k == 0)
                        return n;

                assert((size_t) k <= nbytes);

                p += k;
                nbytes -= k;
                n += k;
        } while (nbytes > 0);

        return n;
}


static int cache_space_refresh(Server *s, JournalStorage *storage) {
        JournalStorageSpace *space;
        JournalMetrics *metrics;
        uint64_t vfs_used, vfs_avail, avail;
        usec_t ts;
        int r;

        assert(s);

        metrics = &storage->metrics;
        space = &storage->space;

        ts = now(CLOCK_MONOTONIC);

        if (space->timestamp != 0 && space->timestamp + RECHECK_SPACE_USEC > ts)
                return 0;

        r = determine_path_usage(s, storage->path, &vfs_used, &vfs_avail);
        if (r < 0)
                return r;

        space->vfs_used = vfs_used;
        space->vfs_available = vfs_avail;

        avail = LESS_BY(vfs_avail, metrics->keep_free);

        space->limit = MIN(MAX(vfs_used + avail, metrics->min_use), metrics->max_use);
        space->available = LESS_BY(space->limit, vfs_used);
        space->timestamp = ts;
        return 1;
}


static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {

        static const char * const xattrs[_CONTEXT_MAX] = {
                [CONTEXT_PID] = "user.coredump.pid",
                [CONTEXT_UID] = "user.coredump.uid",
                [CONTEXT_GID] = "user.coredump.gid",
                [CONTEXT_SIGNAL] = "user.coredump.signal",
                [CONTEXT_TIMESTAMP] = "user.coredump.timestamp",
                [CONTEXT_RLIMIT] = "user.coredump.rlimit",
                [CONTEXT_HOSTNAME] = "user.coredump.hostname",
                [CONTEXT_COMM] = "user.coredump.comm",
                [CONTEXT_EXE] = "user.coredump.exe",
        };

        int r = 0;
        unsigned i;

        assert(fd >= 0);

        /* Attach some metadata to coredumps via extended
         * attributes. Just because we can. */

        for (i = 0; i < _CONTEXT_MAX; i++) {
                int k;

                if (isempty(context[i]) || !xattrs[i])
                        continue;

                k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE);
                if (k < 0 && r == 0)
                        r = -errno;
        }

        return r;
}


int config_parse_line_max(
                const char* unit,
                const char *filename,
                unsigned line,
                const char *section,
                unsigned section_line,
                const char *lvalue,
                int ltype,
                const char *rvalue,
                void *data,
                void *userdata) {

        size_t *sz = data;
        int r;

        assert(filename);
        assert(lvalue);
        assert(rvalue);
        assert(data);

        if (isempty(rvalue))
                /* Empty assignment means default */
                *sz = DEFAULT_LINE_MAX;
        else {
                uint64_t v;

                r = parse_size(rvalue, 1024, &v);
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue);
                        return 0;
                }

                if (v < 79) {
                        /* Why specify 79 here as minimum line length? Simply, because the most common traditional
                         * terminal size is 80ch, and it might make sense to break one character before the natural
                         * line break would occur on that. */
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too small, clamping to 79: %s", rvalue);
                        *sz = 79;
                } else if (v > (uint64_t) (SSIZE_MAX-1)) {
                        /* So, why specify SSIZE_MAX-1 here? Because that's one below the largest size value read()
                         * can return, and we need one extra byte for the trailing NUL byte. Of course IRL such large
                         * memory allocations will fail anyway, hence this limit is mostly theoretical anyway, as we'll
                         * fail much earlier anyway. */
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too large, clamping to %" PRIu64 ": %s", (uint64_t) (SSIZE_MAX-1), rvalue);
                        *sz = SSIZE_MAX-1;
                } else
                        *sz = (size_t) v;
        }

        return 0;


static int setup_signals(Server *s) {
        int r;

        assert(s);

        assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);

        r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
        if (r < 0)
                return r;

        r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2, dispatch_sigusr2, s);
        if (r < 0)
                return r;

        r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM, dispatch_sigterm, s);
        if (r < 0)
                return r;

        /* Let's process SIGTERM late, so that we flush all queued
         * messages to disk before we exit */
        r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20);
        if (r < 0)
                return r;

        /* When journald is invoked on the terminal (when debugging),
         * it's useful if C-c is handled equivalent to SIGTERM. */
        r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20);
        if (r < 0)
                return r;

        /* SIGRTMIN+1 causes an immediate sync. We process this very
         * late, so that everything else queued at this point is
         * really written to disk. Clients can watch
         * /run/systemd/journal/synced with inotify until its mtime
         * changes to see when a sync happened. */
        r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s);
        if (r < 0)
                return r;

        r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15);
        if (r < 0)
                return r;

        return 0;


void server_dispatch_message(
                Server *s,
                struct iovec *iovec, size_t n, size_t m,
                ClientContext *c,
                const struct timeval *tv,
                int priority,
                pid_t object_pid) {

        uint64_t available = 0;
        int rl;

        assert(s);
        assert(iovec || n == 0);

        if (n == 0)
                return;

        if (LOG_PRI(priority) > s->max_level_store)
                return;

        /* Stop early in case the information will not be stored
         * in a journal. */
        if (s->storage == STORAGE_NONE)
                return;

        if (c && c->unit) {
                (void) determine_space(s, &available, NULL);

                rl = journal_rate_limit_test(s->rate_limit, c->unit, c->log_rate_limit_interval, c->log_rate_limit_burst, priority & LOG_PRIMASK, available);
                if (rl == 0)
                        return;

                /* Write a suppression message if we suppressed something */
                if (rl > 1)
                        server_driver_message(s, c->pid,
                                              "MESSAGE_ID=" SD_MESSAGE_JOURNAL_DROPPED_STR,
                                              LOG_MESSAGE("Suppressed %i messages from %s", rl - 1, c->unit),
                                              "N_DROPPED=%i", rl - 1,
                                              NULL);
        }

        dispatch_message_real(s, iovec, n, m, c, tv, priority, object_pid);


int config_parse_compress(const char* unit,
                          const char *filename,
                          unsigned line,
                          const char *section,
                          unsigned section_line,
                          const char *lvalue,
                          int ltype,
                          const char *rvalue,
                          void *data,
                          void *userdata) {
        JournalCompressOptions* compress = data;
        int r;

        if (streq(rvalue, "1")) {
                log_syntax(unit, LOG_WARNING, filename, line, 0,
                           "Compress= ambiguously specified as 1, enabling compression with default threshold");
                compress->enabled = true;
        } else if (streq(rvalue, "0")) {
                log_syntax(unit, LOG_WARNING, filename, line, 0,
                           "Compress= ambiguously specified as 0, disabling compression");
                compress->enabled = false;
        } else if ((r = parse_boolean(rvalue)) >= 0)
                compress->enabled = r;
        else if (parse_size(rvalue, 1024, &compress->threshold_bytes) == 0)
                compress->enabled = true;
        else if (isempty(rvalue)) {
                compress->enabled = true;
                compress->threshold_bytes = (uint64_t) -1;
        } else
                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Compress= value, ignoring: %s", rvalue);

        return 0;


static size_t nul_length(const uint8_t *p, size_t sz) {
        size_t n = 0;

        while (sz > 0) {
                if (*p != 0)
                        break;

                n++;
                p++;
                sz--;
        }

        return n;
}


static int server_open_hostname(Server *s) {
        int r;

        assert(s);

        s->hostname_fd = open("/proc/sys/kernel/hostname",
                              O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
        if (s->hostname_fd < 0)
                return log_error_errno(errno, "Failed to open /proc/sys/kernel/hostname: %m");

        r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
        if (r < 0) {
                /* kernels prior to 3.2 don't support polling this file. Ignore
                 * the failure. */
                if (r == -EPERM) {
                        log_warning_errno(r, "Failed to register hostname fd in event loop, ignoring: %m");
                        s->hostname_fd = safe_close(s->hostname_fd);
                        return 0;
                }

                return log_error_errno(r, "Failed to register hostname fd in event loop: %m");
        }

        r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
        if (r < 0)
                return log_error_errno(r, "Failed to adjust priority of host name event source: %m");

        return 0;


static void map_context_fields(const struct iovec *iovec, const char* context[]) {

        static const char * const context_field_names[] = {
                [CONTEXT_PID] = "COREDUMP_PID=",
                [CONTEXT_UID] = "COREDUMP_UID=",
                [CONTEXT_GID] = "COREDUMP_GID=",
                [CONTEXT_SIGNAL] = "COREDUMP_SIGNAL=",
                [CONTEXT_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
                [CONTEXT_RLIMIT] = "COREDUMP_RLIMIT=",
                [CONTEXT_HOSTNAME] = "COREDUMP_HOSTNAME=",
                [CONTEXT_COMM] = "COREDUMP_COMM=",
                [CONTEXT_EXE] = "COREDUMP_EXE=",
        };

        unsigned i;

        assert(iovec);
        assert(context);

        for (i = 0; i < ELEMENTSOF(context_field_names); i++) {
                char *p;

                if (!context_field_names[i])
                        continue;

                p = memory_startswith(iovec->iov_base, iovec->iov_len, context_field_names[i]);
                if (!p)
                        continue;

                /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
                 * buffer, though not included in the iov_len count. (see below) */
                context[i] = p;
                break;
        }
}


static int accept_connection(const char* type, int fd,
                             SocketAddress *addr, char **hostname) {
        int fd2, r;

        log_debug("Accepting new %s connection on fd:%d", type, fd);
        fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
        if (fd2 < 0)
                return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);

        switch(socket_address_family(addr)) {
        case AF_INET:
        case AF_INET6: {
                _cleanup_free_ char *a = NULL;
                char *b;

                r = socket_address_print(addr, &a);
                if (r < 0) {
                        log_error_errno(r, "socket_address_print(): %m");
                        close(fd2);
                        return r;
                }

                r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
                if (r < 0) {
                        log_error_errno(r, "Resolving hostname failed: %m");
                        close(fd2);
                        return r;
                }

                log_debug("Accepted %s %s connection from %s",
                          type,
                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
                          a);

                *hostname = b;

                return fd2;
        };
        default:
                log_error("Rejected %s connection with unsupported family %d",
                          type, socket_address_family(addr));
                close(fd2);

                return -EINVAL;
        }
}


static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
        MHD_stop_daemon(d->daemon);
        sd_event_source_unref(d->io_event);
        sd_event_source_unref(d->timer_event);
        free(d);
}


static int spawn_getter(const char *getter) {
        int r;
        _cleanup_strv_free_ char **words = NULL;

        assert(getter);
        r = strv_split_extract(&words, getter, WHITESPACE, EXTRACT_QUOTES);
        if (r < 0)
                return log_error_errno(r, "Failed to split getter option: %m");

        r = spawn_child(words[0], words);
        if (r < 0)
                log_error_errno(r, "Failed to spawn getter %s: %m", getter);

        return r;
}


static int spawn_curl(const char* url) {
        char **argv = STRV_MAKE("curl",
                                "-HAccept: application/vnd.fdo.journal",
                                "--silent",
                                "--show-error",
                                url);
        int r;

        r = spawn_child("curl", argv);
        if (r < 0)
                log_error_errno(r, "Failed to spawn curl: %m");
        return r;
}


static int remove_source(RemoteServer *s, int fd) {
        RemoteSource *source;

        assert(s);
        assert(fd >= 0 && fd < (ssize_t) s->sources_size);

        source = s->sources[fd];
        if (source) {
                /* this closes fd too */
                source_free(source);
                s->sources[fd] = NULL;
                s->active--;
        }

        return 0;
}


static int open_output(RemoteServer *s, Writer *w, const char* host) {
        _cleanup_free_ char *_filename = NULL;
        const char *filename;
        int r;

        switch (s->split_mode) {
        case JOURNAL_WRITE_SPLIT_NONE:
                filename = s->output;
                break;

        case JOURNAL_WRITE_SPLIT_HOST: {
                _cleanup_free_ char *name;

                assert(host);

                name = filename_escape(host);
                if (!name)
                        return log_oom();

                r = asprintf(&_filename, "%s/remote-%s.journal", s->output, name);
                if (r < 0)
                        return log_oom();

                filename = _filename;
                break;
        }

        default:
                assert_not_reached("what?");
        }

        r = journal_file_open_reliably(filename,
                                       O_RDWR|O_CREAT, 0640,
                                       s->compress, (uint64_t) -1, s->seal,
                                       &w->metrics,
                                       w->mmap, NULL,
                                       NULL, &w->journal);
        if (r < 0)
                return log_error_errno(r, "Failed to open output journal %s: %m", filename);

        log_debug("Opened output file %s", w->journal->path);
        return 0;
}


static int load_certificates(char **key, char **cert, char **trust) {
        int r;

        r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
        if (r < 0)
                return log_error_errno(r, "Failed to read key from file '%s': %m",
                                       arg_key ?: PRIV_KEY_FILE);

        r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
        if (r < 0)
                return log_error_errno(r, "Failed to read certificate from file '%s': %m",
                                       arg_cert ?: CERT_FILE);

        if (arg_trust_all)
                log_info("Certificate checking disabled.");
        else {
                r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
                if (r < 0)
                        return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
                                               arg_trust ?: TRUST_FILE);
        }

        if ((arg_listen_raw || arg_listen_http) && *trust)
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                       "Option --trust makes all non-HTTPS connections untrusted.");

        return 0;
}


static void forward_syslog_raw(Server *s, int priority, const char *buffer, size_t buffer_len, const struct ucred *ucred, const struct timeval *tv) {
        struct iovec iovec;

        assert(s);
        assert(buffer);

        if (LOG_PRI(priority) > s->max_level_syslog)
                return;

        iovec = IOVEC_MAKE((char *) buffer, buffer_len);
        forward_syslog_iovec(s, &iovec, 1, ucred, tv);
}


int main(void) {
        test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", 11);
        test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, 6);
        test_syslog_parse_identifier("pidu:  xxx", "pidu", NULL, 7);
        test_syslog_parse_identifier("pidu xxx", NULL, NULL, 0);
        test_syslog_parse_identifier(":", "", NULL, 1);
        test_syslog_parse_identifier(":  ", "", NULL, 3);
        test_syslog_parse_identifier("pidu:", "pidu", NULL, 5);
        test_syslog_parse_identifier("pidu: ", "pidu", NULL, 6);
        test_syslog_parse_identifier("pidu : ", NULL, NULL, 0);

        return 0;
}


   Move specified message to a mailbox */
PHP_FUNCTION(imap_mail_move)
{
	zval *streamind;
	zend_string *seq, *folder;
	zend_long options = 0;
	pils *imap_le_struct;
	int argc = ZEND_NUM_ARGS();

	if (zend_parse_parameters(argc, "rSS|l", &streamind, &seq, &folder, &options) == FAILURE) {
		return;
	}

	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
		RETURN_FALSE;
	}

	if (mail_copy_full(imap_le_struct->imap_stream, ZSTR_VAL(seq), ZSTR_VAL(folder), (argc == 4 ? (options | CP_MOVE) : CP_MOVE)) == T) {
		RETURN_TRUE;
	} else {
		RETURN_FALSE;
	}


/* Author: CJH */
PHP_FUNCTION(imap_last_error)
{
	ERRORLIST *cur=NIL;

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	if (IMAPG(imap_errorstack) == NIL) {
		RETURN_FALSE;
	}

	cur = IMAPG(imap_errorstack);
	while (cur != NIL) {
		if (cur->next == NIL) {
			RETURN_STRING((char*)cur->LTEXT);
		}
		cur = cur->next;
	}


	Sets the ACL for a given mailbox */
PHP_FUNCTION(imap_setacl)
{
	zval *streamind;
	zend_string *mailbox, *id, *rights;
	pils *imap_le_struct;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSSS", &streamind, &mailbox, &id, &rights) == FAILURE) {
		return;
	}

	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
		RETURN_FALSE;
	}

	RETURN_BOOL(imap_setacl(imap_le_struct->imap_stream, ZSTR_VAL(mailbox), ZSTR_VAL(id), ZSTR_VAL(rights)));


   Sets flags on messages */
PHP_FUNCTION(imap_setflag_full)
{
	zval *streamind;
	zend_string *sequence, *flag;
	zend_long flags = 0;
	pils *imap_le_struct;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS|l", &streamind, &sequence, &flag, &flags) == FAILURE) {
		return;
	}

	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
		RETURN_FALSE;
	}

	mail_setflag_full(imap_le_struct->imap_stream, ZSTR_VAL(sequence), ZSTR_VAL(flag), (flags ? flags : NIL));
	RETURN_TRUE;


   Read the list of mailboxes */
PHP_FUNCTION(imap_list)
{
	zval *streamind;
	zend_string *ref, *pat;
	pils *imap_le_struct;
	STRINGLIST *cur=NIL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
		return;
	}

	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
		RETURN_FALSE;
	}

	/* set flag for normal, old mailbox list */
	IMAPG(folderlist_style) = FLIST_ARRAY;

	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;
	mail_list(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
	if (IMAPG(imap_folders) == NIL) {
		RETURN_FALSE;
	}

	array_init(return_value);
	cur=IMAPG(imap_folders);
	while (cur != NIL) {
		add_next_index_string(return_value, (char*)cur->LTEXT);
		cur=cur->next;
	}
	mail_free_stringlist (&IMAPG(imap_folders));
	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;


   Check if the IMAP stream is still active */
PHP_FUNCTION(imap_ping)
{
	zval *streamind;
	pils *imap_le_struct;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
		return;
	}

	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
		RETURN_FALSE;
	}

	RETURN_BOOL(mail_ping(imap_le_struct->imap_stream));


void mail_getquota(MAILSTREAM *stream, char *qroot, QUOTALIST *qlist)
{
	zval t_map, *return_value;

	return_value = *IMAPG(quota_return);

/* put parsing code here */
	for(; qlist; qlist = qlist->next) {
		array_init(&t_map);
		if (strncmp(qlist->name, "STORAGE", 7) == 0)
		{
			/* this is to add backwards compatibility */
			add_assoc_long_ex(return_value, "usage", sizeof("usage") - 1, qlist->usage);
			add_assoc_long_ex(return_value, "limit", sizeof("limit") - 1, qlist->limit);
		}

		add_assoc_long_ex(&t_map, "usage", sizeof("usage") - 1, qlist->usage);
		add_assoc_long_ex(&t_map, "limit", sizeof("limit") - 1, qlist->limit);
		add_assoc_zval_ex(return_value, qlist->name, strlen(qlist->name), &t_map);
	}


   Create a MIME message based on given envelope and body sections */
PHP_FUNCTION(imap_mail_compose)
{
	zval *envelope, *body;
	zend_string *key;
	zval *data, *pvalue, *disp_data, *env_data;
	char *cookie = NIL;
	ENVELOPE *env;
	BODY *bod=NULL, *topbod=NULL;
	PART *mypart=NULL, *part;
	PARAMETER *param, *disp_param = NULL, *custom_headers_param = NULL, *tmp_param = NULL;
	char *tmp=NULL, *mystring=NULL, *t=NULL, *tempstring=NULL, *str_copy = NULL;
	int toppart = 0;
	int first;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &envelope, &body) == FAILURE) {
		return;
	}

#define PHP_RFC822_PARSE_ADRLIST(target, value) \
	str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \
	rfc822_parse_adrlist(target, str_copy, "NO HOST"); \
	efree(str_copy);

	env = mail_newenvelope();
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		env->remail = cpystr(Z_STRVAL_P(pvalue));
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue);
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue));
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue);
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue);
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		env->in_reply_to = cpystr(Z_STRVAL_P(pvalue));
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		env->subject = cpystr(Z_STRVAL_P(pvalue));
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue);
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue);
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue);
	}
	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) {
		convert_to_string_ex(pvalue);
		env->message_id=cpystr(Z_STRVAL_P(pvalue));
	}

	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "custom_headers", sizeof("custom_headers") - 1)) != NULL) {
		if (Z_TYPE_P(pvalue) == IS_ARRAY) {
			custom_headers_param = tmp_param = NULL;
			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) {
				custom_headers_param = mail_newbody_parameter();
				convert_to_string_ex(env_data);
				custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1);
				custom_headers_param->attribute = NULL;
				memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1);
				custom_headers_param->next = tmp_param;
				tmp_param = custom_headers_param;
			} ZEND_HASH_FOREACH_END();
		}
	}

	first = 1;
	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(body), data) {
		if (first) {
			first = 0;

			if (Z_TYPE_P(data) != IS_ARRAY) {
				php_error_docref(NULL, E_WARNING, "body parameter must be a non-empty array");
				RETURN_FALSE;
			}

			bod = mail_newbody();
			topbod = bod;

			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type", sizeof("type") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				bod->type = (short) Z_LVAL_P(pvalue);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "encoding", sizeof("encoding") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				bod->encoding = (short) Z_LVAL_P(pvalue);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				tmp_param = mail_newbody_parameter();
				tmp_param->value = cpystr(Z_STRVAL_P(pvalue));
				tmp_param->attribute = cpystr("CHARSET");
				tmp_param->next = bod->parameter;
				bod->parameter = tmp_param;
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type.parameters", sizeof("type.parameters") - 1)) != NULL) {
				if(Z_TYPE_P(pvalue) == IS_ARRAY) {
					disp_param = tmp_param = NULL;
					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
						disp_param = mail_newbody_parameter();
						disp_param->attribute = cpystr(ZSTR_VAL(key));
						convert_to_string_ex(disp_data);
						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
						disp_param->next = tmp_param;
						tmp_param = disp_param;
					} ZEND_HASH_FOREACH_END();
					bod->parameter = disp_param;
				}
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->subtype = cpystr(Z_STRVAL_P(pvalue));
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->id = cpystr(Z_STRVAL_P(pvalue));
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->description = cpystr(Z_STRVAL_P(pvalue));
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
				memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition", sizeof("disposition") - 1)) != NULL) {
				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
					disp_param = tmp_param = NULL;
					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
						disp_param = mail_newbody_parameter();
						disp_param->attribute = cpystr(ZSTR_VAL(key));
						convert_to_string_ex(disp_data);
						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
						disp_param->next = tmp_param;
						tmp_param = disp_param;
					} ZEND_HASH_FOREACH_END();
					bod->disposition.parameter = disp_param;
				}
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "contents.data", sizeof("contents.data") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->contents.text.data = fs_get(Z_STRLEN_P(pvalue) + 1);
				memcpy(bod->contents.text.data, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
				bod->contents.text.size = Z_STRLEN_P(pvalue);
			} else {
				bod->contents.text.data = fs_get(1);
				memcpy(bod->contents.text.data, "", 1);
				bod->contents.text.size = 0;
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "lines", sizeof("lines") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				bod->size.lines = Z_LVAL_P(pvalue);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "bytes", sizeof("bytes") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				bod->size.bytes = Z_LVAL_P(pvalue);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->md5 = cpystr(Z_STRVAL_P(pvalue));
			}
		} else if (Z_TYPE_P(data) == IS_ARRAY) {
			short type = -1;
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type", sizeof("type") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				type = (short) Z_LVAL_P(pvalue);
			}

			if (!toppart) {
				bod->nested.part = mail_newbody_part();
				mypart = bod->nested.part;
				toppart = 1;
			} else {
				mypart->next = mail_newbody_part();
				mypart = mypart->next;
			}

			bod = &mypart->body;

			if (type != TYPEMULTIPART) {
				bod->type = type;
			}

			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "encoding", sizeof("encoding") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				bod->encoding = (short) Z_LVAL_P(pvalue);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				tmp_param = mail_newbody_parameter();
				tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
				memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
				tmp_param->attribute = cpystr("CHARSET");
				tmp_param->next = bod->parameter;
				bod->parameter = tmp_param;
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type.parameters", sizeof("type.parameters") - 1)) != NULL) {
				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
					disp_param = tmp_param = NULL;
					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
						disp_param = mail_newbody_parameter();
						disp_param->attribute = cpystr(ZSTR_VAL(key));
						convert_to_string_ex(disp_data);
						disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1);
						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
						disp_param->next = tmp_param;
						tmp_param = disp_param;
					} ZEND_HASH_FOREACH_END();
					bod->parameter = disp_param;
				}
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->subtype = cpystr(Z_STRVAL_P(pvalue));
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->id = cpystr(Z_STRVAL_P(pvalue));
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->description = cpystr(Z_STRVAL_P(pvalue));
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
				memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition", sizeof("disposition") - 1)) != NULL) {
				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
					disp_param = tmp_param = NULL;
					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
						disp_param = mail_newbody_parameter();
						disp_param->attribute = cpystr(ZSTR_VAL(key));
						convert_to_string_ex(disp_data);
						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
						disp_param->next = tmp_param;
						tmp_param = disp_param;
					} ZEND_HASH_FOREACH_END();
					bod->disposition.parameter = disp_param;
				}
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "contents.data", sizeof("contents.data") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->contents.text.data = fs_get(Z_STRLEN_P(pvalue) + 1);
				memcpy(bod->contents.text.data, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
				bod->contents.text.size = Z_STRLEN_P(pvalue);
			} else {
				bod->contents.text.data = fs_get(1);
				memcpy(bod->contents.text.data, "", 1);
				bod->contents.text.size = 0;
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "lines", sizeof("lines") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				bod->size.lines = Z_LVAL_P(pvalue);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "bytes", sizeof("bytes") - 1)) != NULL) {
				convert_to_long_ex(pvalue);
				bod->size.bytes = Z_LVAL_P(pvalue);
			}
			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
				convert_to_string_ex(pvalue);
				bod->md5 = cpystr(Z_STRVAL_P(pvalue));
			}
		}
	} ZEND_HASH_FOREACH_END();

	if (first) {
		php_error_docref(NULL, E_WARNING, "body parameter must be a non-empty array");
		RETURN_FALSE;
	}

	if (bod && bod->type == TYPEMULTIPART && (!bod->nested.part || !bod->nested.part->next)) {
		php_error_docref(NULL, E_WARNING, "cannot generate multipart e-mail without components.");
		RETVAL_FALSE;
		goto done;
	}

	rfc822_encode_body_7bit(env, topbod);

	tmp = emalloc(SENDBUFLEN + 1);

	rfc822_header(tmp, env, topbod);

	/* add custom envelope headers */
	if (custom_headers_param) {
		int l = strlen(tmp) - 2, l2;
		PARAMETER *tp = custom_headers_param;

		/* remove last CRLF from tmp */
		tmp[l] = '\0';
		tempstring = emalloc(l);
		memcpy(tempstring, tmp, l);

		do {
			l2 = strlen(custom_headers_param->value);
			tempstring = erealloc(tempstring, l + l2 + CRLF_LEN + 1);
			memcpy(tempstring + l, custom_headers_param->value, l2);
			memcpy(tempstring + l + l2, CRLF, CRLF_LEN);
			l += l2 + CRLF_LEN;
		} while ((custom_headers_param = custom_headers_param->next));

		mail_free_body_parameter(&tp);

		mystring = emalloc(l + CRLF_LEN + 1);
		memcpy(mystring, tempstring, l);
		memcpy(mystring + l , CRLF, CRLF_LEN);
		mystring[l + CRLF_LEN] = '\0';

		efree(tempstring);
	} else {
		mystring = estrdup(tmp);
	}

	bod = topbod;

	if (bod && bod->type == TYPEMULTIPART) {

		/* first body part */
			part = bod->nested.part;

		/* find cookie */
			for (param = bod->parameter; param && !cookie; param = param->next) {
				if (!strcmp (param->attribute, "BOUNDARY")) {
					cookie = param->value;
				}
			}

		/* yucky default */
			if (!cookie) {
				cookie = "-";
			} else if (strlen(cookie) > (SENDBUFLEN - 2 - 2 - 2)) { /* validate cookie length -- + CRLF * 2 */
				php_error_docref(NULL, E_WARNING, "The boundary should be no longer than 4kb");
				RETVAL_FALSE;
				goto done;
			}

		/* for each part */
			do {
				t = tmp;

			/* append mini-header */
				*t = '\0';
				rfc822_write_body_header(&t, &part->body);

			/* output cookie, mini-header, and contents */
				spprintf(&tempstring, 0, "%s--%s%s%s%s", mystring, cookie, CRLF, tmp, CRLF);
				efree(mystring);
				mystring=tempstring;

				bod=&part->body;

				spprintf(&tempstring, 0, "%s%s%s", mystring, bod->contents.text.data, CRLF);
				efree(mystring);
				mystring=tempstring;
			} while ((part = part->next)); /* until done */

			/* output trailing cookie */
			spprintf(&tempstring, 0, "%s--%s--%s", mystring, cookie, CRLF);
			efree(mystring);
			mystring=tempstring;
	} else if (bod) {
		spprintf(&tempstring, 0, "%s%s%s", mystring, bod->contents.text.data, CRLF);
		efree(mystring);
		mystring=tempstring;
	} else {
		efree(mystring);
		RETVAL_FALSE;
		goto done;
	}

	RETVAL_STRING(tempstring);
	efree(tempstring);
done:
	if (tmp) {
		efree(tmp);
	}
	mail_free_body(&topbod);
	mail_free_envelope(&env);


seticc_cal(i_ctx_t * i_ctx_p, float *white, float *black, float *gamma,
           float *matrix, int num_colorants, ulong dictkey)
{
    int                     code;
    gs_color_space *        pcs;
    gs_memory_t             *mem = igs->memory;
    int                     i;
    cmm_profile_t           *cal_profile;

    /* See if the color space is in the profile cache */
    pcs = gsicc_find_cs(dictkey, igs);
    if (pcs == NULL ) {
        /* build the color space object.  Since this is cached
           in the profile cache which is a member variable
           of the graphic state, we will want to use stable
           memory here */
        code = gs_cspace_build_ICC(&pcs, NULL, mem->stable_memory);
        if (code < 0)
            return gs_rethrow(code, "building color space object");
        /* There is no alternate for this.  Perhaps we should set DeviceRGB? */
        pcs->base_space = NULL;
        /* Create the ICC profile from the CalRGB or CalGray parameters */
        cal_profile = gsicc_create_from_cal(white, black, gamma, matrix,
                                            mem->stable_memory, num_colorants);
        if (cal_profile == NULL)
            return gs_rethrow(gs_error_VMerror, "creating the cal profile failed");
        /* Assign the profile to this color space */
        code = gsicc_set_gscs_profile(pcs, cal_profile, mem->stable_memory);
        /* profile is created with ref count of 1, gsicc_set_gscs_profile()
         * increments the ref count, so we need to decrement it here.
         */
        rc_decrement(cal_profile, "seticc_cal");
        if (code < 0)
            return gs_rethrow(code, "installing the cal profile");
        for (i = 0; i < num_colorants; i++) {
            pcs->cmm_icc_profile_data->Range.ranges[i].rmin = 0;
            pcs->cmm_icc_profile_data->Range.ranges[i].rmax = 1;
        }
        /* Add the color space to the profile cache */
        gsicc_add_cs(igs, pcs,dictkey);
    }
    /* Set the color space.  We are done.  */
    code = gs_setcolorspace(igs, pcs);
    return code;
}


zcurrentcacheparams(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    uint params[3];

    params[0] = gs_currentcachesize(ifont_dir);
    params[1] = gs_currentcachelower(ifont_dir);
    params[2] = gs_currentcacheupper(ifont_dir);
    push(4);
    make_mark(op - 3);
    make_uint_array(op - 2, params, 3);
    return 0;
}


build_gs_primitive_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
                        font_type ftype, gs_memory_type_ptr_t pstype,
                        const build_proc_refs * pbuild,
                        build_font_options_t options)
{
    ref *pcharstrings = 0;
    ref CharStrings;
    gs_font_base *pfont;
    font_data *pdata;
    int code;

    if (dict_find_string(op, "CharStrings", &pcharstrings) <= 0) {
        if (!(options & bf_CharStrings_optional))
            return_error(gs_error_invalidfont);
    } else {
        ref *ignore;

        if (!r_has_type(pcharstrings, t_dictionary))
            return_error(gs_error_invalidfont);
        if ((options & bf_notdef_required) != 0 &&
            dict_find_string(pcharstrings, ".notdef", &ignore) <= 0
            )
            return_error(gs_error_invalidfont);
        /*
         * Since build_gs_simple_font may resize the dictionary and cause
         * pointers to become invalid, save CharStrings.
         */
        CharStrings = *pcharstrings;
    }
    code = build_gs_outline_font(i_ctx_p, op, ppfont, ftype, pstype, pbuild,
                                 options, build_gs_simple_font);
    if (code != 0)
        return code;
    pfont = *ppfont;
    pdata = pfont_data(pfont);
    if (pcharstrings)
        ref_assign(&pdata->CharStrings, &CharStrings);
    else
        make_null(&pdata->CharStrings);
    /* Check that the UniqueIDs match.  This is part of the */
    /* Adobe protection scheme, but we may as well emulate it. */
    if (uid_is_valid(&pfont->UID) &&
        !dict_check_uid_param(op, &pfont->UID)
        )
        uid_set_invalid(&pfont->UID);
    if (uid_is_valid(&pfont->UID)) {
        const gs_font *pfont0 = (const gs_font *)pfont;

        code = gs_font_find_similar(ifont_dir, &pfont0,
                       font_with_same_UID_and_another_metrics);
        if (code < 0)
            return code; /* Must not happen. */
        if (code)
            uid_set_invalid(&pfont->UID);
    }
    return 0;
}


zfont_get_to_unicode_map(gs_font_dir *dir)
{
    const gs_unicode_decoder *pud = (gs_unicode_decoder *)dir->glyph_to_unicode_table;

    return (pud == NULL ? NULL : &pud->data);
}


zcurrentopacityalpha(i_ctx_t *i_ctx_p)
{
    return current_float_value(i_ctx_p, gs_currentopacityalpha);
}


build_gs_simple_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
                     font_type ftype, gs_memory_type_ptr_t pstype,
                     const build_proc_refs * pbuild,
                     build_font_options_t options)
{
    double bbox[4];
    gs_uid uid;
    int code;
    gs_font_base *pfont;
    uint space = ialloc_space(idmemory);

    code = font_bbox_param(imemory, op, bbox);
    if (code < 0)
        return code;
    /*
     * Make sure that we allocate uid
     * in the same VM as the font dictionary
     * (see build_gs_sub_font).
     */
    ialloc_set_space(idmemory, r_space(op));
    code = dict_uid_param(op, &uid, 0, imemory, i_ctx_p);
    ialloc_set_space(idmemory, space);
    if (code < 0)
        return code;
    if ((options & bf_UniqueID_ignored) && uid_is_UniqueID(&uid))
        uid_set_invalid(&uid);
    code = build_gs_font(i_ctx_p, op, (gs_font **) ppfont, ftype, pstype,
                         pbuild, options);
    if (code != 0)		/* invalid or scaled font */
        return code;
    pfont = *ppfont;
    pfont->procs.init_fstack = gs_default_init_fstack;
    pfont->procs.define_font = gs_no_define_font;
    pfont->procs.decode_glyph = gs_font_map_glyph_to_unicode;
    pfont->procs.make_font = zbase_make_font;
    pfont->procs.next_char_glyph = gs_default_next_char_glyph;
    pfont->FAPI = 0;
    pfont->FAPI_font_data = 0;
    init_gs_simple_font(pfont, bbox, &uid);
    lookup_gs_simple_font_encoding(pfont);
    get_GlyphNames2Unicode(i_ctx_p, (gs_font *)pfont, op);
    return 0;
}


currentbasecolor_cont(i_ctx_t *i_ctx_p)
{
    ref arr, *parr = &arr;
    es_ptr ep = esp;
    int i, code = 0, stage, base, cont=1, stack_depth = 0, CIESubst=0;
    unsigned int depth;
    PS_colour_space_t *obj;

    stack_depth = (int)ep[-4].value.intval;
    base = (int)ep[-3].value.intval;
    depth = (unsigned int)ep[-2].value.intval;
    stage = (int)ep[-1].value.intval;

    /* This shouldn't be possible, all the procedures which call this should
     * set the depth to at *least* 1.
     */
    if (depth < 1) {
        esp -= 7;
        return_error(gs_error_unknownerror);
    }

    /* If we get a continuation from a sub-procedure, we will want to come back
     * here afterward, to do any remaining stages. We need to set up for that now.
     * so that our continuation is ahead of the sub-proc's continuation.
     */
    check_estack(1);
    /* The push_op_estack macro increments esp before use, so we don't need to */
    push_op_estack(currentbasecolor_cont);

    while (code == 0 && cont) {
        ref_assign(&arr, ep);
        parr = &arr;
        /* Run along the nested color spaces until we get to the lowest one
         * that we haven't yet processed (given by 'depth')
         */
        for (i = 0;i < depth;i++) {
            code = get_space_object(i_ctx_p, parr, &obj);
            if (code < 0) {
                esp -= 7;
                return code;
            }

            if (i < (depth - 1)) {
                if (!obj->alternateproc) {
                    esp -= 7;
                    return_error(gs_error_typecheck);
                }
                code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
                if (code < 0) {
                    esp -= 7;
                    return code;
                }
            }
        }

        code = obj->basecolorproc(i_ctx_p, parr, base, &stage, &cont, &stack_depth);
        make_int(&ep[-4], stack_depth);
        make_int(&ep[-1], stage);
        if (code > 0)
            return code;
        /* Completed that space, increment the 'depth' */
        make_int(&ep[-2], ++depth);
    }
    if (code <= 0) {
        /* Remove our next continuation and our data */
        esp -= 7;
        code = o_pop_estack;
    }
    return code;
}


zbuildcolorrendering1(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    gs_memory_t *mem = gs_gstate_memory(igs);
    int code;
    es_ptr ep = esp;
    gs_cie_render *pcrd;
    ref_cie_render_procs procs;

    check_read_type(*op, t_dictionary);
    check_dict_read(*op);
    code = gs_cie_render1_build(&pcrd, mem, ".buildcolorrendering1");
    if (code < 0)
        return code;
    code = zcrd1_params(op, pcrd, &procs, mem);
    if (code < 0 ) {
        rc_free_struct(pcrd, ".buildcolorrendering1");
        esp = ep;
        return code;
    }
    /****** FIX refct ******/
    /*rc_decrement(pcrd, ".buildcolorrendering1"); *//* build sets rc = 1 */
    istate->colorrendering.dict = *op;
    make_istruct_new(op, a_readonly, pcrd);
    return (esp == ep ? 0 : o_push_estack);
}


font_restore(const alloc_save_t * save)
{

    gs_memory_t *smem = gs_save_any_memory(save);
    gs_font_dir *pdir = smem->gs_lib_ctx->font_dir;
    int code;

    if (pdir == 0)		/* not initialized yet */
        return 0;

    /* Purge original (unscaled) fonts. */

    {
        gs_font *pfont;

otop:
        for (pfont = pdir->orig_fonts; pfont != 0;
             pfont = pfont->next
            ) {
            if (alloc_is_since_save((char *)pfont, save)) {
                code = gs_purge_font(pfont);
                if (code < 0)
                    return code;
                goto otop;
            }
        }
    }

    /* Purge cached scaled fonts. */

    {
        gs_font *pfont;

top:
        for (pfont = pdir->scaled_fonts; pfont != 0;
             pfont = pfont->next
            ) {
            if (alloc_is_since_save((char *)pfont, save)) {
                code = gs_purge_font(pfont);
                if (code < 0)
                    return code;
                goto top;
            }
        }
    }

    /* Purge xfonts and uncached scaled fonts. */

    {
        cached_fm_pair *pair;
        uint n;

        for (pair = pdir->fmcache.mdata, n = pdir->fmcache.mmax;
             n > 0; pair++, n--
            )
            if (!fm_pair_is_free(pair)) {
#if 0
                /* We disabled this code portion because
                   gx_add_fm_pair now copied xvalues
                   into a stable memory.
                 */
                if ((uid_is_XUID(&pair->UID) &&
                     alloc_is_since_save((char *)pair->UID.xvalues,
                                         save))
                    ) {
                    code = gs_purge_fm_pair(pdir, pair, 0);
                    if (code < 0)
                        return code;
                    continue;
                }
#endif
                if (pair->font != 0 &&
                    alloc_is_since_save((char *)pair->font, save)
                    ) {
                    if (!uid_is_valid(&pair->UID))
                        gs_clean_fm_pair(pdir, pair);
                    /* Don't discard pairs with a surviving UID. */
                    pair->font = 0;
                }
                if (pair->xfont != 0 &&
                    alloc_is_since_save((char *)pair->xfont, save)
                    ) {
                    code = gs_purge_fm_pair(pdir, pair, 1);
                    if (code < 0)
                        return code;
                }
            }
    }

    /* Purge characters with names about to be removed. */
    /* We only need to do this if any new names have been created */
    /* since the save. */

    if (alloc_any_names_since_save(save))
        gx_purge_selected_cached_chars(pdir, purge_if_name_removed,
                                       (void *)save);
    return 0;
}


rect_param(gs_rect *prect, os_ptr op)
{
    double coords[4];
    int code = num_params(op, 4, coords);

    if (code < 0)
        return code;
    prect->p.x = coords[0], prect->p.y = coords[1];
    prect->q.x = coords[2], prect->q.y = coords[3];
    return 0;
}


build_gs_outline_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
                      font_type ftype, gs_memory_type_ptr_t pstype,
                      const build_proc_refs * pbuild,
                      build_font_options_t options,
                      build_base_font_proc_t build_base_font)
{
    int painttype;
    float strokewidth;
    gs_font_base *pfont;
    int code = dict_int_param(op, "PaintType", 0, 3, 0, &painttype);

    if (code < 0)
        return code;
    code = dict_float_param(op, "StrokeWidth", 0.0, &strokewidth);
    if (code < 0)
        return code;
    code = build_base_font(i_ctx_p, op, ppfont, ftype, pstype, pbuild,
                           options);
    if (code != 0)
        return code;
    pfont = *ppfont;
    pfont->PaintType = painttype;
    pfont->StrokeWidth = strokewidth;
    return 0;
}


zsetstrokeconstantalpha(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    double value;

    if (real_param(op, &value) < 0)
        return_op_typecheck(op);

    gs_setstrokeconstantalpha(igs, (float)value);
    pop(1);
    return 0;
}


zcurrentcolorrendering(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;

    push(1);
    *op = istate->colorrendering.dict;
    return 0;
}


ztpqr_scale_wb0(i_ctx_t *i_ctx_p)
{
    return ztpqr_scale_wb_common(i_ctx_p, 3);
}


ztpqr_scale_wb2(i_ctx_t *i_ctx_p)
{
    return ztpqr_scale_wb_common(i_ctx_p, 5);
}


static int iccdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
{
    int components, i, code = 0;
    ref *tempref, ICCdict, valref;

    code = array_get(imemory, space, 1, &ICCdict);
    if (code < 0)
        return code;
    code = dict_find_string(&ICCdict, "N", &tempref);
    if (code < 0)
        return code;
    if (code == 0)
        return gs_note_error(gs_error_undefined);
    if (!r_has_type(tempref, t_integer))
        return gs_note_error(gs_error_typecheck);

    components = tempref->value.intval;
    code = dict_find_string(&ICCdict, "Range", &tempref);
    if (code > 0 && !r_has_type(tempref, t_null)) {
        for (i=0;i<components * 2;i++) {
            code = array_get(imemory, tempref, i, &valref);
            if (code < 0)
                return code;
            if (r_has_type(&valref, t_integer))
                ptr[i * 2] = (float)valref.value.intval;
            else
                ptr[i * 2] = valref.value.realval;
        }
    } else {
        for (i=0;i<components;i++) {
            ptr[i * 2] = 0;
            ptr[(i * 2) + 1] = 1;
        }
    }
    return 0;
}


static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
{
	ssize_t bytes_copied = 0;
	size_t bytes_total = copy->cp_count;
	u64 src_pos = copy->cp_src_pos;
	u64 dst_pos = copy->cp_dst_pos;

	do {
		if (kthread_should_stop())
			break;
		bytes_copied = nfsd_copy_file_range(copy->file_src, src_pos,
				copy->file_dst, dst_pos, bytes_total);
		if (bytes_copied <= 0)
			break;
		bytes_total -= bytes_copied;
		copy->cp_res.wr_bytes_written += bytes_copied;
		src_pos += bytes_copied;
		dst_pos += bytes_copied;
	} while (bytes_total > 0 && !copy->cp_synchronous);
	return bytes_copied;
}


nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		union nfsd4_op_u *u)
{
	__be32 status;

	fh_put(&cstate->current_fh);
	status = exp_pseudoroot(rqstp, &cstate->current_fh);
	return status;
}


static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
				 struct rpc_task *task)
{
	return 1;
}


nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	       union nfsd4_op_u *u)
{
	return nfsd4_fallocate(rqstp, cstate, &u->allocate, 0);
}


void nfsd4_shutdown_copy(struct nfs4_client *clp)
{
	struct nfsd4_copy *copy;

	while ((copy = nfsd4_get_copy(clp)) != NULL)
		nfsd4_stop_copy(copy);
}


nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     union nfsd4_op_u *u)
{
	struct nfsd4_commit *commit = &u->commit;

	gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp));
	return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
			     commit->co_count);
}


static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
{
	dst->cp_src_pos = src->cp_src_pos;
	dst->cp_dst_pos = src->cp_dst_pos;
	dst->cp_count = src->cp_count;
	dst->cp_synchronous = src->cp_synchronous;
	memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res));
	memcpy(&dst->fh, &src->fh, sizeof(src->fh));
	dst->cp_clp = src->cp_clp;
	dst->file_dst = get_file(src->file_dst);
	dst->file_src = get_file(src->file_src);
	memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
}


nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    union nfsd4_op_u *u)
{
	u->getfh = &cstate->current_fh;
	return nfs_ok;
}


gx_dc_pattern2_save_dc(
    const gx_device_color * pdevc,
    gx_device_color_saved * psdc )
{
    gs_pattern2_instance_t * pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;

    psdc->type = pdevc->type;
    psdc->colors.pattern2.id = pinst->pattern_id;
    psdc->colors.pattern2.shfill = pinst->shfill;
}


static void sock_ofree(struct sk_buff *skb)
{
	struct sock *sk = skb->sk;

	atomic_sub(skb->truesize, &sk->sk_omem_alloc);
}


int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind)
{
	struct proto *prot = sk->sk_prot;
	long allocated = sk_memory_allocated_add(sk, amt);

	if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
	    !mem_cgroup_charge_skmem(sk->sk_memcg, amt))
		goto suppress_allocation;

	/* Under limit. */
	if (allocated <= sk_prot_mem_limits(sk, 0)) {
		sk_leave_memory_pressure(sk);
		return 1;
	}

	/* Under pressure. */
	if (allocated > sk_prot_mem_limits(sk, 1))
		sk_enter_memory_pressure(sk);

	/* Over hard limit. */
	if (allocated > sk_prot_mem_limits(sk, 2))
		goto suppress_allocation;

	/* guarantee minimum buffer size under pressure */
	if (kind == SK_MEM_RECV) {
		if (atomic_read(&sk->sk_rmem_alloc) < prot->sysctl_rmem[0])
			return 1;

	} else { /* SK_MEM_SEND */
		if (sk->sk_type == SOCK_STREAM) {
			if (sk->sk_wmem_queued < prot->sysctl_wmem[0])
				return 1;
		} else if (refcount_read(&sk->sk_wmem_alloc) <
			   prot->sysctl_wmem[0])
				return 1;
	}

	if (sk_has_memory_pressure(sk)) {
		int alloc;

		if (!sk_under_memory_pressure(sk))
			return 1;
		alloc = sk_sockets_allocated_read_positive(sk);
		if (sk_prot_mem_limits(sk, 2) > alloc *
		    sk_mem_pages(sk->sk_wmem_queued +
				 atomic_read(&sk->sk_rmem_alloc) +
				 sk->sk_forward_alloc))
			return 1;
	}

suppress_allocation:

	if (kind == SK_MEM_SEND && sk->sk_type == SOCK_STREAM) {
		sk_stream_moderate_sndbuf(sk);

		/* Fail only if socket is _under_ its sndbuf.
		 * In this case we cannot block, so that we have to fail.
		 */
		if (sk->sk_wmem_queued + size >= sk->sk_sndbuf)
			return 1;
	}

	trace_sock_exceed_buf_limit(sk, prot, allocated);

	sk_memory_allocated_sub(sk, amt);

	if (mem_cgroup_sockets_enabled && sk->sk_memcg)
		mem_cgroup_uncharge_skmem(sk->sk_memcg, amt);

	return 0;
}


void __sk_mem_reduce_allocated(struct sock *sk, int amount)
{
	sk_memory_allocated_sub(sk, amount);

	if (mem_cgroup_sockets_enabled && sk->sk_memcg)
		mem_cgroup_uncharge_skmem(sk->sk_memcg, amount);

	if (sk_under_memory_pressure(sk) &&
	    (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)))
		sk_leave_memory_pressure(sk);
}


    ExifData::const_iterator flashBias(const ExifData& ed)
    {
        static const char* keys[] = {
            "Exif.CanonSi.FlashBias",
            "Exif.Panasonic.FlashBias",
            "Exif.Olympus.FlashBias",
            "Exif.OlympusCs.FlashExposureComp",
            "Exif.Minolta.FlashExposureComp",
            "Exif.SonyMinolta.FlashExposureComp",
            "Exif.Sony1.FlashExposureComp",
            "Exif.Sony2.FlashExposureComp"
        };
        return findMetadatum(ed, keys, EXV_COUNTOF(keys));
    }


    ExifData::const_iterator lensName(const ExifData& ed)
    {
        static const char* keys[] = {
            // Exif.Canon.LensModel only reports focal length.
            // Try Exif.CanonCs.LensType first.
            "Exif.CanonCs.LensType",
            "Exif.Photo.LensModel",
            "Exif.NikonLd1.LensIDNumber",
            "Exif.NikonLd2.LensIDNumber",
            "Exif.NikonLd3.LensIDNumber",
            "Exif.Pentax.LensType",
            "Exif.PentaxDng.LensType",
            "Exif.Minolta.LensID",
            "Exif.SonyMinolta.LensID",
            "Exif.Sony1.LensID",
            "Exif.Sony2.LensID",
            "Exif.OlympusEq.LensType",
            "Exif.Panasonic.LensType",
            "Exif.Samsung2.LensType"
        };
        return findMetadatum(ed, keys, EXV_COUNTOF(keys));
    }


addEPollSock(epolld_type_t typ, void *ptr, int sock, epolld_t **pEpd)
{
	DEFiRet;
	epolld_t *epd = NULL;

	CHKmalloc(epd = calloc(1, sizeof(epolld_t)));
	epd->typ = typ;
	epd->ptr = ptr;
	epd->sock = sock;
	*pEpd = epd;
	epd->ev.events = EPOLLIN|EPOLLET|EPOLLONESHOT;
	epd->ev.data.ptr = (void*) epd;

	if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &(epd->ev)) != 0) {
		char errStr[1024];
		int eno = errno;
		errmsg.LogError(0, RS_RET_EPOLL_CTL_FAILED, "os error (%d) during epoll ADD: %s",
			        eno, rs_strerror_r(eno, errStr, sizeof(errStr)));
		ABORT_FINALIZE(RS_RET_EPOLL_CTL_FAILED);
	}

	DBGPRINTF("imptcp: added socket %d to epoll[%d] set\n", sock, epollfd);

finalize_it:
	if(iRet != RS_RET_OK) {
		if (epd != NULL) {
			errmsg.LogError(0, RS_RET_INTERNAL_ERROR, "error: could not initialize mutex for ptcp "
			"connection for socket: %d", sock);
		}
		free(epd);
	}
	RETiRet;
}


	for(inst = pModConf->root ; inst != NULL ; ) {
		free(inst->pszBindPort);
		free(inst->pszBindPath);
		free(inst->pszBindAddr);
		free(inst->pszBindRuleset);
		free(inst->pszInputName);
		free(inst->dfltTZ);
		del = inst;
		inst = inst->next;
		free(del);
	}


	if(Debug) {
		dbgprintf("module (global) param blk for imptcp:\n");
		cnfparamsPrint(&modpblk, pvals);
	}


startWorkerPool(void)
{
	int i;
	wrkrRunning = 0;
	DBGPRINTF("imptcp: starting worker pool, %d workers\n", runModConf->wrkrMax);
    wrkrInfo = calloc(runModConf->wrkrMax, sizeof(struct wrkrInfo_s));
    if (wrkrInfo == NULL) {
        DBGPRINTF("imptcp: worker-info array allocation failed.\n");
        return;
    }
	for(i = 0 ; i < runModConf->wrkrMax ; ++i) {
		/* init worker info structure! */
		wrkrInfo[i].numCalled = 0;
		pthread_create(&wrkrInfo[i].tid, &wrkrThrdAttr, wrkr, &(wrkrInfo[i]));
	}

}


	if((pvals = nvlstGetParams(lst, &inppblk, NULL)) == NULL) {
		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
	}


closeSess(ptcpsess_t *pSess)
{
	int sock;
	DEFiRet;

	if(pSess->compressionMode >= COMPRESS_STREAM_ALWAYS)
		doZipFinish(pSess);

	sock = pSess->sock;
	CHKiRet(removeEPollSock(sock, pSess->epd));
	close(sock);

	pthread_mutex_lock(&pSess->pLstn->pSrv->mutSessLst);
	/* finally unlink session from structures */
	if(pSess->next != NULL)
		pSess->next->prev = pSess->prev;
	if(pSess->prev == NULL) {
		/* need to update root! */
		pSess->pLstn->pSrv->pSess = pSess->next;
	} else {
		pSess->prev->next = pSess->next;
	}
	pthread_mutex_unlock(&pSess->pLstn->pSrv->mutSessLst);

	/* unlinked, now remove structure */
	destructSess(pSess);

finalize_it:
	DBGPRINTF("imptcp: session on socket %d closed with iRet %d.\n", sock, iRet);
	RETiRet;
}


static void dns_free_resolution(struct dns_resolution *resolution)
{
	struct dns_requester *req, *reqback;

	/* clean up configuration */
	dns_reset_resolution(resolution);
	resolution->hostname_dn = NULL;
	resolution->hostname_dn_len = 0;

	list_for_each_entry_safe(req, reqback, &resolution->requesters, list) {
		LIST_DEL(&req->list);
		req->resolution = NULL;
	}

	LIST_DEL(&resolution->list);
	pool_free(dns_resolution_pool, resolution);
}


static void dns_reset_resolution(struct dns_resolution *resolution)
{
	/* update resolution status */
	resolution->step            = RSLV_STEP_NONE;
	resolution->try             = 0;
	resolution->last_resolution = now_ms;
	resolution->nb_queries      = 0;
	resolution->nb_responses    = 0;
	resolution->query_type      = resolution->prefered_query_type;

	/* clean up query id */
	eb32_delete(&resolution->qid);
	resolution->query_id = 0;
	resolution->qid.key   = 0;
}


static void dns_deinit(void)
{
	struct dns_resolvers  *resolvers, *resolversback;
	struct dns_nameserver *ns, *nsback;
	struct dns_resolution *res, *resback;
	struct dns_requester  *req, *reqback;
	struct dns_srvrq      *srvrq, *srvrqback;

	list_for_each_entry_safe(resolvers, resolversback, &dns_resolvers, list) {
		list_for_each_entry_safe(ns, nsback, &resolvers->nameservers, list) {
			free(ns->id);
			free((char *)ns->conf.file);
			if (ns->dgram && ns->dgram->t.sock.fd != -1)
				fd_delete(ns->dgram->t.sock.fd);
			free(ns->dgram);
			LIST_DEL(&ns->list);
			free(ns);
		}

		list_for_each_entry_safe(res, resback, &resolvers->resolutions.curr, list) {
			list_for_each_entry_safe(req, reqback, &res->requesters, list) {
				LIST_DEL(&req->list);
				free(req);
			}
			dns_free_resolution(res);
		}

		list_for_each_entry_safe(res, resback, &resolvers->resolutions.wait, list) {
			list_for_each_entry_safe(req, reqback, &res->requesters, list) {
				LIST_DEL(&req->list);
				free(req);
			}
			dns_free_resolution(res);
		}

		free(resolvers->id);
		free((char *)resolvers->conf.file);
		task_delete(resolvers->t);
		task_free(resolvers->t);
		LIST_DEL(&resolvers->list);
		free(resolvers);
	}

	list_for_each_entry_safe(srvrq, srvrqback, &dns_srvrq_list, list) {
		free(srvrq->name);
		free(srvrq->hostname_dn);
		LIST_DEL(&srvrq->list);
		free(srvrq);
	}
}


static inline unsigned short dns_response_get_query_id(unsigned char *resp)
{
	return resp[0] * 256 + resp[1];
}


static int dns_send_query(struct dns_resolution *resolution)
{
	struct dns_resolvers  *resolvers = resolution->resolvers;
	struct dns_nameserver *ns;

	list_for_each_entry(ns, &resolvers->nameservers, list) {
		int fd = ns->dgram->t.sock.fd;
		if (fd == -1) {
			if (dns_connect_namesaver(ns) == -1)
				continue;
			fd = ns->dgram->t.sock.fd;
			resolvers->nb_nameservers++;
		}
		fd_want_send(fd);
	}

	/* Update resolution */
	resolution->nb_queries   = 0;
	resolution->nb_responses = 0;
	resolution->last_query   = now_ms;

	/* Push the resolution at the end of the active list */
	LIST_DEL(&resolution->list);
	LIST_ADDQ(&resolvers->resolutions.curr, &resolution->list);
	return 0;
}


static struct task *dns_process_resolvers(struct task *t, void *context, unsigned short state)
{
	struct dns_resolvers  *resolvers = context;
	struct dns_resolution *res, *resback;
	int exp;

	HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);

	/* Handle all expired resolutions from the active list */
	list_for_each_entry_safe(res, resback, &resolvers->resolutions.curr, list) {
		/* When we find the first resolution in the future, then we can
		 * stop here */
		exp = tick_add(res->last_query, resolvers->timeout.retry);
		if (!tick_is_expired(exp, now_ms))
			break;

		/* If current resolution has been tried too many times and
		 * finishes in timeout we update its status and remove it from
		 * the list */
		if (!res->try) {
			struct dns_requester *req;

			/* Notify the result to the requesters */
			if (!res->nb_responses)
				res->status = RSLV_STATUS_TIMEOUT;
			list_for_each_entry(req, &res->requesters, list)
				req->requester_error_cb(req, res->status);

			/* Clean up resolution info and remove it from the
			 * current list */
			dns_reset_resolution(res);
			LIST_DEL(&res->list);
			LIST_ADDQ(&resolvers->resolutions.wait, &res->list);
		}
		else {
			/* Otherwise resend the DNS query and requeue the resolution */
			if (!res->nb_responses || res->prefered_query_type != res->query_type) {
				/* No response received (a real timeout) or fallback already done */
				res->query_type = res->prefered_query_type;
				res->try--;
			}
			else {
				/* Fallback from A to AAAA or the opposite and re-send
				 * the resolution immediately. try counter is not
				 * decremented. */
				if (res->prefered_query_type == DNS_RTYPE_A)
					res->query_type = DNS_RTYPE_AAAA;
				else if (res->prefered_query_type == DNS_RTYPE_AAAA)
					res->query_type = DNS_RTYPE_A;
				else
					res->try--;
			}
			dns_send_query(res);
		}
	}

	/* Handle all resolutions in the wait list */
	list_for_each_entry_safe(res, resback, &resolvers->resolutions.wait, list) {
		exp = tick_add(res->last_resolution, dns_resolution_timeout(res));
		if (tick_isset(res->last_resolution) && !tick_is_expired(exp, now_ms))
			continue;

		if (dns_run_resolution(res) != 1) {
			res->last_resolution = now_ms;
			LIST_DEL(&res->list);
			LIST_ADDQ(&resolvers->resolutions.wait, &res->list);
		}
	}

	dns_update_resolvers_timeout(resolvers);
	HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
	return t;
}


sg_common_write(Sg_fd * sfp, Sg_request * srp,
		unsigned char *cmnd, int timeout, int blocking)
{
	int k, data_dir, at_head;
	Sg_device *sdp = sfp->parentdp;
	sg_io_hdr_t *hp = &srp->header;

	srp->data.cmd_opcode = cmnd[0];	/* hold opcode of command */
	hp->status = 0;
	hp->masked_status = 0;
	hp->msg_status = 0;
	hp->info = 0;
	hp->host_status = 0;
	hp->driver_status = 0;
	hp->resid = 0;
	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
			"sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
			(int) cmnd[0], (int) hp->cmd_len));

	k = sg_start_req(srp, cmnd);
	if (k) {
		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
			"sg_common_write: start_req err=%d\n", k));
		sg_finish_rem_req(srp);
		return k;	/* probably out of space --> ENOMEM */
	}
	if (atomic_read(&sdp->detaching)) {
		if (srp->bio) {
			if (srp->rq->cmd != srp->rq->__cmd)
				kfree(srp->rq->cmd);

			blk_end_request_all(srp->rq, -EIO);
			srp->rq = NULL;
		}

		sg_finish_rem_req(srp);
		return -ENODEV;
	}

	switch (hp->dxfer_direction) {
	case SG_DXFER_TO_FROM_DEV:
	case SG_DXFER_FROM_DEV:
		data_dir = DMA_FROM_DEVICE;
		break;
	case SG_DXFER_TO_DEV:
		data_dir = DMA_TO_DEVICE;
		break;
	case SG_DXFER_UNKNOWN:
		data_dir = DMA_BIDIRECTIONAL;
		break;
	default:
		data_dir = DMA_NONE;
		break;
	}
	hp->duration = jiffies_to_msecs(jiffies);
	if (hp->interface_id != '\0' &&	/* v3 (or later) interface */
	    (SG_FLAG_Q_AT_TAIL & hp->flags))
		at_head = 0;
	else
		at_head = 1;

	srp->rq->timeout = timeout;
	kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
	blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
			      srp->rq, at_head, sg_rq_end_io);
	return 0;
}