Beispiel #1
0
/**
 * Dispatches an AFC packet over a client.
 * 
 * @param client The client to send data through.
 * @param operation The operation to perform.
 * @param data The data to send together with the header.
 * @param data_length The length of the data to send with the header.
 * @param payload The data to send after the header has been sent.
 * @param payload_length The length of data to send after the header.
 * @param bytes_sent The total number of bytes actually sent.
 *
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 */
static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, const char *data, uint32_t data_length, const char* payload, uint32_t payload_length, uint32_t *bytes_sent)
{
	uint32_t sent = 0;

	if (!client || !client->parent || !client->afc_packet)
		return AFC_E_INVALID_ARG;

	*bytes_sent = 0;

	if (!data || !data_length)
		data_length = 0;
	if (!payload || !payload_length)
		payload_length = 0;

	client->afc_packet->packet_num++;
	client->afc_packet->operation = operation;
	client->afc_packet->entire_length = sizeof(AFCPacket) + data_length + payload_length;
	client->afc_packet->this_length = sizeof(AFCPacket) + data_length;

	debug_info("packet length = %i", client->afc_packet->this_length);

	debug_buffer((char*)client->afc_packet, sizeof(AFCPacket));

	/* send AFC packet header */
	AFCPacket_to_LE(client->afc_packet);
	sent = 0;
	service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket), &sent);
	AFCPacket_from_LE(client->afc_packet);
	*bytes_sent += sent;
	if (sent < sizeof(AFCPacket)) {
		return AFC_E_SUCCESS;
	}

	/* send AFC packet data (if there's data to send) */
	sent = 0;
	if (data_length > 0) {
		debug_info("packet data follows");
		debug_buffer(data, data_length);
		service_send(client->parent, data, data_length, &sent);
	}
	*bytes_sent += sent;
	if (sent < data_length) {
		return AFC_E_SUCCESS;
	}

	sent = 0;
	if (payload_length > 0) {
		debug_info("packet payload follows");
		debug_buffer(payload, payload_length);
		service_send(client->parent, payload, payload_length, &sent);
	}
	*bytes_sent += sent;
	if (sent < payload_length) {
		return AFC_E_SUCCESS;
	}

	return AFC_E_SUCCESS;
}
Beispiel #2
0
static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg,
				  int nmsgs)
{
	struct sandbox_i2c_flash *priv = dev_get_priv(emul);
	uint offset = 0;

	debug("\n%s\n", __func__);
	debug_buffer(0, priv->data, 1, 16, 0);
	for (; nmsgs > 0; nmsgs--, msg++) {
		struct sandbox_i2c_flash_plat_data *plat =
				dev_get_platdata(emul);
		int len;
		u8 *ptr;

		if (!plat->size)
			return -ENODEV;
		if (msg->addr + msg->len > plat->size) {
			debug("%s: Address %x, len %x is outside range 0..%x\n",
			      __func__, msg->addr, msg->len, plat->size);
			return -EINVAL;
		}
		len = msg->len;
		debug("   %s: msg->len=%d",
		      msg->flags & I2C_M_RD ? "read" : "write",
		      msg->len);
		if (msg->flags & I2C_M_RD) {
			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
				len = 1;
			debug(", offset %x, len %x: ", offset, len);
			memcpy(msg->buf, priv->data + offset, len);
			memset(msg->buf + len, '\xff', msg->len - len);
			debug_buffer(0, msg->buf, 1, msg->len, 0);
		} else if (len >= plat->offset_len) {
			int i;

			ptr = msg->buf;
			for (i = 0; i < plat->offset_len; i++, len--)
				offset = (offset << 8) | *ptr++;
			debug(", set offset %x: ", offset);
			debug_buffer(0, msg->buf, 1, msg->len, 0);
			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
				len = min(len, 1);

			/* For testing, map offsets into our limited buffer */
			for (i = 24; i > 0; i -= 8) {
				if (offset > (1 << i)) {
					offset = (offset >> i) |
						(offset & ((1 << i) - 1));
					offset += i;
				}
			}
			memcpy(priv->data + offset, ptr, len);
		}
Beispiel #3
0
void debug_buffers(FILE *fp, readers_t *files)
{
    int i;
    for (i=0; i<files->nreaders; i++)
        debug_buffer(fp, &files->readers[i]);
    fprintf(fp,"\n");
}
Beispiel #4
0
static int sandbox_i2c_rtc_xfer(struct udevice *emul, struct i2c_msg *msg,
				int nmsgs)
{
	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
	uint offset = 0;
	int ret;

	debug("\n%s\n", __func__);
	ret = sandbox_i2c_rtc_prepare_read(emul);
	if (ret)
		return ret;
	for (; nmsgs > 0; nmsgs--, msg++) {
		int len;
		u8 *ptr;

		len = msg->len;
		debug("   %s: msg->len=%d",
		      msg->flags & I2C_M_RD ? "read" : "write",
		      msg->len);
		if (msg->flags & I2C_M_RD) {
			debug(", offset %x, len %x: ", offset, len);

			/* Read the register */
			memcpy(msg->buf, plat->reg + offset, len);
			memset(msg->buf + len, '\xff', msg->len - len);
			debug_buffer(0, msg->buf, 1, msg->len, 0);
		} else if (len >= 1) {
			ptr = msg->buf;
			offset = *ptr++ & (REG_COUNT - 1);
			len--;
			debug(", set offset %x: ", offset);
			debug_buffer(0, msg->buf, 1, msg->len, 0);

			/* Write the register */
			memcpy(plat->reg + offset, ptr, len);
			if (offset == REG_RESET)
				reset_time(emul);
		}
	}
	ret = sandbox_i2c_rtc_complete_write(emul);
	if (ret)
		return ret;

	return 0;
}
void debug_buffers(FILE *fp, bcf_srs_t *files)
{
    int i;
    for (i=0; i<files->nreaders; i++)
    {
        fprintf(fp, "has_line: %d\t%s\n", bcf_sr_has_line(files,i),files->readers[i].fname);
        debug_buffer(fp, &files->readers[i]);
    }
    fprintf(fp,"\n");
}
Beispiel #6
0
/**
 * Locks or unlocks a file on the device. 
 *
 * makes use of flock on the device, see
 * http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/flock.2.html
 *
 * @param client The client to lock the file with.
 * @param handle File handle of a previously opened file.
 * @param operation the lock or unlock operation to perform, this is one of
 *        AFC_LOCK_SH (shared lock), AFC_LOCK_EX (exclusive lock),
 *        or AFC_LOCK_UN (unlock).
 */
afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
{
	char *buffer = (char *)malloc(16);
	uint32_t bytes = 0;
	uint64_t op = htole64(operation);
	afc_error_t ret = AFC_E_UNKNOWN_ERROR;

	if (!client || (handle == 0))
		return AFC_E_INVALID_ARG;

	afc_lock(client);

	debug_info("file handle %i", handle);

	/* Send command */
	memcpy(buffer, &handle, sizeof(uint64_t));
	memcpy(buffer + 8, &op, 8);

	client->afc_packet->operation = AFC_OP_FILE_LOCK;
	client->afc_packet->entire_length = client->afc_packet->this_length = 0;
	ret = afc_dispatch_packet(client, buffer, 16, &bytes);
	free(buffer);
	buffer = NULL;

	if (ret != AFC_E_SUCCESS) {
		afc_unlock(client);
		debug_info("could not send lock command");
		return AFC_E_UNKNOWN_ERROR;
	}
	/* Receive the response */
	ret = afc_receive_data(client, &buffer, &bytes);
	if (buffer) {
		debug_buffer(buffer, bytes);
		free(buffer);
	}
	afc_unlock(client);

	return ret;
}
Beispiel #7
0
static int
mexp_vprintf (mexp_h *h, int password, const char *fs, va_list args)
{
  char *msg;
  int len;
  size_t n;
  ssize_t r;
  char *p;

  len = vasprintf (&msg, fs, args);

  if (len < 0)
    return -1;

  if (h->debug_fp) {
    if (!password) {
      fprintf (h->debug_fp, "DEBUG: writing: ");
      debug_buffer (h->debug_fp, msg);
      fprintf (h->debug_fp, "\n");
    }
    else
      fprintf (h->debug_fp, "DEBUG: writing the password\n");
  }

  n = len;
  p = msg;
  while (n > 0) {
    r = write (h->fd, p, n);
    if (r == -1) {
      free (msg);
      return -1;
    }
    n -= r;
    p += r;
  }

  free (msg);
  return len;
}
void checkAndGzip(buffer *tmpFilePath, buffer *targetFilePath, buffer *expectFilePath, buffer *responsePath){
	char *responseCnt = readResponse(responsePath->ptr);
	int httpStatus = getHttpStatus(responseCnt);
	if(200 == httpStatus) {
		if(-1 != rename(tmpFilePath->ptr, targetFilePath->ptr)) {
			//system invoke unzip
			buffer *unzipCmd = buffer_init_size(20 + targetFilePath->used + expectFilePath->used);
			stringAppend(unzipCmd, GZIP_CMD, GZIP_CMD_LEN);
			stringAppend(unzipCmd, targetFilePath->ptr, targetFilePath->used);
			stringAppend(unzipCmd, " > ", 3);
			stringAppend(unzipCmd, expectFilePath->ptr, expectFilePath->used);

			debug_buffer(unzipCmd, "unzipCmd");
			if(-1 == system(unzipCmd->ptr)) {
				fprintf(stderr, "system(gzip....) error:%s\n", unzipCmd->ptr);
				exit(5);
			}
			buffer_free(unzipCmd);
		}
	}
	free(responseCnt);
}
Beispiel #9
0
/**
 * Receives data through an AFC client and sets a variable to the received data.
 * 
 * @param client The client to receive data on.
 * @param dump_here The char* to point to the newly-received data.
 * @param bytes_recv How much data was received.
 * 
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 */
static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint32_t *bytes_recv)
{
	AFCPacket header;
	uint32_t entire_len = 0;
	uint32_t this_len = 0;
	uint32_t current_count = 0;
	uint64_t param1 = -1;

	*bytes_recv = 0;

	/* first, read the AFC header */
	service_receive(client->parent, (char*)&header, sizeof(AFCPacket), bytes_recv);
	AFCPacket_from_LE(&header);
	if (*bytes_recv == 0) {
		debug_info("Just didn't get enough.");
		*dump_here = NULL;
		return AFC_E_MUX_ERROR;
	} else if (*bytes_recv < sizeof(AFCPacket)) {
		debug_info("Did not even get the AFCPacket header");
		*dump_here = NULL;
		return AFC_E_MUX_ERROR;
	}

	/* check if it's a valid AFC header */
	if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) {
		debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");
	}

	/* check if it has the correct packet number */
	if (header.packet_num != client->afc_packet->packet_num) {
		/* otherwise print a warning but do not abort */
		debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num);
		*dump_here = NULL;
		return AFC_E_OP_HEADER_INVALID;
	}

	/* then, read the attached packet */
	if (header.this_length < sizeof(AFCPacket)) {
		debug_info("Invalid AFCPacket header received!");
		*dump_here = NULL;
		return AFC_E_OP_HEADER_INVALID;
	} else if ((header.this_length == header.entire_length)
			&& header.entire_length == sizeof(AFCPacket)) {
		debug_info("Empty AFCPacket received!");
		*dump_here = NULL;
		*bytes_recv = 0;
		if (header.operation == AFC_OP_DATA) {
			return AFC_E_SUCCESS;
		} else {
			return AFC_E_IO_ERROR;
		}
	}

	debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation);

	entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket);
	this_len = (uint32_t)header.this_length - sizeof(AFCPacket);

	/* this is here as a check (perhaps a different upper limit is good?) */
	if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) {
		fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!", __FUNCTION__, entire_len, MAXIMUM_PACKET_SIZE);
	}

	*dump_here = (char*)malloc(entire_len);
	if (this_len > 0) {
		service_receive(client->parent, *dump_here, this_len, bytes_recv);
		if (*bytes_recv <= 0) {
			free(*dump_here);
			*dump_here = NULL;
			debug_info("Did not get packet contents!");
			return AFC_E_NOT_ENOUGH_DATA;
		} else if (*bytes_recv < this_len) {
			free(*dump_here);
			*dump_here = NULL;
			debug_info("Could not receive this_len=%d bytes", this_len);
			return AFC_E_NOT_ENOUGH_DATA;
		}
	}

	current_count = this_len;

	if (entire_len > this_len) {
		while (current_count < entire_len) {
			service_receive(client->parent, (*dump_here)+current_count, entire_len - current_count, bytes_recv);
			if (*bytes_recv <= 0) {
				debug_info("Error receiving data (recv returned %d)", *bytes_recv);
				break;
			}
			current_count += *bytes_recv;
		}
		if (current_count < entire_len) {
			debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len);
		}
	}

	if (current_count >= sizeof(uint64_t)) {
		param1 = le64toh(*(uint64_t*)(*dump_here));
	}

	debug_info("packet data size = %i", current_count);
	debug_info("packet data follows");
	debug_buffer(*dump_here, current_count);

	/* check operation types */
	if (header.operation == AFC_OP_STATUS) {
		/* status response */
		debug_info("got a status response, code=%lld", param1);

		if (param1 != AFC_E_SUCCESS) {
			/* error status */
			/* free buffer */
			free(*dump_here);
			*dump_here = NULL;
			return (afc_error_t)param1;
		}
	} else if (header.operation == AFC_OP_DATA) {
		/* data response */
		debug_info("got a data response");
	} else if (header.operation == AFC_OP_FILE_OPEN_RES) {
		/* file handle response */
		debug_info("got a file handle response, handle=%lld", param1);
	} else if (header.operation == AFC_OP_FILE_TELL_RES) {
		/* tell response */
		debug_info("got a tell response, position=%lld", param1);
	} else {
		/* unknown operation code received */
		free(*dump_here);
		*dump_here = NULL;
		*bytes_recv = 0;

		debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
#ifndef WIN32
		fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);
#endif

		return AFC_E_OP_NOT_SUPPORTED;
	}

	*bytes_recv = current_count;
	return AFC_E_SUCCESS;
}
Beispiel #10
0
/**
 * Dispatches an AFC packet over a client.
 * 
 * @param client The client to send data through.
 * @param data The data to send.
 * @param length The length to send.
 * @param bytes_sent The number of bytes actually sent.
 *
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 * 
 * @warning set client->afc_packet->this_length and
 *          client->afc_packet->entire_length to 0 before calling this.  The
 *          reason is that if you set them to different values, it indicates
 *          you want to send the data as two packets.
 */
static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, uint32_t length, uint32_t *bytes_sent)
{
	uint32_t offset = 0;
	uint32_t sent = 0;

	if (!client || !client->parent || !client->afc_packet)
		return AFC_E_INVALID_ARG;

	*bytes_sent = 0;

	if (!data || !length)
		length = 0;

	client->afc_packet->packet_num++;
	if (!client->afc_packet->entire_length) {
		client->afc_packet->entire_length = (length) ? sizeof(AFCPacket) + length : sizeof(AFCPacket);
		client->afc_packet->this_length = client->afc_packet->entire_length;
	}
	if (!client->afc_packet->this_length) {
		client->afc_packet->this_length = sizeof(AFCPacket);
	}
	/* We want to send two segments; buffer+sizeof(AFCPacket) to this_length
	   is the parameters and everything beyond that is the next packet.
	   (for writing) */
	if (client->afc_packet->this_length != client->afc_packet->entire_length) {
		offset = (uint32_t)(client->afc_packet->this_length - sizeof(AFCPacket));

		debug_info("Offset: %i", offset);
		if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) {
			debug_info("Length did not resemble what it was supposed to based on packet");
			debug_info("length minus offset: %i", length - offset);
			debug_info("rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length);
			return AFC_E_INTERNAL_ERROR;
		}

		/* send AFC packet header */
		AFCPacket_to_LE(client->afc_packet);
		sent = 0;
		service_send(client->parent, (const char *)client->afc_packet, sizeof(AFCPacket), &sent);
		AFCPacket_from_LE(client->afc_packet);
		if (sent == 0) {
			/* FIXME: should this be handled as success?! */
			return AFC_E_SUCCESS;
		}
		*bytes_sent += sent;

		/* send AFC packet data */
		sent = 0;
		service_send(client->parent, data, offset, &sent);
		if (sent == 0) {
			return AFC_E_SUCCESS;
		}
		*bytes_sent += sent;

		debug_info("sent the first now go with the second");
		debug_info("Length: %i", length - offset);
		debug_info("Buffer: ");
		debug_buffer(data + offset, length - offset);

		sent = 0;
		service_send(client->parent, data + offset, length - offset, &sent);

		*bytes_sent = sent;
		return AFC_E_SUCCESS;
	} else {
		debug_info("doin things the old way");
		debug_info("packet length = %i", client->afc_packet->this_length);

		debug_buffer((char*)client->afc_packet, sizeof(AFCPacket));

		/* send AFC packet header */
		AFCPacket_to_LE(client->afc_packet);
		sent = 0;
		service_send(client->parent, (const char *)client->afc_packet, sizeof(AFCPacket), &sent);
		AFCPacket_from_LE(client->afc_packet);
		if (sent == 0) {
			return AFC_E_SUCCESS;
		}
		*bytes_sent += sent;
		/* send AFC packet data (if there's data to send) */
		if (length > 0) {
			debug_info("packet data follows");

			debug_buffer(data, length);
			service_send(client->parent, data, length, &sent);
			*bytes_sent += sent;
		}
		return AFC_E_SUCCESS;
	}
	return AFC_E_INTERNAL_ERROR;
}
/**
 * Receives a plist using the given property list service client.
 * Internally used generic plist receive function.
 *
 * @param client The property list service client to use for receiving
 * @param plist pointer to a plist_t that will point to the received plist
 *      upon successful return
 * @param timeout Maximum time in milliseconds to wait for data.
 *
 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
 *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
 *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
 *      converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
 *      communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR
 *      when an unspecified error occurs.
 */
static property_list_service_error_t internal_plist_receive_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
{
	property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
	uint32_t pktlen = 0;
	uint32_t bytes = 0;

	if (!client || (client && !client->parent) || !plist) {
		return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
	}

	*plist = NULL;
	service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);
	if ((serr == SERVICE_E_SUCCESS) && (bytes == 0)) {
		return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT;
	}
	debug_info("initial read=%i", bytes);
	if (bytes < 4) {
		debug_info("initial read failed!");
		return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
	} else {
		uint32_t curlen = 0;
		char *content = NULL;

		pktlen = be32toh(pktlen);
		debug_info("%d bytes following", pktlen);
		content = (char*)malloc(pktlen);
		if (!content) {
			debug_info("out of memory when allocating %d bytes", pktlen);
			return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
		}

		while (curlen < pktlen) {
			service_receive(client->parent, content+curlen, pktlen-curlen, &bytes);
			if (bytes <= 0) {
				res = PROPERTY_LIST_SERVICE_E_MUX_ERROR;
				break;
			}
			debug_info("received %d bytes", bytes);
			curlen += bytes;
		}
		if (curlen < pktlen) {
			debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen);
			if (curlen > 0) {
				debug_info("incomplete packet following:");
				debug_buffer(content, curlen);
			}
			free(content);
			return res;
		}
		if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) {
			plist_from_bin(content, pktlen, plist);
		} else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) {
			/* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */
			for (bytes = 0; bytes < pktlen-1; bytes++) {
				if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d))
					content[bytes] = 0x20;
			}
			plist_from_xml(content, pktlen, plist);
		} else {
			debug_info("WARNING: received unexpected non-plist content");
			debug_buffer(content, pktlen);
		}
		if (*plist) {
			debug_plist(*plist);
			res = PROPERTY_LIST_SERVICE_E_SUCCESS;
		} else {
			res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
		}
		free(content);
		content = NULL;
	}
	return res;
}
Beispiel #12
0
enum mexp_status
mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
{
  time_t start_t, now_t;
  int timeout;
  struct pollfd pfds[1];
  int r;
  ssize_t rs;

  time (&start_t);

  if (h->next_match == -1) {
    /* Fully clear the buffer, then read. */
    clear_buffer (h);
  } else {
    /* See the comment in the manual about h->next_match.  We have
     * some data remaining in the buffer, so begin by matching that.
     */
    memmove (&h->buffer[0], &h->buffer[h->next_match], h->len - h->next_match);
    h->len -= h->next_match;
    h->buffer[h->len] = '\0';
    h->next_match = -1;
    goto try_match;
  }

  for (;;) {
    /* If we've got a timeout then work out how many seconds are left.
     * Timeout == 0 is not particularly well-defined, but it probably
     * means "return immediately if there's no data to be read".
     */
    if (h->timeout >= 0) {
      time (&now_t);
      timeout = h->timeout - ((now_t - start_t) * 1000);
      if (timeout < 0)
        timeout = 0;
    }
    else
      timeout = 0;

    pfds[0].fd = h->fd;
    pfds[0].events = POLLIN;
    pfds[0].revents = 0;
    r = poll (pfds, 1, timeout);
    if (h->debug_fp)
      fprintf (h->debug_fp, "DEBUG: poll returned %d\n", r);
    if (r == -1)
      return MEXP_ERROR;

    if (r == 0)
      return MEXP_TIMEOUT;

    /* Otherwise we expect there is something to read from the file
     * descriptor.
     */
    if (h->alloc - h->len <= h->read_size) {
      char *new_buffer;
      /* +1 here allows us to store \0 after the data read */
      new_buffer = realloc (h->buffer, h->alloc + h->read_size + 1);
      if (new_buffer == NULL)
        return MEXP_ERROR;
      h->buffer = new_buffer;
      h->alloc += h->read_size;
    }
    rs = read (h->fd, h->buffer + h->len, h->read_size);
    if (h->debug_fp)
      fprintf (h->debug_fp, "DEBUG: read returned %zd\n", rs);
    if (rs == -1) {
      /* Annoyingly on Linux (I'm fairly sure this is a bug) if the
       * writer closes the connection, the entire pty is destroyed,
       * and read returns -1 / EIO.  Handle that special case here.
       */
      if (errno == EIO)
        return MEXP_EOF;
      return MEXP_ERROR;
    }
    if (rs == 0)
      return MEXP_EOF;

    /* We read something. */
    h->len += rs;
    h->buffer[h->len] = '\0';
    if (h->debug_fp) {
      fprintf (h->debug_fp, "DEBUG: read %zd bytes from pty\n", rs);
      fprintf (h->debug_fp, "DEBUG: buffer content: ");
      debug_buffer (h->debug_fp, h->buffer);
      fprintf (h->debug_fp, "\n");
    }

  try_match:
    /* See if there is a full or partial match against any regexp. */
    if (regexps) {
      size_t i;
      int can_clear_buffer = 1;

      assert (h->buffer != NULL);

      for (i = 0; regexps[i].r > 0; ++i) {
        const int options = regexps[i].options | PCRE_PARTIAL_SOFT;

        r = pcre_exec (regexps[i].re, regexps[i].extra,
                       h->buffer, (int)h->len, 0,
                       options,
                       ovector, ovecsize);
        h->pcre_error = r;

        if (r >= 0) {
          /* A full match. */
          if (ovector != NULL && ovecsize >= 1 && ovector[1] >= 0)
            h->next_match = ovector[1];
          else
            h->next_match = -1;
          return regexps[i].r;
        }

        else if (r == PCRE_ERROR_NOMATCH) {
          /* No match at all. */
          /* (nothing here) */
        }

        else if (r == PCRE_ERROR_PARTIAL) {
          /* Partial match.  Keep the buffer and keep reading. */
          can_clear_buffer = 0;
        }

        else {
          /* An actual PCRE error. */
          return MEXP_PCRE_ERROR;
        }
      }

      /* If none of the regular expressions matched (not partially)
       * then we can clear the buffer.  This is an optimization.
       */
      if (can_clear_buffer)
        clear_buffer (h);

    } /* if (regexps) */
  }
}
void parseArgs(VersionUpdateConfig *config, int argc, char *args[]) {

	if(argc < 4) {
		fprintf(stderr, "USAGE:%s\n", USAGE);
		exit(3);
	}

	if(debug) {
		int i = 0;
		for(i = 0; i < argc; i++) {
			fprintf(stdout, "param $%d == %s\n", i, args[i]);
		}
	}

	char *URL = args[1];
	char *path = args[2];
	int   intervalSecond = atoi(args[3]);
	char *lockURL = args[4];

	if(argc > 5) {
		debug = atoi(args[5]);
	}
	//global var
	size_t URLLen = strlen(URL);
	size_t pathLen = strlen(path);
	
	if(!parseLockUrl(lockURL, config)){
		exit(1);
	}
	
	//interval time
	config->intervalSecond = intervalSecond;
	//url
	buffer *URLDomain = buffer_init_size(URLLen + 1);
	stringAppend(URLDomain, URL, URLLen);
	config->URLDomain = URLDomain;
	debug_buffer(URLDomain, "URLDomain");
	
	//dir
	buffer *versionFileDir = buffer_init_size(pathLen + 1);
	char *lastChar = strrchr(path, '/');
	if(NULL == lastChar) {
		fprintf(stderr, "USAGE:%s\n", USAGE);
		exit(5);
	}
	stringAppend(versionFileDir, path, pathLen - strlen(lastChar));
	config->versionFileDir = versionFileDir;
	struct stat st;
	if (-1 == stat(versionFileDir->ptr, &st)) {
		//mkdir
		mkdir_recursive(versionFileDir->ptr);
		debug_buffer(versionFileDir, "mkdir_recursive make done....");
	}
	debug_buffer(versionFileDir, "versionFileDir");
	//source
	buffer *versionFilePath = buffer_init_size(pathLen + 1);
	stringAppend(versionFilePath, path, pathLen);
	config->versionFilePath = versionFilePath;
	debug_buffer(versionFilePath, "versionFilePath");
	//expect
	buffer *expectVersionFilePath = buffer_init_size(versionFilePath->size);
	stringAppend(expectVersionFilePath, path, pathLen - 3); //--clean .gz
	config->expectVersionFilePath = expectVersionFilePath;
	debug_buffer(expectVersionFilePath, "expectVersionFilePath");
	//response
	buffer *reponseFilePath = buffer_init_size(versionFilePath->size + REPONSE_LOG_LEN);
	stringAppend(reponseFilePath, expectVersionFilePath->ptr, expectVersionFilePath->used);
	stringAppend(reponseFilePath, REPONSE_LOG, REPONSE_LOG_LEN);
	config->reponseFilePath = reponseFilePath;
	debug_buffer(reponseFilePath, "reponseFilePath");
	//tmp
	buffer *tmpVersionFilePath = buffer_init_size(versionFilePath->size + TMP_LEN);
	stringAppend(tmpVersionFilePath, versionFilePath->ptr, versionFilePath->used);
	stringAppend(tmpVersionFilePath, TMP, TMP_LEN);
	config->tmpVersionFilePath = tmpVersionFilePath;
	debug_buffer(tmpVersionFilePath, "tmpVersionFilePath");
}
void intervalWork(VersionUpdateConfig *config) {

	if(debug) {
		fprintf(stdout, "start intervalWork\n");
	}
	//clean old responsefile
	remove(config->reponseFilePath->ptr);

	buffer *lastModifiedTime = NULL;

	int paramLen = config->URLDomain->used + config->tmpVersionFilePath->used + config->reponseFilePath->used;
	buffer *param = buffer_init_size(20 + paramLen);
	stringAppend(param, " ", 1);
	stringAppend(param, config->URLDomain->ptr, config->URLDomain->used);
	stringAppend(param, " -O ", 4);
	stringAppend(param, config->tmpVersionFilePath->ptr, config->tmpVersionFilePath->used);
	stringAppend(param, " > ", 3);
	stringAppend(param, config->reponseFilePath->ptr, config->reponseFilePath->used);
	stringAppend(param, " 2>&1 ", 6);

	while(1) {
		char *responseCnt = readResponse(config->reponseFilePath->ptr);
		int httpStatus = getHttpStatus(responseCnt);
		if(debug) {
			fprintf(stdout, "httpStatus:%d\n", httpStatus);
		}
		// ignore the lock checke for the first version file request
		if(0 != httpStatus && 404 != httpStatus) {
			int bLocked = checkLockStatus(config->lockRequestURL->ptr);
			if(bLocked){
				sleep(config->intervalSecond);
				continue;
			}
		}
		if(304 != httpStatus) {
			getLastModified(responseCnt, &lastModifiedTime);
		}
		debug_buffer(lastModifiedTime, "lastModifiedTime");
		
		//thread interval exec
		buffer *cmdBuf = buffer_init_size(LAST_MODIFIED_LEN + WGET_CMD_LEN + HEADER_LEN + param->used);
		stringAppend(cmdBuf, WGET_CMD, WGET_CMD_LEN);
		if(NULL != lastModifiedTime) {
			stringAppend(cmdBuf, HEADER, HEADER_LEN);
			stringAppend(cmdBuf, lastModifiedTime->ptr, lastModifiedTime->used);
			stringAppend(cmdBuf, "\"", 1);
		}
		stringAppend(cmdBuf, param->ptr, param->used);
		debug_buffer(cmdBuf, "cmdBuf");

		if(-1 == system(cmdBuf->ptr)) {
			fprintf(stderr, "system (wget...) error:%s\n", cmdBuf->ptr);
			exit(4);
		}

		free(responseCnt);
		buffer_free(cmdBuf);

		checkAndGzip(config->tmpVersionFilePath, config->versionFilePath,
					config->expectVersionFilePath, config->reponseFilePath);

		sleep(config->intervalSecond);
	}
}