A format change can now hit only one activity instead of the whole file.
Sadf has also been updated to be able to display activities with
unknown format (sadf -H).
xxxx/xx/xx: Version 9.1.6 - Sebastien Godard (sysstat <at> orange.fr)
WARNING: Daily data files format has changed, and is *not*
compatible with the previous one! [0x2171]
+ * Added a new magical value for each activity in file.
+ A format change can now hit only one activity instead of
+ the whole file.
* Added hugepages utilization statistics to sar.
* [Ivana Varekova]: Moved manual pages to $prefix/share/man
instead of $prefix/man.
struct activity cpu_act = {
.id = A_CPU,
.options = AO_COLLECTED + AO_REMANENT + AO_GLOBAL_ITV + AO_MULTIPLE_OUTPUTS,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_cpu_nr,
.f_count2 = NULL,
struct activity pcsw_act = {
.id = A_PCSW,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity irq_act = {
.id = A_IRQ,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_irq_nr,
.f_count2 = NULL,
struct activity swap_act = {
.id = A_SWAP,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity paging_act = {
.id = A_PAGE,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity io_act = {
.id = A_IO,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity memory_act = {
.id = A_MEMORY,
.options = AO_COLLECTED + AO_MULTIPLE_OUTPUTS,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity ktables_act = {
.id = A_KTABLES,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity queue_act = {
.id = A_QUEUE,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity serial_act = {
.id = A_SERIAL,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_serial_nr,
.f_count2 = NULL,
struct activity disk_act = {
.id = A_DISK,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_disk_nr,
.f_count2 = NULL,
struct activity net_dev_act = {
.id = A_NET_DEV,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_iface_nr,
.f_count2 = NULL,
struct activity net_edev_act = {
.id = A_NET_EDEV,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_iface_nr,
.f_count2 = NULL,
struct activity net_nfs_act = {
.id = A_NET_NFS,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_nfsd_act = {
.id = A_NET_NFSD,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_sock_act = {
.id = A_NET_SOCK,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_ip_act = {
.id = A_NET_IP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_eip_act = {
.id = A_NET_EIP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_icmp_act = {
.id = A_NET_ICMP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_eicmp_act = {
.id = A_NET_EICMP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_tcp_act = {
.id = A_NET_TCP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_etcp_act = {
.id = A_NET_ETCP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_udp_act = {
.id = A_NET_UDP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_sock6_act = {
.id = A_NET_SOCK6,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_ip6_act = {
.id = A_NET_IP6,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_eip6_act = {
.id = A_NET_EIP6,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_icmp6_act = {
.id = A_NET_ICMP6,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_eicmp6_act = {
.id = A_NET_EICMP6,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity net_udp6_act = {
.id = A_NET_UDP6,
.options = AO_CLOSE_MARKUP,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
struct activity pwr_cpufreq_act = {
.id = A_PWR_CPUFREQ,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_cpu_nr,
.f_count2 = NULL,
struct activity pwr_fan_act = {
.id = A_PWR_FAN,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_fan_nr,
.f_count2 = NULL,
struct activity pwr_temp_act = {
.id = A_PWR_TEMP,
.options = AO_NULL,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_temp_nr,
.f_count2 = NULL,
struct activity pwr_in_act = {
.id = A_PWR_IN,
.options = AO_CLOSE_MARKUP,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = wrap_get_in_nr,
.f_count2 = NULL,
struct activity huge_act = {
.id = A_HUGE,
.options = AO_COLLECTED,
+ .magic = ACTIVITY_MAGIC_BASE,
#ifdef SOURCE_SADC
.f_count = NULL,
.f_count2 = NULL,
* Activity options (AO_SELECTED, ...)
*/
unsigned int options;
+ /*
+ * Activity magical number. This number changes when activity format in file
+ * is no longer compatible with the format of that same activity from
+ * previous versions.
+ */
+ unsigned int magic;
/*
* The f_count() function is used to count the number of
* items (serial lines, network interfaces, etc.) -> @nr
#define FILE_HEADER_SIZE (sizeof(struct file_header))
+/*
+ * Base magical number for activities.
+ */
+#define ACTIVITY_MAGIC_BASE 0x8a
+/*
+ * Magical value used for activities with
+ * unknown format (used for sadf -H only).
+ */
+#define ACTIVITY_MAGIC_UNKNOWN 0x89
+
/* List of activities saved in file */
struct file_activity {
/*
* Identification value of activity.
*/
unsigned int id __attribute__ ((aligned (4)));
+ /*
+ * Activity magical number.
+ */
+ unsigned int magic __attribute__ ((packed));
/*
* Number of items for this activity.
*/
for (i = 0; i < act_nr; i++, fal++) {
- if ((p = get_activity_position(act, fal->id)) < 0) {
+ if (((p = get_activity_position(act, fal->id)) < 0) ||
+ (act[p]->magic != fal->magic)) {
/*
* Ignore current activity in file, which is unknown to
- * current sysstat version.
+ * current sysstat version or has an unknown format.
*/
if (lseek(ifd, fal->size * fal->nr * fal->nr2, SEEK_CUR) < (fal->size * fal->nr * fal->nr2)) {
close(ifd);
handle_invalid_sa_file(ifd, file_magic, dfile, 0);
}
+ if ((p = get_activity_position(act, fal->id)) < 0)
+ /* Unknown activity */
+ continue;
+
+ if (act[p]->magic != fal->magic) {
+ /* Bad magical number */
+ if (ignore) {
+ /*
+ * This is how sadf -H knows that this
+ * activity has an unknown format.
+ */
+ act[p]->magic = ACTIVITY_MAGIC_UNKNOWN;
+ }
+ else
+ continue;
+ }
+
if (fal->id == A_CPU) {
a_cpu = TRUE;
}
- if ((p = get_activity_position(act, fal->id)) >= 0) {
- if (fal->size > act[p]->msize) {
- act[p]->msize = fal->size;
- }
- act[p]->fsize = fal->size;
- act[p]->nr = fal->nr;
- act[p]->nr2 = fal->nr2;
- id_seq[j++] = fal->id;
+ if (fal->size > act[p]->msize) {
+ act[p]->msize = fal->size;
}
+ act[p]->fsize = fal->size;
+ act[p]->nr = fal->nr;
+ act[p]->nr2 = fal->nr2;
+ /*
+ * This is a known activity with a known format
+ * (magical number). Only such activities will be displayed.
+ * (Well, this may also be an unknown format if we have entered sadf -H.)
+ */
+ id_seq[j++] = fal->id;
}
if (!a_cpu) {
- /* CPU activity should always be in file */
+ /*
+ * CPU activity should always be in file
+ * and have a known format (expected magical number).
+ */
handle_invalid_sa_file(ifd, file_magic, dfile, 0);
}
act[i]->nr2 = (*act[i]->f_count2)(act[i]);
}
/* else act[i]->nr2 is a constant and doesn't need to be calculated */
+
if (!act[i]->nr2) {
act[i]->nr = 0;
}
* Fill system activity file header, then write it (or print it if stdout).
*
* IN:
- * @fd Output file descriptor. May be stdout.
+ * @fd Output file descriptor. May be stdout.
***************************************************************************
*/
void setup_file_hdr(int fd)
continue;
if (IS_COLLECTED(act[p]->options)) {
- file_act.id = act[p]->id;
- file_act.nr = act[p]->nr;
- file_act.nr2 = act[p]->nr2;
- file_act.size = act[p]->fsize;
+ file_act.id = act[p]->id;
+ file_act.magic = act[p]->magic;
+ file_act.nr = act[p]->nr;
+ file_act.nr2 = act[p]->nr2;
+ file_act.size = act[p]->fsize;
if ((n = write_all(fd, &file_act, FILE_ACTIVITY_SIZE))
!= FILE_ACTIVITY_SIZE)
* before the cron daemon is started to avoid conflict with sa1/sa2 scripts.
*
* IN:
- * @ofd Output file descriptor.
- * @rtype Record type to write (dummy or comment).
+ * @ofd Output file descriptor.
+ * @rtype Record type to write (dummy or comment).
***************************************************************************
*/
void write_special_record(int ofd, int rtype)
* Write stats (or print them if stdout).
*
* IN:
- * @ofd Output file descriptor. May be stdout.
+ * @ofd Output file descriptor. May be stdout.
***************************************************************************
*/
void write_stats(int ofd)
* Create a system activity daily data file.
*
* IN:
- * @ofile Name of output file.
+ * @ofile Name of output file.
*
* OUT:
- * @ofd Output file descriptor.
+ * @ofd Output file descriptor.
***************************************************************************
*/
void create_sa_file(int *ofd, char *ofile)
* Get descriptor for stdout.
*
* IN:
- * @stdfd A value >= 0 indicates that stats data should also
- * be written to stdout.
+ * @stdfd A value >= 0 indicates that stats data should also
+ * be written to stdout.
*
* OUT:
- * @stdfd Stdout file descriptor.
+ * @stdfd Stdout file descriptor.
***************************************************************************
*/
void open_stdout(int *stdfd)
* We may enter this function several times (when we rotate a file).
*
* IN:
- * @ofile Name of output file.
+ * @ofile Name of output file.
*
* OUT:
- * @ofd Output file descriptor.
+ * @ofd Output file descriptor.
***************************************************************************
*/
void open_ofile(int *ofd, char ofile[])
p = get_activity_position(act, file_act.id);
- if ((p < 0) || (act[p]->fsize != file_act.size))
- /* Unknown activity in list or item size has changed */
+ if ((p < 0) || (act[p]->fsize != file_act.size) ||
+ (act[p]->magic != file_act.magic))
+ /*
+ * Unknown activity in list or item size has changed or
+ * unknown activity format.
+ */
goto append_error;
if ((act[p]->nr != file_act.nr) || (act[p]->nr2 != file_act.nr2)) {
* Display data file header.
*
* IN:
- * @dfile Name of system activity data file
- * @file_magic System activity file magic header
- * @file_hdr System activity file standard header
+ * @dfile Name of system activity data file.
+ * @file_magic System activity file magic header.
+ * @file_hdr System activity file standard header.
***************************************************************************
*/
void display_file_header(char *dfile, struct file_magic *file_magic,
{
int i, p;
static __nr_t cpu_nr = -1;
-
+
if (cpu_nr < 0) {
cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
}
}
printf("%02d: %s\t(x%d)", act[p]->id, act[p]->name, act[p]->nr);
if (act[p]->f_count2 || (act[p]->nr2 > 1)) {
- printf(" (x%d)", act[p]->nr2);
+ printf("\t(x%d)", act[p]->nr2);
+ }
+ if (act[p]->magic == ACTIVITY_MAGIC_UNKNOWN) {
+ printf(_("\t[Unknown activity format]"));
}
printf("\n");
}
if ((p < 0) || (act[p]->fsize != file_act.size)
|| !file_act.nr
- || !file_act.nr2) {
+ || !file_act.nr2
+ || (act[p]->magic != file_act.magic)) {
+ /* Remember that we are reading data from sadc and not from a file... */
fprintf(stderr, _("Inconsistent input data\n"));
exit(3);
}
exit(2);
}
- /* Read and write stats located between two possible Linux restarts */
+ /*
+ * Read and write stats located between two possible Linux restarts.
+ * Activities that should be displayed are saved in id_seq[] array.
+ */
for (i = 0; i < NR_ACT; i++) {
if (!id_seq[i])