Esempio n. 1
0
static int
read_number(int c, FILE *cfile)
{
	int	seenx = 0, i = 0, token = TOK_NUMBER;

	tokbuf[i++] = c;
	for (; i < sizeof(tokbuf); i++) {
		c = get_char(cfile);
		if (!seenx && c == 'x')
			seenx = 1;
		else if (!isascii(c) || !isxdigit(c)) {
			ungetc(c, cfile);
			ugflag = 1;
			break;
		}
		tokbuf[i] = c;
	}
	if (i == sizeof(tokbuf)) {
		parse_warn("numeric token larger than internal buffer");
		i--;
	}
	tokbuf[i] = 0;
	tval = tokbuf;

	return (token);
}
Esempio n. 2
0
/*
 * Parse a sequence of numbers separated by the token specified in separator.
 * Exactly max numbers are expected.
 */
int
parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int max, int separator,
    int base)
{
	char *val;
	int token, count;

	if (buf == NULL || max == 0)
		error("no space for numeric aggregate");

	for (count = 0; count < max; count++, buf++) {
		if (count && (peek_token(&val, cfile) == separator))
			token = next_token(&val, cfile);

		token = next_token(&val, cfile);

		if (token == TOK_NUMBER || (base == 16 && token == TOK_NUMBER_OR_NAME))
			/* XXX Need to check if conversion was successful. */
			convert_num(buf, val, base, 8);
		else
			break;
	}

	if (count < max) {
		parse_warn("numeric aggregate too short.");
		return (0);
	}

	return (1);
}
Esempio n. 3
0
static int
read_num_or_name(int c, FILE *cfile)
{
	int	i = 0;
	int	rv = TOK_NUMBER_OR_NAME;

	tokbuf[i++] = c;
	for (; i < sizeof(tokbuf); i++) {
		c = get_char(cfile);
		if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
			ungetc(c, cfile);
			ugflag = 1;
			break;
		}
		if (!isxdigit(c))
			rv = TOK_NAME;
		tokbuf[i] = c;
	}
	if (i == sizeof(tokbuf)) {
		parse_warn("token larger than internal buffer");
		i--;
	}
	tokbuf[i] = 0;
	tval = tokbuf;

	return (intern(tval, rv));
}
Esempio n. 4
0
/**
 * Parse a version string coming from a database file.
 *
 * It parses a version string, and prints a warning or an error depending
 * on the parse options.
 *
 * @param ps The parsedb state.
 * @param pkg The package being parsed.
 * @param version The version to parse into.
 * @param value The version string to parse from.
 * @param fmt The error format string.
 */
void
parse_db_version(struct parsedb_state *ps, const struct pkginfo *pkg,
                 struct versionrevision *version, const char *value,
                 const char *fmt, ...)
{
  const char *msg;
  bool warn_msg = false;

  msg = parseversion_lax(version, value);
  if (msg == NULL) {
    msg = version_strict_check(version);
    if (ps->flags & pdb_lax_parser)
      warn_msg = true;
  }

  if (msg) {
    va_list args;
    char buf[1000];

    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);

    if (warn_msg)
      parse_warn(ps, pkg, "%s: %.250s", buf, msg);
    else
      parse_error(ps, pkg, "%s: %.250s", buf, msg);

    va_end(args);
  }
}
Esempio n. 5
0
void
parse_string_list(FILE *cfile, struct string_list **lp, int multiple)
{
	int			 token;
	char			*val;
	size_t			 valsize;
	struct string_list	*cur, *tmp;

	/* Find the last medium in the media list. */
	if (*lp)
		for (cur = *lp; cur->next; cur = cur->next)
			;	/* nothing */
	else
		cur = NULL;

	do {
		token = next_token(&val, cfile);
		if (token != STRING) {
			parse_warn("Expecting media options.");
			skip_to_semi(cfile);
			return;
		}

		valsize = strlen(val) + 1;
		tmp = new_string_list(valsize);
		if (tmp == NULL)
			error("no memory for string list entry.");
		memcpy(tmp->string, val, valsize);
		tmp->next = NULL;

		/* Store this medium at the end of the media list. */
		if (cur)
			cur->next = tmp;
		else
			*lp = tmp;
		cur = tmp;

		token = next_token(&val, cfile);
	} while (multiple && token == COMMA);

	if (token != SEMI) {
		parse_warn("expecting semicolon.");
		skip_to_semi(cfile);
	}
}
Esempio n. 6
0
int
parse_X(FILE *cfile, u_int8_t *buf, int max)
{
	int	 token;
	char	*val;
	int	 len;

	token = peek_token(&val, cfile);
	if (token == TOK_NUMBER_OR_NAME || token == TOK_NUMBER) {
		len = 0;
		do {
			token = next_token(&val, cfile);
			if (token != TOK_NUMBER && token != TOK_NUMBER_OR_NAME) {
				parse_warn("expecting hexadecimal constant.");
				skip_to_semi(cfile);
				return (0);
			}
			convert_num(&buf[len], val, 16, 8);
			if (len++ > max) {
				parse_warn("hexadecimal constant too long.");
				skip_to_semi(cfile);
				return (0);
			}
			token = peek_token(&val, cfile);
			if (token == ':')
				token = next_token(&val, cfile);
		} while (token == ':');
		val = (char *)buf;
	} else if (token == TOK_STRING) {
		token = next_token(&val, cfile);
		len = strlen(val);
		if (len + 1 > max) {
			parse_warn("string constant too long.");
			skip_to_semi(cfile);
			return (0);
		}
		memcpy(buf, val, len + 1);
	} else {
		parse_warn("expecting string or hexadecimal data");
		skip_to_semi(cfile);
		return (0);
	}
	return (len);
}
Esempio n. 7
0
/*
 * interface-declaration :==
 *	INTERFACE string LBRACE client-declarations RBRACE
 */
void
parse_interface_declaration(FILE *cfile, struct client_config *outer_config)
{
	int			 token;
	char			*val;
	struct interface_info	*ip;

	token = next_token(&val, cfile);
	if (token != STRING) {
		parse_warn("expecting interface name (in quotes).");
		skip_to_semi(cfile);
		return;
	}

	ip = interface_or_dummy(val);

	if (!ip->client)
		make_client_state(ip);

	if (!ip->client->config)
		make_client_config(ip, outer_config);

	token = next_token(&val, cfile);
	if (token != LBRACE) {
		parse_warn("expecting left brace.");
		skip_to_semi(cfile);
		return;
	}

	do {
		token = peek_token(&val, cfile);
		if (token == EOF) {
			parse_warn("unterminated interface declaration.");
			return;
		}
		if (token == RBRACE)
			break;
		parse_client_statement(cfile, ip, ip->client->config);
	} while (1);
	token = next_token(&val, cfile);
}
Esempio n. 8
0
int
parse_semi(FILE *cfile)
{
	int token;

	token = next_token(NULL, cfile);
	if (token != ';') {
		parse_warn("semicolon expected.");
		skip_to_semi(cfile);
		return (0);
	}
	return (1);
}
Esempio n. 9
0
/*
 * option-list :== option_name |
 *		   option_list COMMA option_name
 */
int
parse_option_list(FILE *cfile, u_int8_t *list)
{
	int	 ix, i;
	int	 token;
	char	*val;

	ix = 0;
	do {
		token = next_token(&val, cfile);
		if (!is_identifier(token)) {
			parse_warn("expected option name.");
			skip_to_semi(cfile);
			return (0);
		}
		for (i = 0; i < 256; i++)
			if (!strcasecmp(dhcp_options[i].name, val))
				break;

		if (i == 256) {
			parse_warn("%s: unexpected option name.", val);
			skip_to_semi(cfile);
			return (0);
		}
		list[ix++] = i;
		if (ix == 256) {
			parse_warn("%s: too many options.", val);
			skip_to_semi(cfile);
			return (0);
		}
		token = next_token(&val, cfile);
	} while (token == ',');
	if (token != ';') {
		parse_warn("expecting semicolon.");
		skip_to_semi(cfile);
		return (0);
	}
	return (ix);
}
Esempio n. 10
0
int
parse_semi(FILE *cfile)
{
	int token;
	char *val;

	token = next_token(&val, cfile);
	if (token != SEMI) {
		parse_warn("semicolon expected.");
		skip_to_semi(cfile);
		return (0);
	}
	return (1);
}
Esempio n. 11
0
/*
 * interface-declaration :==
 *	INTERFACE string LBRACE client-declarations RBRACE
 */
void
parse_interface_declaration(FILE *cfile)
{
	char *val;
	int token;

	token = next_token(&val, cfile);
	if (token != TOK_STRING) {
		parse_warn("expecting interface name (in quotes).");
		skip_to_semi(cfile);
		return;
	}

	if (strcmp(ifi->name, val) != 0) {
		skip_to_semi(cfile);
		return;
	}

	token = next_token(&val, cfile);
	if (token != '{') {
		parse_warn("expecting left brace.");
		skip_to_semi(cfile);
		return;
	}

	do {
		token = peek_token(&val, cfile);
		if (token == EOF) {
			parse_warn("unterminated interface declaration.");
			return;
		}
		if (token == '}')
			break;
		parse_client_statement(cfile);
	} while (1);
	token = next_token(&val, cfile);
}
Esempio n. 12
0
static int
read_string(FILE *cfile)
{
	int i, c, bs;

	/*
	 * Read in characters until an un-escaped '"' is encountered. And
	 * then unvis the data that was read.
	 */
	bs = i = 0;
	memset(visbuf, 0, sizeof(visbuf));
	while ((c = get_char(cfile)) != EOF) {
		if (c == '"' && bs == 0)
			break;

		visbuf[i++] = c;
		if (bs)
			bs = 0;
		else if (c == '\\')
			bs = 1;

		if (i == sizeof(visbuf) - 1)
			break;
	}
	if (bs == 1)
		visbuf[--i] = '\0';
	i = strnunvis(tokbuf, visbuf, sizeof(tokbuf));

	if (c == EOF)
		parse_warn("eof in string constant");
	else if (i == -1 || i >= sizeof(tokbuf))
		parse_warn("string constant too long");

	tval = tokbuf;

	return (TOK_STRING);
}
Esempio n. 13
0
/*
 * hardware-parameter :== HARDWARE ETHERNET csns SEMI
 * csns :== NUMBER | csns COLON NUMBER
 */
void
parse_hardware_param(FILE *cfile, struct hardware *hardware)
{
	int token;
	char *val;

	token = next_token(&val, cfile);
	switch (token) {
	case TOK_ETHERNET:
		hardware->htype = HTYPE_ETHER;
		hardware->hlen = 6;
		break;
	case TOK_TOKEN_RING:
		hardware->htype = HTYPE_IEEE802;
		hardware->hlen = 6;
		break;
	case TOK_FDDI:
		hardware->htype = HTYPE_FDDI;
		hardware->hlen = 6;
		break;
	default:
		parse_warn("expecting a network hardware type");
		skip_to_semi(cfile);
		return;
	}

	if (parse_numeric_aggregate(cfile, hardware->haddr, hardware->hlen,
	    ':', 16) == 0)
		return;

	token = next_token(&val, cfile);
	if (token != ';') {
		parse_warn("expecting semicolon.");
		skip_to_semi(cfile);
	}
}
Esempio n. 14
0
/*
 * lease-time :== NUMBER SEMI
 */
void
parse_lease_time(FILE *cfile, time_t *timep)
{
	char *val;
	int token;

	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("Expecting numeric lease time");
		skip_to_semi(cfile);
		return;
	}
	convert_num((unsigned char *)timep, val, 10, 32);
	/* Unswap the number - convert_num returns stuff in NBO. */
	*timep = ntohl(*timep); /* XXX */

	parse_semi(cfile);
}
Esempio n. 15
0
void read_leases ()
{
	FILE *cfile;
	char *val;
	int token;

	new_parse (path_dhcpd_db);

	/* Open the lease file.   If we can't open it, fail.   The reason
	   for this is that although on initial startup, the absence of
	   a lease file is perfectly benign, if dhcpd has been running 
	   and this file is absent, it means that dhcpd tried and failed
	   to rewrite the lease database.   If we proceed and the
	   problem which caused the rewrite to fail has been fixed, but no
	   human has corrected the database problem, then we are left
	   thinking that no leases have been assigned to anybody, which
	   could create severe network chaos. */
	if ((cfile = fopen (path_dhcpd_db, "r")) == NULL) {
		warn ("Can't open lease database %s: %m -- %s",
		      path_dhcpd_db,
		      "check for failed database rewrite attempt!");
		warn ("Please read the dhcpd.leases manual page if you.");
		error ("don't know what to do about this.");	}

	do {
		token = next_token (&val, cfile);
		if (token == EOF)
			break;
		if (token != LEASE) {
			warn ("Corrupt lease file - possible data loss!");
			skip_to_semi (cfile);
		} else {
			struct lease *lease;
			lease = parse_lease_declaration (cfile);
			if (lease)
				enter_lease (lease);
			else
				parse_warn ("possibly corrupt lease file");
		}

	} while (1);
}
Esempio n. 16
0
/**
 * Parse a version string coming from a database file.
 *
 * It parses a version string, and prints a warning or an error depending
 * on the parse options.
 *
 * @param ps The parsedb state.
 * @param version The version to parse into.
 * @param value The version string to parse from.
 * @param fmt The error format string.
 */
void
parse_db_version(struct parsedb_state *ps, struct versionrevision *version,
                 const char *value, const char *fmt, ...)
{
  struct dpkg_error err;
  va_list args;
  char buf[1000];

  if (parseversion(version, value, &err) == 0)
    return;

  va_start(args, fmt);
  vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);

  if (err.type == DPKG_MSG_WARN && (ps->flags & pdb_lax_parser))
    parse_warn(ps, "%s: %.250s", buf, err.str);
  else
    parse_error(ps, "%s: %.250s", buf, err.str);

  dpkg_error_destroy(&err);
}
Esempio n. 17
0
/*
 * string-parameter :== STRING SEMI
 */
char *
parse_string(FILE *cfile)
{
	char *val, *s;
	int token;

	token = next_token(&val, cfile);
	if (token != TOK_STRING) {
		parse_warn("filename must be a string");
		skip_to_semi(cfile);
		return (NULL);
	}
	s = strdup(val);
	if (!s)
		error("no memory for string %s.", val);

	if (!parse_semi(cfile)) {
		free(s);
		return (NULL);
	}
	return (s);
}
Esempio n. 18
0
/*
 * string-parameter :== STRING SEMI
 */
char *
parse_string(FILE *cfile)
{
	char *val, *s;
	size_t valsize;
	int token;

	token = next_token(&val, cfile);
	if (token != STRING) {
		parse_warn("filename must be a string");
		skip_to_semi(cfile);
		return (NULL);
	}
	valsize = strlen(val) + 1;
	s = malloc(valsize);
	if (!s)
		error("no memory for string %s.", val);
	memcpy(s, val, valsize);

	if (!parse_semi(cfile))
		return (NULL);
	return (s);
}
Esempio n. 19
0
int parsedb(const char *filename, enum parsedbflags flags,
            struct pkginfo **donep, FILE *warnto, int *warncount) {
  /* warnto, warncount and donep may be null.
   * If donep is not null only one package's information is expected.
   */
  
  static int fd;
  struct pkginfo newpig, *pigp;
  struct pkginfoperfile *newpifp, *pifp;
  struct arbitraryfield *arp, **larpp;
  struct trigaw *ta;
  int pdone;
  int fieldencountered[array_count(fieldinfos)];
  const struct fieldinfo *fip;
  const struct nickname *nick;
  char *data, *dataptr, *endptr;
  const char *fieldstart, *valuestart;
  char *value= NULL;
  int fieldlen= 0, valuelen= 0;
  int *ip, c;
  struct stat st;
  struct parsedb_state ps;

  ps.filename = filename;
  ps.flags = flags;
  ps.lno = 0;
  ps.warnto = warnto;
  ps.warncount = 0;

  newpifp= (flags & pdb_recordavailable) ? &newpig.available : &newpig.installed;
  fd= open(filename, O_RDONLY);
  if (fd == -1) ohshite(_("failed to open package info file `%.255s' for reading"),filename);

  push_cleanup(cu_closefd, ~ehflag_normaltidy, NULL, 0, 1, &fd);

  if (fstat(fd, &st) == -1)
    ohshite(_("can't stat package info file `%.255s'"),filename);

  if (st.st_size > 0) {
#ifdef USE_MMAP
    dataptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
    if (dataptr == MAP_FAILED)
      ohshite(_("can't mmap package info file `%.255s'"),filename);
#else
    dataptr = m_malloc(st.st_size);

    fd_buf_copy(fd, dataptr, st.st_size, _("copy info file `%.255s'"), filename);
#endif
    data= dataptr;
    endptr = dataptr + st.st_size;
  } else {
    data= dataptr= endptr= NULL;
  }

  pdone= 0;
#define EOF_mmap(dataptr, endptr)	(dataptr >= endptr)
#define getc_mmap(dataptr)		*dataptr++;
#define ungetc_mmap(c, dataptr, data)	dataptr--;

  for (;;) { /* loop per package */
    memset(fieldencountered, 0, sizeof(fieldencountered));
    blankpackage(&newpig);

/* Skip adjacent new lines */
    while(!EOF_mmap(dataptr, endptr)) {
      c= getc_mmap(dataptr); if (c!='\n' && c!=MSDOS_EOF_CHAR ) break;
      ps.lno++;
    }
    if (EOF_mmap(dataptr, endptr)) break;
    for (;;) { /* loop per field */
      fieldstart= dataptr - 1;
      while (!EOF_mmap(dataptr, endptr) && !isspace(c) && c!=':' && c!=MSDOS_EOF_CHAR)
        c= getc_mmap(dataptr);
      fieldlen= dataptr - fieldstart - 1;
      while (!EOF_mmap(dataptr, endptr) && c != '\n' && isspace(c)) c= getc_mmap(dataptr);
      if (EOF_mmap(dataptr, endptr))
        parse_error(&ps, &newpig,
                    _("EOF after field name `%.*s'"), fieldlen, fieldstart);
      if (c == '\n')
        parse_error(&ps, &newpig,
                    _("newline in field name `%.*s'"), fieldlen, fieldstart);
      if (c == MSDOS_EOF_CHAR)
        parse_error(&ps, &newpig,
                    _("MSDOS EOF (^Z) in field name `%.*s'"),
                    fieldlen, fieldstart);
      if (c != ':')
        parse_error(&ps, &newpig,
                    _("field name `%.*s' must be followed by colon"),
                    fieldlen, fieldstart);
/* Skip space after ':' but before value and eol */
      while(!EOF_mmap(dataptr, endptr)) {
        c= getc_mmap(dataptr);
        if (c == '\n' || !isspace(c)) break;
      }
      if (EOF_mmap(dataptr, endptr))
        parse_error(&ps, &newpig,
                    _("EOF before value of field `%.*s' (missing final newline)"),
                 fieldlen,fieldstart);
      if (c == MSDOS_EOF_CHAR)
        parse_error(&ps, &newpig,
                    _("MSDOS EOF char in value of field `%.*s' (missing newline?)"),
                    fieldlen,fieldstart);
      valuestart= dataptr - 1;
      for (;;) {
        if (c == '\n' || c == MSDOS_EOF_CHAR) {
          ps.lno++;
	  if (EOF_mmap(dataptr, endptr)) break;
          c= getc_mmap(dataptr);
/* Found double eol, or start of new field */
          if (EOF_mmap(dataptr, endptr) || c == '\n' || !isspace(c)) break;
          ungetc_mmap(c,dataptr, data);
          c= '\n';
        } else if (EOF_mmap(dataptr, endptr)) {
          parse_error(&ps, &newpig,
                      _("EOF during value of field `%.*s' (missing final newline)"),
                      fieldlen,fieldstart);
        }
        c= getc_mmap(dataptr);
      }
      valuelen= dataptr - valuestart - 1;
/* trim ending space on value */
      while (valuelen && isspace(*(valuestart+valuelen-1)))
 valuelen--;
      for (nick = nicknames;
           nick->nick && (strncasecmp(nick->nick, fieldstart, fieldlen) ||
                          nick->nick[fieldlen] != '\0'); nick++) ;
      if (nick->nick) {
	fieldstart= nick->canon;
	fieldlen= strlen(fieldstart);
      }
      for (fip= fieldinfos, ip= fieldencountered;
           fip->name && strncasecmp(fieldstart,fip->name, fieldlen);
           fip++, ip++);
      if (fip->name) {
        value = m_realloc(value, valuelen + 1);
	memcpy(value,valuestart,valuelen);
        *(value + valuelen) = '\0';
        if ((*ip)++)
          parse_error(&ps, &newpig,
                      _("duplicate value for `%s' field"), fip->name);
        fip->rcall(&newpig, newpifp, &ps, value, fip);
      } else {
        if (fieldlen<2)
          parse_error(&ps, &newpig,
                      _("user-defined field name `%.*s' too short"),
                      fieldlen, fieldstart);
        larpp= &newpifp->arbs;
        while ((arp= *larpp) != NULL) {
          if (!strncasecmp(arp->name,fieldstart,fieldlen))
            parse_error(&ps, &newpig,
                       _("duplicate value for user-defined field `%.*s'"),
                       fieldlen, fieldstart);
          larpp= &arp->next;
        }
        arp= nfmalloc(sizeof(struct arbitraryfield));
        arp->name= nfstrnsave(fieldstart,fieldlen);
        arp->value= nfstrnsave(valuestart,valuelen);
        arp->next= NULL;
        *larpp= arp;
      }
      if (EOF_mmap(dataptr, endptr) || c == '\n' || c == MSDOS_EOF_CHAR) break;
    } /* loop per field */
    if (pdone && donep)
      parse_error(&ps, &newpig,
                  _("several package info entries found, only one allowed"));
    parse_must_have_field(&ps, &newpig, newpig.name, "package name");
    if ((flags & pdb_recordavailable) || newpig.status != stat_notinstalled) {
      parse_ensure_have_field(&ps, &newpig,
                              &newpifp->description, "description");
      parse_ensure_have_field(&ps, &newpig,
                              &newpifp->maintainer, "maintainer");
      if (newpig.status != stat_halfinstalled)
        parse_must_have_field(&ps, &newpig,
                              newpifp->version.version, "version");
    }
    if (flags & pdb_recordavailable)
      parse_ensure_have_field(&ps, &newpig,
                              &newpifp->architecture, "architecture");

    /* Check the Config-Version information:
     * If there is a Config-Version it is definitely to be used, but
     * there shouldn't be one if the package is `installed' (in which case
     * the Version and/or Revision will be copied) or if the package is
     * `not-installed' (in which case there is no Config-Version).
     */
    if (!(flags & pdb_recordavailable)) {
      if (newpig.configversion.version) {
        if (newpig.status == stat_installed || newpig.status == stat_notinstalled)
          parse_error(&ps, &newpig,
                      _("Configured-Version for package with inappropriate Status"));
      } else {
        if (newpig.status == stat_installed) newpig.configversion= newpifp->version;
      }
    }

    if (newpig.trigaw.head &&
        (newpig.status <= stat_configfiles ||
         newpig.status >= stat_triggerspending))
      parse_error(&ps, &newpig,
                  _("package has status %s but triggers are awaited"),
                  statusinfos[newpig.status].name);
    else if (newpig.status == stat_triggersawaited && !newpig.trigaw.head)
      parse_error(&ps, &newpig,
                  _("package has status triggers-awaited but no triggers "
                    "awaited"));

    if (!(newpig.status == stat_triggerspending ||
          newpig.status == stat_triggersawaited) &&
        newpig.trigpend_head)
      parse_error(&ps, &newpig,
                  _("package has status %s but triggers are pending"),
                  statusinfos[newpig.status].name);
    else if (newpig.status == stat_triggerspending && !newpig.trigpend_head)
      parse_error(&ps, &newpig,
                  _("package has status triggers-pending but no triggers "
                    "pending"));

    /* FIXME: There was a bug that could make a not-installed package have
     * conffiles, so we check for them here and remove them (rather than
     * calling it an error, which will do at some point).
     */
    if (!(flags & pdb_recordavailable) &&
        newpig.status == stat_notinstalled &&
        newpifp->conffiles) {
      parse_warn(&ps, &newpig,
                 _("Package which in state not-installed has conffiles, "
                   "forgetting them"));
      newpifp->conffiles= NULL;
    }

    /* XXX: Mark not-installed leftover packages for automatic removal on
     * next database dump. This code can be removed after dpkg 1.16.x, when
     * there's guarantee that no leftover is found on the status file on
     * major distributions. */
    if (!(flags & pdb_recordavailable) &&
        newpig.status == stat_notinstalled &&
        newpig.eflag == eflag_ok &&
        (newpig.want == want_purge ||
         newpig.want == want_deinstall ||
         newpig.want == want_hold)) {
      newpig.want = want_unknown;
    }

    pigp= findpackage(newpig.name);
    pifp= (flags & pdb_recordavailable) ? &pigp->available : &pigp->installed;

    if ((flags & pdb_ignoreolder) &&
	versioncompare(&newpifp->version, &pifp->version) < 0)
      continue;

    /* Copy the priority and section across, but don't overwrite existing
     * values if the pdb_weakclassification flag is set.
     */
    if (newpig.section && *newpig.section &&
        !((flags & pdb_weakclassification) && pigp->section && *pigp->section))
      pigp->section= newpig.section;
    if (newpig.priority != pri_unknown &&
        !((flags & pdb_weakclassification) && pigp->priority != pri_unknown)) {
      pigp->priority= newpig.priority;
      if (newpig.priority == pri_other) pigp->otherpriority= newpig.otherpriority;
    }

    /* Sort out the dependency mess. */
    copy_dependency_links(pigp,&pifp->depends,newpifp->depends,
                          (flags & pdb_recordavailable) ? 1 : 0);
    /* Leave the `depended' pointer alone, we've just gone to such
     * trouble to get it right :-).  The `depends' pointer in
     * pifp was indeed also updated by copy_dependency_links,
     * but since the value was that from newpifp anyway there's
     * no need to copy it back.
     */
    newpifp->depended= pifp->depended;

    /* Copy across data */
    memcpy(pifp,newpifp,sizeof(struct pkginfoperfile));
    if (!(flags & pdb_recordavailable)) {
      pigp->want= newpig.want;
      pigp->eflag= newpig.eflag;
      pigp->status= newpig.status;
      pigp->configversion= newpig.configversion;
      pigp->files= NULL;

      pigp->trigpend_head = newpig.trigpend_head;
      pigp->trigaw = newpig.trigaw;
      for (ta = pigp->trigaw.head; ta; ta = ta->sameaw.next) {
        assert(ta->aw == &newpig);
        ta->aw = pigp;
        /* ->othertrigaw_head is updated by trig_note_aw in *(findpackage())
         * rather than in newpig */
      }

    } else if (!(flags & pdb_ignorefiles)) {
      pigp->files= newpig.files;
    }

    if (donep) *donep= pigp;
    pdone++;
    if (EOF_mmap(dataptr, endptr)) break;
    if (c == '\n')
      ps.lno++;
  }
  if (data != NULL) {
#ifdef USE_MMAP
    munmap(data, st.st_size);
#else
    free(data);
#endif
  }
  free(value);
  pop_cleanup(ehflag_normaltidy);
  if (close(fd)) ohshite(_("failed to close after read: `%.255s'"),filename);
  if (donep && !pdone) ohshit(_("no package information in `%.255s'"),filename);

  if (warncount)
    *warncount = ps.warncount;

  return pdone;
}
Esempio n. 20
0
/*
 * client-declaration :==
 *	SEND option-decl |
 *	DEFAULT option-decl |
 *	SUPERSEDE option-decl |
 *	PREPEND option-decl |
 *	APPEND option-decl |
 *	hardware-declaration |
 *	REQUEST option-list |
 *	REQUIRE option-list |
 *	TIMEOUT number |
 *	RETRY number |
 *	REBOOT number |
 *	SELECT_TIMEOUT number |
 *	SCRIPT string |
 *	interface-declaration |
 *	LEASE client-lease-statement |
 *	ALIAS client-lease-statement
 */
void
parse_client_statement(FILE *cfile, struct interface_info *ip,
    struct client_config *config)
{
	int		 token;
	char		*val;
	struct option	*option;

	switch (next_token(&val, cfile)) {
	case SEND:
		parse_option_decl(cfile, &config->send_options[0]);
		return;
	case DEFAULT:
		option = parse_option_decl(cfile, &config->defaults[0]);
		if (option)
			config->default_actions[option->code] = ACTION_DEFAULT;
		return;
	case SUPERSEDE:
		option = parse_option_decl(cfile, &config->defaults[0]);
		if (option)
			config->default_actions[option->code] =
			    ACTION_SUPERSEDE;
		return;
	case APPEND:
		option = parse_option_decl(cfile, &config->defaults[0]);
		if (option)
			config->default_actions[option->code] = ACTION_APPEND;
		return;
	case PREPEND:
		option = parse_option_decl(cfile, &config->defaults[0]);
		if (option)
			config->default_actions[option->code] = ACTION_PREPEND;
		return;
	case MEDIA:
		parse_string_list(cfile, &config->media, 1);
		return;
	case HARDWARE:
		if (ip)
			parse_hardware_param(cfile, &ip->hw_address);
		else {
			parse_warn("hardware address parameter %s",
				    "not allowed here.");
			skip_to_semi(cfile);
		}
		return;
	case REQUEST:
		config->requested_option_count =
			parse_option_list(cfile, config->requested_options);
		return;
	case REQUIRE:
		memset(config->required_options, 0,
		    sizeof(config->required_options));
		parse_option_list(cfile, config->required_options);
		return;
	case TIMEOUT:
		parse_lease_time(cfile, &config->timeout);
		return;
	case RETRY:
		parse_lease_time(cfile, &config->retry_interval);
		return;
	case SELECT_TIMEOUT:
		parse_lease_time(cfile, &config->select_interval);
		return;
	case REBOOT:
		parse_lease_time(cfile, &config->reboot_timeout);
		return;
	case BACKOFF_CUTOFF:
		parse_lease_time(cfile, &config->backoff_cutoff);
		return;
	case INITIAL_INTERVAL:
		parse_lease_time(cfile, &config->initial_interval);
		return;
	case SCRIPT:
		config->script_name = parse_string(cfile);
		return;
	case INTERFACE:
		if (ip)
			parse_warn("nested interface declaration.");
		parse_interface_declaration(cfile, config);
		return;
	case LEASE:
		parse_client_lease_statement(cfile, 1);
		return;
	case ALIAS:
		parse_client_lease_statement(cfile, 2);
		return;
	case REJECT:
		parse_reject_statement(cfile, config);
		return;
	default:
		parse_warn("expecting a statement.");
		skip_to_semi(cfile);
		break;
	}
	token = next_token(&val, cfile);
	if (token != SEMI) {
		parse_warn("semicolon expected.");
		skip_to_semi(cfile);
	}
}
Esempio n. 21
0
/*
 * client-lease-declaration :==
 *	BOOTP |
 *	INTERFACE string |
 *	FIXED_ADDR ip_address |
 *	FILENAME string |
 *	SERVER_NAME string |
 *	OPTION option-decl |
 *	RENEW time-decl |
 *	REBIND time-decl |
 *	EXPIRE time-decl
 */
void
parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
    struct interface_info **ipp)
{
	int			 token;
	char			*val;
	struct interface_info	*ip;

	switch (next_token(&val, cfile)) {
	case BOOTP:
		lease->is_bootp = 1;
		break;
	case INTERFACE:
		token = next_token(&val, cfile);
		if (token != STRING) {
			parse_warn("expecting interface name (in quotes).");
			skip_to_semi(cfile);
			break;
		}
		ip = interface_or_dummy(val);
		*ipp = ip;
		break;
	case FIXED_ADDR:
		if (!parse_ip_addr(cfile, &lease->address))
			return;
		break;
	case MEDIUM:
		parse_string_list(cfile, &lease->medium, 0);
		return;
	case FILENAME:
		lease->filename = parse_string(cfile);
		return;
	case NEXT_SERVER:
		if (!parse_ip_addr(cfile, &lease->nextserver))
			return;
		break;
	case SERVER_NAME:
		lease->server_name = parse_string(cfile);
		return;
	case RENEW:
		lease->renewal = parse_date(cfile);
		return;
	case REBIND:
		lease->rebind = parse_date(cfile);
		return;
	case EXPIRE:
		lease->expiry = parse_date(cfile);
		return;
	case OPTION:
		parse_option_decl(cfile, lease->options);
		return;
	default:
		parse_warn("expecting lease declaration.");
		skip_to_semi(cfile);
		break;
	}
	token = next_token(&val, cfile);
	if (token != SEMI) {
		parse_warn("expecting semicolon.");
		skip_to_semi(cfile);
	}
}
Esempio n. 22
0
/*
 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
 *		NUMBER COLON NUMBER COLON NUMBER SEMI
 *
 * Dates are always in GMT; first number is day of week; next is
 * year/month/day; next is hours:minutes:seconds on a 24-hour
 * clock.
 */
time_t
parse_date(FILE *cfile)
{
	static int months[11] = { 31, 59, 90, 120, 151, 181,
	    212, 243, 273, 304, 334 };
	int guess, token;
	struct tm tm;
	char *val;

	/* Day of week... */
	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("numeric day of week expected.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}
	tm.tm_wday = atoi(val);

	/* Year... */
	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("numeric year expected.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}
	tm.tm_year = atoi(val);
	if (tm.tm_year > 1900)
		tm.tm_year -= 1900;

	/* Slash separating year from month... */
	token = next_token(&val, cfile);
	if (token != SLASH) {
		parse_warn("expected slash separating year from month.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}

	/* Month... */
	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("numeric month expected.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}
	tm.tm_mon = atoi(val) - 1;

	/* Slash separating month from day... */
	token = next_token(&val, cfile);
	if (token != SLASH) {
		parse_warn("expected slash separating month from day.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}

	/* Month... */
	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("numeric day of month expected.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}
	tm.tm_mday = atoi(val);

	/* Hour... */
	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("numeric hour expected.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}
	tm.tm_hour = atoi(val);

	/* Colon separating hour from minute... */
	token = next_token(&val, cfile);
	if (token != COLON) {
		parse_warn("expected colon separating hour from minute.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}

	/* Minute... */
	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("numeric minute expected.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}
	tm.tm_min = atoi(val);

	/* Colon separating minute from second... */
	token = next_token(&val, cfile);
	if (token != COLON) {
		parse_warn("expected colon separating hour from minute.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}

	/* Minute... */
	token = next_token(&val, cfile);
	if (token != NUMBER) {
		parse_warn("numeric minute expected.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (0);
	}
	tm.tm_sec = atoi(val);
	tm.tm_isdst = 0;

	/* XXX: We assume that mktime does not use tm_yday. */
	tm.tm_yday = 0;

	/* Make sure the date ends in a semicolon... */
	token = next_token(&val, cfile);
	if (token != SEMI) {
		parse_warn("semicolon expected.");
		skip_to_semi(cfile);
		return (0);
	}

	/* Guess the time value... */
	guess = ((((((365 * (tm.tm_year - 70) +	/* Days in years since '70 */
		    (tm.tm_year - 69) / 4 +	/* Leap days since '70 */
		    (tm.tm_mon			/* Days in months this year */
		    ? months[tm.tm_mon - 1]
		    : 0) +
		    (tm.tm_mon > 1 &&		/* Leap day this year */
		    !((tm.tm_year - 72) & 3)) +
		    tm.tm_mday - 1) * 24) +	/* Day of month */
		    tm.tm_hour) * 60) +
		    tm.tm_min) * 60) + tm.tm_sec;

	/*
	 * This guess could be wrong because of leap seconds or other
	 * weirdness we don't know about that the system does.   For
	 * now, we're just going to accept the guess, but at some point
	 * it might be nice to do a successive approximation here to get
	 * an exact value.   Even if the error is small, if the server
	 * is restarted frequently (and thus the lease database is
	 * reread), the error could accumulate into something
	 * significant.
	 */
	return (guess);
}
Esempio n. 23
0
/*
 * No BNF for numeric aggregates - that's defined by the caller.  What
 * this function does is to parse a sequence of numbers separated by the
 * token specified in separator.  If max is zero, any number of numbers
 * will be parsed; otherwise, exactly max numbers are expected.  Base
 * and size tell us how to internalize the numbers once they've been
 * tokenized.
 */
unsigned char *
parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
    int separator, int base, int size)
{
	unsigned char *bufp = buf, *s = NULL;
	int token, count = 0;
	char *val, *t;
	size_t valsize;
	pair c = NULL;

	if (!bufp && *max) {
		bufp = malloc(*max * size / 8);
		if (!bufp)
			error("can't allocate space for numeric aggregate");
	} else
		s = bufp;

	do {
		if (count) {
			token = peek_token(&val, cfile);
			if (token != separator) {
				if (!*max)
					break;
				if (token != RBRACE && token != LBRACE)
					token = next_token(&val, cfile);
				parse_warn("too few numbers.");
				if (token != SEMI)
					skip_to_semi(cfile);
				return (NULL);
			}
			token = next_token(&val, cfile);
		}
		token = next_token(&val, cfile);

		if (token == EOF) {
			parse_warn("unexpected end of file");
			break;
		}

		/* Allow NUMBER_OR_NAME if base is 16. */
		if (token != NUMBER &&
		    (base != 16 || token != NUMBER_OR_NAME)) {
			parse_warn("expecting numeric value.");
			skip_to_semi(cfile);
			return (NULL);
		}
		/*
		 * If we can, convert the number now; otherwise, build a
		 * linked list of all the numbers.
		 */
		if (s) {
			convert_num(s, val, base, size);
			s += size / 8;
		} else {
			valsize = strlen(val) + 1;
			t = malloc(valsize);
			if (!t)
				error("no temp space for number.");
			memcpy(t, val, valsize);
			c = cons(t, c);
		}
	} while (++count != *max);

	/* If we had to cons up a list, convert it now. */
	if (c) {
		bufp = malloc(count * size / 8);
		if (!bufp)
			error("can't allocate space for numeric aggregate.");
		s = bufp + count - size / 8;
		*max = count;
	}
	while (c) {
		pair cdr = c->cdr;
		convert_num(s, (char *)c->car, base, size);
		s -= size / 8;
		/* Free up temp space. */
		free(c->car);
		free(c);
		c = cdr;
	}
	return (bufp);
}
Esempio n. 24
0
struct option *
parse_option_decl(FILE *cfile, struct option_data *options)
{
	char		*val;
	int		 token;
	u_int8_t	 buf[4];
	u_int8_t	 hunkbuf[1024];
	int		 hunkix = 0;
	char		*vendor;
	char		*fmt;
	struct universe	*universe;
	struct option	*option;
	struct iaddr	 ip_addr;
	u_int8_t	*dp;
	int		 len;
	int		 nul_term = 0;

	token = next_token(&val, cfile);
	if (!is_identifier(token)) {
		parse_warn("expecting identifier after option keyword.");
		if (token != SEMI)
			skip_to_semi(cfile);
		return (NULL);
	}
	if ((vendor = strdup(val)) == NULL)
		error("no memory for vendor information.");

	token = peek_token(&val, cfile);
	if (token == DOT) {
		/* Go ahead and take the DOT token... */
		token = next_token(&val, cfile);

		/* The next token should be an identifier... */
		token = next_token(&val, cfile);
		if (!is_identifier(token)) {
			parse_warn("expecting identifier after '.'");
			if (token != SEMI)
				skip_to_semi(cfile);
			return (NULL);
		}

		/* Look up the option name hash table for the specified
		   vendor. */
		universe = ((struct universe *)hash_lookup(&universe_hash,
		    (unsigned char *)vendor, 0));
		/* If it's not there, we can't parse the rest of the
		   declaration. */
		if (!universe) {
			parse_warn("no vendor named %s.", vendor);
			skip_to_semi(cfile);
			return (NULL);
		}
	} else {
		/* Use the default hash table, which contains all the
		   standard dhcp option names. */
		val = vendor;
		universe = &dhcp_universe;
	}

	/* Look up the actual option info... */
	option = (struct option *)hash_lookup(universe->hash,
	    (unsigned char *)val, 0);

	/* If we didn't get an option structure, it's an undefined option. */
	if (!option) {
		if (val == vendor)
			parse_warn("no option named %s", val);
		else
			parse_warn("no option named %s for vendor %s",
				    val, vendor);
		skip_to_semi(cfile);
		return (NULL);
	}

	/* Free the initial identifier token. */
	free(vendor);

	/* Parse the option data... */
	do {
		for (fmt = option->format; *fmt; fmt++) {
			if (*fmt == 'A')
				break;
			switch (*fmt) {
			case 'X':
				len = parse_X(cfile, &hunkbuf[hunkix],
				    sizeof(hunkbuf) - hunkix);
				hunkix += len;
				break;
			case 't': /* Text string... */
				token = next_token(&val, cfile);
				if (token != STRING) {
					parse_warn("expecting string.");
					skip_to_semi(cfile);
					return (NULL);
				}
				len = strlen(val);
				if (hunkix + len + 1 > sizeof(hunkbuf)) {
					parse_warn("option data buffer %s",
					    "overflow");
					skip_to_semi(cfile);
					return (NULL);
				}
				memcpy(&hunkbuf[hunkix], val, len + 1);
				nul_term = 1;
				hunkix += len;
				break;
			case 'I': /* IP address. */
				if (!parse_ip_addr(cfile, &ip_addr))
					return (NULL);
				len = ip_addr.len;
				dp = ip_addr.iabuf;
alloc:
				if (hunkix + len > sizeof(hunkbuf)) {
					parse_warn("option data buffer "
					    "overflow");
					skip_to_semi(cfile);
					return (NULL);
				}
				memcpy(&hunkbuf[hunkix], dp, len);
				hunkix += len;
				break;
			case 'L':	/* Unsigned 32-bit integer... */
			case 'l':	/* Signed 32-bit integer... */
				token = next_token(&val, cfile);
				if (token != NUMBER) {
need_number:
					parse_warn("expecting number.");
					if (token != SEMI)
						skip_to_semi(cfile);
					return (NULL);
				}
				convert_num(buf, val, 0, 32);
				len = 4;
				dp = buf;
				goto alloc;
			case 's':	/* Signed 16-bit integer. */
			case 'S':	/* Unsigned 16-bit integer. */
				token = next_token(&val, cfile);
				if (token != NUMBER)
					goto need_number;
				convert_num(buf, val, 0, 16);
				len = 2;
				dp = buf;
				goto alloc;
			case 'b':	/* Signed 8-bit integer. */
			case 'B':	/* Unsigned 8-bit integer. */
				token = next_token(&val, cfile);
				if (token != NUMBER)
					goto need_number;
				convert_num(buf, val, 0, 8);
				len = 1;
				dp = buf;
				goto alloc;
			case 'f': /* Boolean flag. */
				token = next_token(&val, cfile);
				if (!is_identifier(token)) {
					parse_warn("expecting identifier.");
bad_flag:
					if (token != SEMI)
						skip_to_semi(cfile);
					return (NULL);
				}
				if (!strcasecmp(val, "true") ||
				    !strcasecmp(val, "on"))
					buf[0] = 1;
				else if (!strcasecmp(val, "false") ||
				    !strcasecmp(val, "off"))
					buf[0] = 0;
				else {
					parse_warn("expecting boolean.");
					goto bad_flag;
				}
				len = 1;
				dp = buf;
				goto alloc;
			default:
				warning("Bad format %c in parse_option_param.",
				    *fmt);
				skip_to_semi(cfile);
				return (NULL);
			}
		}
		token = next_token(&val, cfile);
	} while (*fmt == 'A' && token == COMMA);

	if (token != SEMI) {
		parse_warn("semicolon expected.");
		skip_to_semi(cfile);
		return (NULL);
	}

	options[option->code].data = malloc(hunkix + nul_term);
	if (!options[option->code].data)
		error("out of memory allocating option data.");
	memcpy(options[option->code].data, hunkbuf, hunkix + nul_term);
	options[option->code].len = hunkix;
	return (option);
}
Esempio n. 25
0
/**
 * Verify and fixup the package structure being constructed.
 */
static void
pkg_parse_verify(struct parsedb_state *ps,
                 struct pkginfo *pkg, struct pkgbin *pkgbin)
{
  struct dependency *dep;
  struct deppossi *dop;

  parse_must_have_field(ps, pkg->set->name, "package name");

  /* XXX: We need to check for status != stat_halfinstalled as while
   * unpacking an unselected package, it will not have yet all data in
   * place. But we cannot check for > stat_halfinstalled as stat_configfiles
   * always should have those fields. */
  if ((ps->flags & pdb_recordavailable) ||
      (pkg->status != stat_notinstalled &&
       pkg->status != stat_halfinstalled)) {
    parse_ensure_have_field(ps, &pkgbin->description, "description");
    parse_ensure_have_field(ps, &pkgbin->maintainer, "maintainer");
    parse_must_have_field(ps, pkgbin->version.version, "version");
  }

  /* XXX: Versions before dpkg 1.10.19 did not preserve the Architecture
   * field in the status file. So there's still live systems with packages
   * in stat_configfiles, ignore those too for now. */
  if ((ps->flags & pdb_recordavailable) ||
      pkg->status > stat_halfinstalled) {
    /* We always want usable architecture information (as long as the package
     * is in such a state that it make sense), so that it can be used safely
     * on string comparisons and the like. */
    if (pkgbin->arch->type == arch_none)
      parse_warn(ps, _("missing %s"), "architecture");
    else if (pkgbin->arch->type == arch_empty)
      parse_warn(ps, _("empty value for %s"), "architecture");
  }
  if (pkgbin->arch->type == arch_empty)
    pkgbin->arch = dpkg_arch_get(arch_none);

  if (pkgbin->arch->type == arch_all && pkgbin->multiarch == multiarch_same)
    parse_error(ps, _("package has field '%s' but is architecture all"),
                "Multi-Arch: same");

  /* Initialize deps to be arch-specific unless stated otherwise. */
  for (dep = pkgbin->depends; dep; dep = dep->next)
    for (dop = dep->list; dop; dop = dop->next)
      if (!dop->arch)
        dop->arch = pkgbin->arch;

  /* Check the Config-Version information:
   * If there is a Config-Version it is definitely to be used, but
   * there shouldn't be one if the package is ‘installed’ (in which case
   * the Version and/or Revision will be copied) or if the package is
   * ‘not-installed’ (in which case there is no Config-Version). */
  if (!(ps->flags & pdb_recordavailable)) {
    if (pkg->configversion.version) {
      if (pkg->status == stat_installed || pkg->status == stat_notinstalled)
        parse_error(ps,
                    _("Configured-Version for package with inappropriate Status"));
    } else {
      if (pkg->status == stat_installed)
        pkg->configversion = pkgbin->version;
    }
  }

  if (pkg->trigaw.head &&
      (pkg->status <= stat_configfiles ||
       pkg->status >= stat_triggerspending))
    parse_error(ps,
                _("package has status %s but triggers are awaited"),
                statusinfos[pkg->status].name);
  else if (pkg->status == stat_triggersawaited && !pkg->trigaw.head)
    parse_error(ps,
                _("package has status triggers-awaited but no triggers awaited"));

  if (pkg->trigpend_head &&
      !(pkg->status == stat_triggerspending ||
        pkg->status == stat_triggersawaited))
    parse_error(ps,
                _("package has status %s but triggers are pending"),
                statusinfos[pkg->status].name);
  else if (pkg->status == stat_triggerspending && !pkg->trigpend_head)
    parse_error(ps,
                _("package has status triggers-pending but no triggers "
                  "pending"));

  /* FIXME: There was a bug that could make a not-installed package have
   * conffiles, so we check for them here and remove them (rather than
   * calling it an error, which will do at some point). */
  if (!(ps->flags & pdb_recordavailable) &&
      pkg->status == stat_notinstalled &&
      pkgbin->conffiles) {
    parse_warn(ps,
               _("Package which in state not-installed has conffiles, "
                 "forgetting them"));
    pkgbin->conffiles = NULL;
  }

  /* XXX: Mark not-installed leftover packages for automatic removal on
   * next database dump. This code can be removed after dpkg 1.16.x, when
   * there's guarantee that no leftover is found on the status file on
   * major distributions. */
  if (!(ps->flags & pdb_recordavailable) &&
      pkg->status == stat_notinstalled &&
      pkg->eflag == eflag_ok &&
      (pkg->want == want_purge ||
       pkg->want == want_deinstall ||
       pkg->want == want_hold)) {
    pkg_set_want(pkg, want_unknown);
  }
}
Esempio n. 26
0
/*
 * Begin a macro.
 *
 * Once we figure out the type of the thing that we're supposed to dump (struct,
 * union, or enum), we select the proper type-specific ops-vector for dumping.
 */
static int
fth_section_init(char *fullname)
{
	ctf_id_t ltid = 0, tid;
	char *curtype, *lpart, *part, *npart;
	int lkind = 0, kind;

	curtype = xstrdup(fullname);
	lpart = NULL;
	part = strtok(fullname, ".");

	/*
	 * First figure out what sort of type we're looking at.  Life would be
	 * simple if we were only going to get type names, but it's not - we
	 * could also get `type.member'.  In that case, we need to figure out
	 * (and dump) the type of `member' instead.
	 */
	for (;;) {
		if (lpart == NULL) {
			/* First part - the struct name */
			if ((tid = find_type(part)) == CTF_ERR ||
			    (tid = ctf_type_resolve(ctf, tid)) == CTF_ERR ||
			    (kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
				free(curtype);
				return (parse_warn("Couldn't find %s: %s",
				    part, ctf_errmsg(ctf_errno(ctf))));
			}
		} else {
			/* Second (or more) part - the member name */
			if (lkind != CTF_K_STRUCT && lkind != CTF_K_UNION) {
				free(curtype);
				return (parse_warn("%s isn't a struct/union",
				    lpart));
			}

			if ((tid = find_member(ltid, part)) <= 0) {
				free(curtype);
				return (parse_warn("%s isn't a member of %s",
				    part, lpart));
			}

			if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
				free(curtype);
				return (parse_warn("Can't get kind for %s",
				    part));
			}
		}

		/*
		 * Stop if there aren't any more parts.  We use `npart' here
		 * because we don't want to clobber part - we need it later.
		 */
		if ((npart = strtok(NULL, ".")) == NULL)
			break;

		lpart = part;
		ltid = tid;
		lkind = kind;

		part = npart;
	}

	/*
	 * Pick the right ops vector for dumping.
	 */
	switch (kind) {
	case CTF_K_STRUCT:
	case CTF_K_UNION:
		fth_type_ops = &fth_struct_ops;
		break;

	case CTF_K_ENUM:
		fth_type_ops = &fth_enum_ops;
		break;

	default:
		fth_type_ops = &fth_null_ops;
		free(curtype);
		return (parse_warn("%s isn't a struct, union, or enum", part));
	}

	fth_curtype = curtype;

	return (fth_type_ops->fto_header(tid));
}
Esempio n. 27
0
static int
fth_process_line(char *line)
{
	char *format = NULL;
	char *word, *name, *c;
	int nblank = 0;
	int n;

	if (strlen(line) == 0) {
		if (fth_section_end() < 0)
			return (-1);

		if (fth_copying == 1 || nblank++ == 1)
			(void) fprintf(out, "\n");
		return (0);
	} else
		nblank = 0;

	/* skip comments */
	if (line[0] == '\\')
		return (0);

	if (strcmp(line, "model_end") == 0) {
		fth_ignoring = 0;
		return (0);
	}

	if (fth_ignoring == 1)
		return (0);

	word = "model_start ";
	if (strncmp(line, word, strlen(word)) == 0) {
		for (c = line + strlen(word); isspace(*c); c++);
		if (strlen(c) == strlen(fth_model) &&
		    strncmp(c, fth_model, strlen(fth_model)) == 0)
			/* EMPTY - match */;
		else
			fth_ignoring = 1;
		return (0);
	}

	if (strcmp(line, "verbatim_end") == 0 ||
	    strcmp(line, "forth_end") == 0) {
		char *start = (strcmp(line, "verbatim_end") == 0 ?
		    "verbatim_begin" : "forth_start");

		if (fth_copying == 0) {
			(void) parse_warn("Found %s without matching %s",
			    line, start);
			if (fth_curtype != NULL)
				(void) fth_section_end();
			return (-1);
		}
		fth_copying = 0;
		return (0);
	}

	if (fth_copying == 1) {
		(void) fprintf(out, "%s\n", line);
		return (0);
	}

	if (strcmp(line, "verbatim_begin") == 0 ||
	    strcmp(line, "forth_start") == 0) {
		if (fth_curtype != NULL) {
			(void) parse_warn("Expected blank line between %s "
			    "macro and %s", fth_curtype, line);
			return (fth_section_end());
		}

		fth_copying = 1;
		return (0);
	}

	for (n = 1, word = strtok(line, " \t"); word != NULL;
	    word = strtok(NULL, " \t"), n++) {
		if (n == 1)
			name = word;
		else if (n == 2)
			format = word;
		else
			(void) parse_warn("Too many words");
	}

	return (fth_section_add_member(name, format));
}
Esempio n. 28
0
int
parse_option_decl(FILE *cfile, struct option_data *options)
{
	char		*val;
	int		 token;
	u_int8_t	 buf[4];
	u_int8_t	 hunkbuf[1024];
	int		 hunkix = 0;
	char		*fmt;
	struct iaddr	 ip_addr;
	u_int8_t	*dp;
	int		 len, code;
	int		 nul_term = 0;

	token = next_token(&val, cfile);
	if (!is_identifier(token)) {
		parse_warn("expecting identifier after option keyword.");
		if (token != ';')
			skip_to_semi(cfile);
		return (-1);
	}

	/* Look up the actual option info. */
	fmt = NULL;
	for (code = 0; code < 256; code++)
		if (strcmp(dhcp_options[code].name, val) == 0)
			break;

	if (code > 255) {
		parse_warn("no option named %s", val);
		skip_to_semi(cfile);
		return (-1);
	}

	/* Parse the option data... */
	do {
		for (fmt = dhcp_options[code].format; *fmt; fmt++) {
			if (*fmt == 'A')
				break;
			switch (*fmt) {
			case 'X':
				len = parse_X(cfile, &hunkbuf[hunkix],
				    sizeof(hunkbuf) - hunkix);
				hunkix += len;
				break;
			case 't': /* Text string... */
				token = next_token(&val, cfile);
				if (token != TOK_STRING) {
					parse_warn("expecting string.");
					skip_to_semi(cfile);
					return (-1);
				}
				len = strlen(val);
				if (hunkix + len + 1 > sizeof(hunkbuf)) {
					parse_warn("option data buffer %s",
					    "overflow");
					skip_to_semi(cfile);
					return (-1);
				}
				memcpy(&hunkbuf[hunkix], val, len + 1);
				nul_term = 1;
				hunkix += len;
				break;
			case 'I': /* IP address. */
				if (!parse_ip_addr(cfile, &ip_addr))
					return (-1);
				len = ip_addr.len;
				dp = ip_addr.iabuf;
alloc:
				if (hunkix + len > sizeof(hunkbuf)) {
					parse_warn("option data buffer "
					    "overflow");
					skip_to_semi(cfile);
					return (-1);
				}
				memcpy(&hunkbuf[hunkix], dp, len);
				hunkix += len;
				break;
			case 'L':	/* Unsigned 32-bit integer... */
			case 'l':	/* Signed 32-bit integer... */
				token = next_token(&val, cfile);
				if (token != TOK_NUMBER) {
need_number:
					parse_warn("expecting number.");
					if (token != ';')
						skip_to_semi(cfile);
					return (-1);
				}
				convert_num(buf, val, 0, 32);
				len = 4;
				dp = buf;
				goto alloc;
			case 's':	/* Signed 16-bit integer. */
			case 'S':	/* Unsigned 16-bit integer. */
				token = next_token(&val, cfile);
				if (token != TOK_NUMBER)
					goto need_number;
				convert_num(buf, val, 0, 16);
				len = 2;
				dp = buf;
				goto alloc;
			case 'b':	/* Signed 8-bit integer. */
			case 'B':	/* Unsigned 8-bit integer. */
				token = next_token(&val, cfile);
				if (token != TOK_NUMBER)
					goto need_number;
				convert_num(buf, val, 0, 8);
				len = 1;
				dp = buf;
				goto alloc;
			case 'f': /* Boolean flag. */
				token = next_token(&val, cfile);
				if (!is_identifier(token)) {
					parse_warn("expecting identifier.");
bad_flag:
					if (token != ';')
						skip_to_semi(cfile);
					return (-1);
				}
				if (!strcasecmp(val, "true") ||
				    !strcasecmp(val, "on"))
					buf[0] = 1;
				else if (!strcasecmp(val, "false") ||
				    !strcasecmp(val, "off"))
					buf[0] = 0;
				else {
					parse_warn("expecting boolean.");
					goto bad_flag;
				}
				len = 1;
				dp = buf;
				goto alloc;
			default:
				warning("Bad format %c in parse_option_param.",
				    *fmt);
				skip_to_semi(cfile);
				return (-1);
			}
		}
		token = next_token(&val, cfile);
	} while (*fmt == 'A' && token == ',');

	if (token != ';') {
		parse_warn("semicolon expected.");
		skip_to_semi(cfile);
		return (-1);
	}

	options[code].data = malloc(hunkix + nul_term);
	if (!options[code].data)
		error("out of memory allocating option data.");
	memcpy(options[code].data, hunkbuf, hunkix + nul_term);
	options[code].len = hunkix;
	return (code);
}
Esempio n. 29
0
/*
 * client-lease-statement :==
 *	RBRACE client-lease-declarations LBRACE
 *
 *	client-lease-declarations :==
 *		<nil> |
 *		client-lease-declaration |
 *		client-lease-declarations client-lease-declaration
 */
void
parse_client_lease_statement(FILE *cfile, int is_static)
{
	struct client_lease	*lease, *lp, *pl;
	int			 token;
	char			*val;

	token = next_token(&val, cfile);
	if (token != '{') {
		parse_warn("expecting left brace.");
		skip_to_semi(cfile);
		return;
	}

	lease = malloc(sizeof(struct client_lease));
	if (!lease)
		error("no memory for lease.");
	memset(lease, 0, sizeof(*lease));
	lease->is_static = is_static;

	do {
		token = peek_token(&val, cfile);
		if (token == EOF) {
			parse_warn("unterminated lease declaration.");
			return;
		}
		if (token == '}')
			break;
		parse_client_lease_declaration(cfile, lease);
	} while (1);
	token = next_token(&val, cfile);

	/* If the lease declaration didn't include an interface
	 * declaration that we recognized, it's of no use to us.
	 */
	if (!ifi) {
		free_client_lease(lease);
		return;
	}

	/* If this is an alias lease, it doesn't need to be sorted in. */
	if (is_static == 2) {
		client->alias = lease;
		return;
	}

	/*
	 * The new lease may supersede a lease that's not the active
	 * lease but is still on the lease list, so scan the lease list
	 * looking for a lease with the same address, and if we find it,
	 * toss it.
	 */
	pl = NULL;
	for (lp = client->leases; lp; lp = lp->next) {
		if (lp->address.len == lease->address.len &&
		    !memcmp(lp->address.iabuf, lease->address.iabuf,
		    lease->address.len)) {
			if (pl)
				pl->next = lp->next;
			else
				client->leases = lp->next;
			free_client_lease(lp);
			break;
		}
	}

	/*
	 * If this is a preloaded lease, just put it on the list of
	 * recorded leases - don't make it the active lease.
	 */
	if (is_static) {
		lease->next = client->leases;
		client->leases = lease;
		return;
	}

	/*
	 * The last lease in the lease file on a particular interface is
	 * the active lease for that interface.    Of course, we don't
	 * know what the last lease in the file is until we've parsed
	 * the whole file, so at this point, we assume that the lease we
	 * just parsed is the active lease for its interface.   If
	 * there's already an active lease for the interface, and this
	 * lease is for the same ip address, then we just toss the old
	 * active lease and replace it with this one.   If this lease is
	 * for a different address, then if the old active lease has
	 * expired, we dump it; if not, we put it on the list of leases
	 * for this interface which are still valid but no longer
	 * active.
	 */
	if (client->active) {
		if (client->active->expiry < cur_time)
			free_client_lease(client->active);
		else if (client->active->address.len ==
		    lease->address.len &&
		    !memcmp(client->active->address.iabuf,
		    lease->address.iabuf, lease->address.len))
			free_client_lease(client->active);
		else {
			client->active->next = client->leases;
			client->leases = client->active;
		}
	}
	client->active = lease;

	/* Phew. */
}
Esempio n. 30
0
/*
 * client-declaration :==
 *	TOK_SEND option-decl |
 *	TOK_DEFAULT option-decl |
 *	TOK_SUPERSEDE option-decl |
 *	TOK_APPEND option-decl |
 *	TOK_PREPEND option-decl |
 *	TOK_MEDIA string-list |
 *	hardware-declaration |
 *	TOK_REQUEST option-list |
 *	TOK_REQUIRE option-list |
 *	TOK_TIMEOUT number |
 *	TOK_RETRY number |
 *	TOK_SELECT_TIMEOUT number |
 *	TOK_REBOOT number |
 *	TOK_BACKOFF_CUTOFF number |
 *	TOK_INITIAL_INTERVAL number |
 *	TOK_SCRIPT string |
 *	interface-declaration |
 *	TOK_LEASE client-lease-statement |
 *	TOK_ALIAS client-lease-statement |
 *	TOK_REJECT reject-statement
 */
void
parse_client_statement(FILE *cfile)
{
	char *val;
	int token, code;

	switch (next_token(&val, cfile)) {
	case TOK_SEND:
		parse_option_decl(cfile, &config->send_options[0]);
		return;
	case TOK_DEFAULT:
		code = parse_option_decl(cfile, &config->defaults[0]);
		if (code != -1)
			config->default_actions[code] = ACTION_DEFAULT;
		return;
	case TOK_SUPERSEDE:
		code = parse_option_decl(cfile, &config->defaults[0]);
		if (code != -1)
			config->default_actions[code] = ACTION_SUPERSEDE;
		return;
	case TOK_APPEND:
		code = parse_option_decl(cfile, &config->defaults[0]);
		if (code != -1)
			config->default_actions[code] = ACTION_APPEND;
		return;
	case TOK_PREPEND:
		code = parse_option_decl(cfile, &config->defaults[0]);
		if (code != -1)
			config->default_actions[code] = ACTION_PREPEND;
		return;
	case TOK_MEDIA:
		parse_string_list(cfile, &config->media, 1);
		return;
	case TOK_HARDWARE:
		parse_hardware_param(cfile, &ifi->hw_address);
		return;
	case TOK_REQUEST:
		config->requested_option_count =
			parse_option_list(cfile, config->requested_options);
		return;
	case TOK_REQUIRE:
		memset(config->required_options, 0,
		    sizeof(config->required_options));
		parse_option_list(cfile, config->required_options);
		return;
	case TOK_LINK_TIMEOUT:
		parse_lease_time(cfile, &config->link_timeout);
		return;
	case TOK_TIMEOUT:
		parse_lease_time(cfile, &config->timeout);
		return;
	case TOK_RETRY:
		parse_lease_time(cfile, &config->retry_interval);
		return;
	case TOK_SELECT_TIMEOUT:
		parse_lease_time(cfile, &config->select_interval);
		return;
	case TOK_REBOOT:
		parse_lease_time(cfile, &config->reboot_timeout);
		return;
	case TOK_BACKOFF_CUTOFF:
		parse_lease_time(cfile, &config->backoff_cutoff);
		return;
	case TOK_INITIAL_INTERVAL:
		parse_lease_time(cfile, &config->initial_interval);
		return;
	case TOK_SCRIPT:
		config->script_name = parse_string(cfile);
		return;
	case TOK_INTERFACE:
		parse_interface_declaration(cfile);
		return;
	case TOK_LEASE:
		parse_client_lease_statement(cfile, 1);
		return;
	case TOK_ALIAS:
		parse_client_lease_statement(cfile, 2);
		return;
	case TOK_REJECT:
		parse_reject_statement(cfile);
		return;
	default:
		parse_warn("expecting a statement.");
		skip_to_semi(cfile);
		break;
	}
	token = next_token(&val, cfile);
	if (token != ';') {
		parse_warn("semicolon expected.");
		skip_to_semi(cfile);
	}
}