perfmonger 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.dir-locals.el +2 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/COPYING +674 -0
- data/Gemfile +5 -0
- data/HOWTO.md +15 -0
- data/NEWS +115 -0
- data/README.md +61 -0
- data/Rakefile +8 -0
- data/bin/perfmonger +6 -0
- data/data/NOTICE +8 -0
- data/data/Twitter_Bootstrap_LICENSE.txt +176 -0
- data/data/assets/css/bootstrap-responsive.css +1109 -0
- data/data/assets/css/bootstrap.css +6167 -0
- data/data/assets/css/perfmonger.css +17 -0
- data/data/assets/dashboard.erb +319 -0
- data/data/assets/img/glyphicons-halflings-white.png +0 -0
- data/data/assets/img/glyphicons-halflings.png +0 -0
- data/data/assets/js/bootstrap.js +2280 -0
- data/data/assets/js/bootstrap.min.js +6 -0
- data/data/assets/js/canvasjs.js +9042 -0
- data/data/assets/js/canvasjs.min.js +271 -0
- data/data/sysstat.ioconf +268 -0
- data/ext/perfmonger/extconf.rb +19 -0
- data/ext/perfmonger/perfmonger.h +58 -0
- data/ext/perfmonger/perfmonger_record.c +754 -0
- data/ext/perfmonger/sysstat/common.c +627 -0
- data/ext/perfmonger/sysstat/common.h +207 -0
- data/ext/perfmonger/sysstat/ioconf.c +515 -0
- data/ext/perfmonger/sysstat/ioconf.h +84 -0
- data/ext/perfmonger/sysstat/iostat.c +1100 -0
- data/ext/perfmonger/sysstat/iostat.h +121 -0
- data/ext/perfmonger/sysstat/libsysstat.h +19 -0
- data/ext/perfmonger/sysstat/mpstat.c +953 -0
- data/ext/perfmonger/sysstat/mpstat.h +79 -0
- data/ext/perfmonger/sysstat/rd_stats.c +2388 -0
- data/ext/perfmonger/sysstat/rd_stats.h +651 -0
- data/ext/perfmonger/sysstat/sysconfig.h +13 -0
- data/lib/perfmonger/cli.rb +115 -0
- data/lib/perfmonger/command/base_command.rb +39 -0
- data/lib/perfmonger/command/fingerprint.rb +453 -0
- data/lib/perfmonger/command/plot.rb +429 -0
- data/lib/perfmonger/command/record.rb +32 -0
- data/lib/perfmonger/command/record_option.rb +149 -0
- data/lib/perfmonger/command/server.rb +294 -0
- data/lib/perfmonger/command/stat.rb +60 -0
- data/lib/perfmonger/command/stat_option.rb +29 -0
- data/lib/perfmonger/command/summary.rb +402 -0
- data/lib/perfmonger/config.rb +6 -0
- data/lib/perfmonger/version.rb +5 -0
- data/lib/perfmonger.rb +12 -0
- data/misc/release-howto.txt +17 -0
- data/misc/sample-cpu.png +0 -0
- data/misc/sample-read-iops.png +0 -0
- data/perfmonger.gemspec +44 -0
- data/test/run-test.sh +39 -0
- data/test/spec/bin_spec.rb +37 -0
- data/test/spec/data/2devices.expected +42 -0
- data/test/spec/data/2devices.output +42 -0
- data/test/spec/spec_helper.rb +20 -0
- data/test/spec/summary_spec.rb +193 -0
- data/test/test-perfmonger.c +145 -0
- data/test/test.h +9 -0
- metadata +154 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
/*
|
2
|
+
* (C) 2011 Modified by Yuto HAYAMIZU (haya <at> tkl.iis.u-tokyo.ac.jp)
|
3
|
+
*/
|
4
|
+
|
5
|
+
/*
|
6
|
+
* sysstat: System performance tools for Linux
|
7
|
+
* (C) 1999-2010 by Sebastien Godard (sysstat <at> orange.fr)
|
8
|
+
*/
|
9
|
+
|
10
|
+
#ifndef _COMMON_H
|
11
|
+
#define _COMMON_H
|
12
|
+
|
13
|
+
/* Maximum length of sensors device name */
|
14
|
+
#define MAX_SENSORS_DEV_LEN 20
|
15
|
+
|
16
|
+
#include <time.h>
|
17
|
+
#include <sched.h> /* For __CPU_SETSIZE */
|
18
|
+
#include "rd_stats.h"
|
19
|
+
|
20
|
+
|
21
|
+
/*
|
22
|
+
***************************************************************************
|
23
|
+
* Various keywords and constants
|
24
|
+
***************************************************************************
|
25
|
+
*/
|
26
|
+
|
27
|
+
#ifndef FALSE
|
28
|
+
# define FALSE 0
|
29
|
+
#endif
|
30
|
+
|
31
|
+
#ifndef TRUE
|
32
|
+
# define TRUE 1
|
33
|
+
#endif
|
34
|
+
|
35
|
+
#define DISP_HDR 1
|
36
|
+
|
37
|
+
/* Maximum number of CPUs */
|
38
|
+
#ifdef __CPU_SETSIZE
|
39
|
+
#define NR_CPUS __CPU_SETSIZE
|
40
|
+
#else
|
41
|
+
#define NR_CPUS 1024
|
42
|
+
#endif
|
43
|
+
|
44
|
+
/* Maximum number of interrupts */
|
45
|
+
#define NR_IRQS 256
|
46
|
+
|
47
|
+
/* Size of /proc/interrupts line, CPU data excluded */
|
48
|
+
#define INTERRUPTS_LINE 128
|
49
|
+
|
50
|
+
/* Keywords */
|
51
|
+
#define K_ISO "ISO"
|
52
|
+
#define K_ALL "ALL"
|
53
|
+
#define K_UTC "UTC"
|
54
|
+
|
55
|
+
/* Files */
|
56
|
+
#define STAT "/proc/stat"
|
57
|
+
#define UPTIME "/proc/uptime"
|
58
|
+
#define PPARTITIONS "/proc/partitions"
|
59
|
+
#define DISKSTATS "/proc/diskstats"
|
60
|
+
#define INTERRUPTS "/proc/interrupts"
|
61
|
+
#define MEMINFO "/proc/meminfo"
|
62
|
+
#define SYSFS_BLOCK "/sys/block"
|
63
|
+
#define SYSFS_DEVCPU "/sys/devices/system/cpu"
|
64
|
+
#define SYSFS_TIME_IN_STATE "cpufreq/stats/time_in_state"
|
65
|
+
#define S_STAT "stat"
|
66
|
+
#define DEVMAP_DIR "/dev/mapper"
|
67
|
+
#define DEVICES "/proc/devices"
|
68
|
+
|
69
|
+
#define MAX_FILE_LEN 256
|
70
|
+
#define MAX_PF_NAME 1024
|
71
|
+
#define DEFAULT_DEVMAP_MAJOR 253
|
72
|
+
#define MAX_NAME_LEN 72
|
73
|
+
|
74
|
+
#define NR_DISKS 4
|
75
|
+
|
76
|
+
/* Environment variables */
|
77
|
+
#define ENV_TIME_FMT "S_TIME_FORMAT"
|
78
|
+
#define ENV_TIME_DEFTM "S_TIME_DEF_TIME"
|
79
|
+
|
80
|
+
#define DIGITS "0123456789"
|
81
|
+
|
82
|
+
|
83
|
+
/*
|
84
|
+
***************************************************************************
|
85
|
+
* Macro functions definitions.
|
86
|
+
***************************************************************************
|
87
|
+
*/
|
88
|
+
|
89
|
+
/* Allocate and init structure */
|
90
|
+
#define SREALLOC(S, TYPE, SIZE) do { \
|
91
|
+
TYPE *_p_; \
|
92
|
+
_p_ = S; \
|
93
|
+
if (SIZE) { \
|
94
|
+
if ((S = (TYPE *) realloc(S, (SIZE))) == NULL) { \
|
95
|
+
perror("realloc"); \
|
96
|
+
exit(4); \
|
97
|
+
} \
|
98
|
+
/* If the ptr was null, then it's a malloc() */ \
|
99
|
+
if (!_p_) \
|
100
|
+
memset(S, 0, (SIZE)); \
|
101
|
+
} \
|
102
|
+
} while (0)
|
103
|
+
|
104
|
+
/*
|
105
|
+
* Macros used to display statistics values.
|
106
|
+
*
|
107
|
+
* NB: Define SP_VALUE() to normalize to %;
|
108
|
+
* HZ is 1024 on IA64 and % should be normalized to 100.
|
109
|
+
*/
|
110
|
+
#define S_VALUE(m,n,p) (((double) ((n) - (m))) / (p) * HZ)
|
111
|
+
#define SP_VALUE(m,n,p) (((double) ((n) - (m))) / (p) * 100)
|
112
|
+
|
113
|
+
/*
|
114
|
+
* Under very special circumstances, STDOUT may become unavailable.
|
115
|
+
* This is what we try to guess here
|
116
|
+
*/
|
117
|
+
#define TEST_STDOUT(_fd_) do { \
|
118
|
+
if (write(_fd_, "", 0) == -1) { \
|
119
|
+
perror("stdout"); \
|
120
|
+
exit(6); \
|
121
|
+
} \
|
122
|
+
} while (0)
|
123
|
+
|
124
|
+
|
125
|
+
#define MINIMUM(a,b) ((a) < (b) ? (a) : (b))
|
126
|
+
|
127
|
+
#define PANIC(m) sysstat_panic(__FUNCTION__, m)
|
128
|
+
|
129
|
+
|
130
|
+
/* Number of ticks per second */
|
131
|
+
#define HZ hz
|
132
|
+
extern unsigned int hz;
|
133
|
+
|
134
|
+
/* Number of bit shifts to convert pages to kB */
|
135
|
+
extern unsigned int kb_shift;
|
136
|
+
|
137
|
+
/*
|
138
|
+
* kB <-> number of pages.
|
139
|
+
* Page size depends on machine architecture (4 kB, 8 kB, 16 kB, 64 kB...)
|
140
|
+
*/
|
141
|
+
#define KB_TO_PG(k) ((k) >> kb_shift)
|
142
|
+
#define PG_TO_KB(k) ((k) << kb_shift)
|
143
|
+
|
144
|
+
/*
|
145
|
+
***************************************************************************
|
146
|
+
* Structures definitions
|
147
|
+
***************************************************************************
|
148
|
+
*/
|
149
|
+
|
150
|
+
/* Structure used for extended disk statistics */
|
151
|
+
struct ext_disk_stats {
|
152
|
+
double util;
|
153
|
+
double await;
|
154
|
+
double svctm;
|
155
|
+
double arqsz;
|
156
|
+
};
|
157
|
+
|
158
|
+
|
159
|
+
/*
|
160
|
+
***************************************************************************
|
161
|
+
* Functions prototypes
|
162
|
+
***************************************************************************
|
163
|
+
*/
|
164
|
+
|
165
|
+
extern void
|
166
|
+
compute_ext_disk_stats(struct stats_disk *, struct stats_disk *,
|
167
|
+
unsigned long long, struct ext_disk_stats *);
|
168
|
+
extern int
|
169
|
+
count_bits(void *, int);
|
170
|
+
extern int
|
171
|
+
count_csvalues(int, char **);
|
172
|
+
extern char *
|
173
|
+
device_name(char *);
|
174
|
+
extern void
|
175
|
+
get_HZ(void);
|
176
|
+
extern unsigned int
|
177
|
+
get_devmap_major(void);
|
178
|
+
extern unsigned long long
|
179
|
+
get_interval(unsigned long long, unsigned long long);
|
180
|
+
extern void
|
181
|
+
get_kb_shift(void);
|
182
|
+
extern time_t
|
183
|
+
get_localtime(struct tm *);
|
184
|
+
extern time_t
|
185
|
+
get_time(struct tm *);
|
186
|
+
unsigned long long
|
187
|
+
get_per_cpu_interval(struct stats_cpu *, struct stats_cpu *);
|
188
|
+
extern int
|
189
|
+
get_sysfs_dev_nr(int);
|
190
|
+
extern int
|
191
|
+
get_win_height(void);
|
192
|
+
extern void
|
193
|
+
init_nls(void);
|
194
|
+
extern int
|
195
|
+
is_device(char *);
|
196
|
+
extern double
|
197
|
+
ll_s_value(unsigned long long, unsigned long long, unsigned long long);
|
198
|
+
extern double
|
199
|
+
ll_sp_value(unsigned long long, unsigned long long, unsigned long long);
|
200
|
+
extern int
|
201
|
+
print_gal_header(struct tm *, char *, char *, char *, char *, int);
|
202
|
+
extern void
|
203
|
+
print_version(void);
|
204
|
+
extern void
|
205
|
+
sysstat_panic(const char *, int);
|
206
|
+
|
207
|
+
#endif /* _COMMON_H */
|
@@ -0,0 +1,515 @@
|
|
1
|
+
/*
|
2
|
+
* ioconf: ioconf configuration file handling code
|
3
|
+
* Original code (C) 2004 by Red Hat (Charlie Bennett <ccb@redhat.com>)
|
4
|
+
*
|
5
|
+
* Modified and maintained by Sebastien GODARD (sysstat <at> orange.fr)
|
6
|
+
*
|
7
|
+
***************************************************************************
|
8
|
+
* This program is free software; you can redistribute it and/or modify it *
|
9
|
+
* under the terms of the GNU General Public License as published by the *
|
10
|
+
* Free Software Foundation; either version 2 of the License, or (at your *
|
11
|
+
* option) any later version. *
|
12
|
+
* *
|
13
|
+
* This program is distributed in the hope that it will be useful, but *
|
14
|
+
* WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
|
15
|
+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
|
16
|
+
* for more details. *
|
17
|
+
* *
|
18
|
+
* You should have received a copy of the GNU General Public License along *
|
19
|
+
* with this program; if not, write to the Free Software Foundation, Inc., *
|
20
|
+
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
21
|
+
***************************************************************************
|
22
|
+
*/
|
23
|
+
|
24
|
+
#include <stdio.h>
|
25
|
+
#include <stdlib.h>
|
26
|
+
#include <string.h>
|
27
|
+
#include <errno.h>
|
28
|
+
#include <dirent.h>
|
29
|
+
#include <sys/stat.h>
|
30
|
+
|
31
|
+
#include "ioconf.h"
|
32
|
+
#include "common.h"
|
33
|
+
|
34
|
+
#ifdef USE_NLS
|
35
|
+
#include <locale.h>
|
36
|
+
#include <libintl.h>
|
37
|
+
#define _(string) gettext(string)
|
38
|
+
#else
|
39
|
+
#define _(string) (string)
|
40
|
+
#endif
|
41
|
+
|
42
|
+
static unsigned int ioc_parsed = 0;
|
43
|
+
static struct ioc_entry *ioconf[MAX_BLKDEV + 1];
|
44
|
+
static unsigned int ioc_refnr[MAX_BLKDEV + 1];
|
45
|
+
|
46
|
+
/*
|
47
|
+
***************************************************************************
|
48
|
+
* Free ioc_entry structures
|
49
|
+
***************************************************************************
|
50
|
+
*/
|
51
|
+
static void ioc_free(void)
|
52
|
+
{
|
53
|
+
unsigned int i;
|
54
|
+
struct ioc_entry **p;
|
55
|
+
|
56
|
+
/* Take out all of the references first */
|
57
|
+
for (i = 0, p = ioconf; i < MAX_BLKDEV; ++i, ++p) {
|
58
|
+
if ((*p == NULL) || ((*p)->live))
|
59
|
+
continue;
|
60
|
+
|
61
|
+
if ((*p)->desc != (*p)->blkp->desc) {
|
62
|
+
/* Not a shared description */
|
63
|
+
free((*p)->desc);
|
64
|
+
}
|
65
|
+
free(*p);
|
66
|
+
*p = NULL;
|
67
|
+
}
|
68
|
+
|
69
|
+
/* Now the live ones */
|
70
|
+
for (i = 0, p = ioconf; i < MAX_BLKDEV; ++i, ++p) {
|
71
|
+
if (*p == NULL)
|
72
|
+
continue;
|
73
|
+
free((*p)->blkp);
|
74
|
+
free(*p);
|
75
|
+
*p = NULL;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
/*
|
80
|
+
***************************************************************************
|
81
|
+
* ioc_conv - Turn a number into a string in radix <radix> using symbol
|
82
|
+
* set (and ordering) syms. Use nozero to generate strings
|
83
|
+
* in which the number system uses a single sym for the
|
84
|
+
* radix value (not 2, like decimal) and adds a column only
|
85
|
+
* at radix+1. If decimal were like this:
|
86
|
+
*
|
87
|
+
* (no zero) 1 2 3 4 5 6 7 8 9 0 11 12 13 14 15 16 17 18 19 10 ...
|
88
|
+
***************************************************************************
|
89
|
+
*/
|
90
|
+
static char *ioc_conv(int radix, int nozero, const char *syms,
|
91
|
+
unsigned int val)
|
92
|
+
{
|
93
|
+
static char out[17];
|
94
|
+
char *p;
|
95
|
+
int j;
|
96
|
+
|
97
|
+
*(p = out + 16) = '\0';
|
98
|
+
|
99
|
+
val += nozero;
|
100
|
+
|
101
|
+
if (val == 0) {
|
102
|
+
if (!nozero) {
|
103
|
+
*--p = '0';
|
104
|
+
}
|
105
|
+
return (p); /* Empty string if nozero radix gets val == 0 */
|
106
|
+
}
|
107
|
+
|
108
|
+
while (val > 0) {
|
109
|
+
*--p = syms[j = val % radix];
|
110
|
+
val /= radix;
|
111
|
+
if (nozero && (j == 0)) {
|
112
|
+
/* Comp for 10 in nozero bases */
|
113
|
+
--val;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
return (p);
|
117
|
+
}
|
118
|
+
|
119
|
+
char *ioc_ito10(unsigned int n)
|
120
|
+
{
|
121
|
+
return (ioc_conv(10, 0, "0123456789", n));
|
122
|
+
}
|
123
|
+
|
124
|
+
char *ioc_ito26(unsigned int n)
|
125
|
+
{
|
126
|
+
return (ioc_conv(26, 1, "zabcdefghijklmnopqrstuvwxy", n));
|
127
|
+
}
|
128
|
+
|
129
|
+
/*
|
130
|
+
***************************************************************************
|
131
|
+
* ioc_init() - internalize the ioconf file
|
132
|
+
*
|
133
|
+
* given: void
|
134
|
+
* does: parses IOCONF into ioconf, an array of ioc_entry *
|
135
|
+
* Only entries having lines in IOCONF will have valid pointers
|
136
|
+
* return: 1 on success
|
137
|
+
* 0 on failure
|
138
|
+
***************************************************************************
|
139
|
+
*/
|
140
|
+
int ioc_init(void)
|
141
|
+
{
|
142
|
+
FILE *fp;
|
143
|
+
unsigned int i, major, indirect, count = 0;
|
144
|
+
char buf[IOC_LINESIZ + 1];
|
145
|
+
char cfmt[IOC_FMTLEN + 1];
|
146
|
+
char dfmt[IOC_FMTLEN + 1];
|
147
|
+
char pfmt[IOC_FMTLEN + 1];
|
148
|
+
char desc[IOC_DESCLEN + 1];
|
149
|
+
struct ioc_entry *iocp = NULL;
|
150
|
+
struct blk_config *blkp = NULL;
|
151
|
+
char ioconf_name[64];
|
152
|
+
|
153
|
+
if ((fp = fopen(IOCONF, "r")) == NULL) {
|
154
|
+
if ((fp = fopen(LOCAL_IOCONF, "r")) == NULL)
|
155
|
+
return 0;
|
156
|
+
strncpy(ioconf_name, LOCAL_IOCONF, 64);
|
157
|
+
}
|
158
|
+
else {
|
159
|
+
strncpy(ioconf_name, IOCONF, 64);
|
160
|
+
}
|
161
|
+
ioconf_name[63] = '\0';
|
162
|
+
|
163
|
+
/* Init ioc_refnr array */
|
164
|
+
memset(ioc_refnr, 0, sizeof(ioc_refnr));
|
165
|
+
|
166
|
+
while (fgets(buf, IOC_LINESIZ, fp)) {
|
167
|
+
|
168
|
+
if ((*buf == '#') || (*buf == '\n'))
|
169
|
+
continue;
|
170
|
+
|
171
|
+
/*
|
172
|
+
* Preallocate some (probably) needed data structures
|
173
|
+
*/
|
174
|
+
IOC_ALLOC(blkp, struct blk_config, BLK_CONFIG_SIZE);
|
175
|
+
IOC_ALLOC(iocp, struct ioc_entry, IOC_ENTRY_SIZE);
|
176
|
+
memset(blkp, 0, BLK_CONFIG_SIZE);
|
177
|
+
memset(iocp, 0, IOC_ENTRY_SIZE);
|
178
|
+
|
179
|
+
i = sscanf(buf, "%u:%u:%u:%s",
|
180
|
+
&major, &indirect, &iocp->ctrlno, desc);
|
181
|
+
|
182
|
+
if (i != 4) {
|
183
|
+
i = sscanf(buf, "%u:%u:%u",
|
184
|
+
&major, &indirect, &iocp->ctrlno);
|
185
|
+
}
|
186
|
+
|
187
|
+
if ((i == 3) || (i == 4)) {
|
188
|
+
/* indirect record */
|
189
|
+
if (indirect == 0) {
|
190
|
+
/* conventional usage for unsupported device */
|
191
|
+
continue;
|
192
|
+
}
|
193
|
+
if (indirect >= MAX_BLKDEV) {
|
194
|
+
fprintf(stderr, "%s: Indirect major #%u out of range\n",
|
195
|
+
ioconf_name, indirect);
|
196
|
+
continue;
|
197
|
+
}
|
198
|
+
if (ioconf[indirect] == NULL) {
|
199
|
+
fprintf(stderr,
|
200
|
+
"%s: Indirect record '%u:%u:%u:...'"
|
201
|
+
" references not yet seen major %u\n",
|
202
|
+
ioconf_name, major, indirect, iocp->ctrlno, major);
|
203
|
+
continue;
|
204
|
+
}
|
205
|
+
/*
|
206
|
+
* Cool. Point this device at its referent.
|
207
|
+
* Skip last: (last field my be empty...)
|
208
|
+
* if it was empty and : was in the sscanf spec
|
209
|
+
* we'd only see 3 fields...
|
210
|
+
*/
|
211
|
+
if (i == 3) {
|
212
|
+
/* reference the mothership */
|
213
|
+
iocp->desc = ioconf[indirect]->blkp->desc;
|
214
|
+
}
|
215
|
+
else {
|
216
|
+
IOC_ALLOC(iocp->desc, char, IOC_DESCLEN + 1);
|
217
|
+
strncpy(iocp->desc, desc, IOC_DESCLEN);
|
218
|
+
}
|
219
|
+
ioc_refnr[indirect]++;
|
220
|
+
ioconf[major] = iocp;
|
221
|
+
iocp->basemajor = indirect;
|
222
|
+
iocp->blkp = ioconf[indirect]->blkp;
|
223
|
+
iocp->live = 0;
|
224
|
+
iocp = NULL;
|
225
|
+
continue;
|
226
|
+
/* all done with indirect record */
|
227
|
+
}
|
228
|
+
|
229
|
+
/* maybe it's a full record? */
|
230
|
+
|
231
|
+
i = sscanf(buf, "%u:%[^:]:%[^:]:%d:%[^:]:%u:%[^:]:%u:%s",
|
232
|
+
&major, blkp->name,
|
233
|
+
cfmt, &iocp->ctrlno,
|
234
|
+
dfmt, &blkp->dcount,
|
235
|
+
pfmt, &blkp->pcount,
|
236
|
+
desc);
|
237
|
+
|
238
|
+
if (i != 9) {
|
239
|
+
fprintf(stderr, "%s: Malformed %d field record: %s\n",
|
240
|
+
ioconf_name, i, buf);
|
241
|
+
continue;
|
242
|
+
}
|
243
|
+
|
244
|
+
/* this is a full-fledged direct record */
|
245
|
+
|
246
|
+
if ((major == 0) || (major >= MAX_BLKDEV)) {
|
247
|
+
fprintf(stderr, "%s: major #%u out of range\n",
|
248
|
+
__FUNCTION__, major);
|
249
|
+
continue;
|
250
|
+
}
|
251
|
+
|
252
|
+
/* is this an exception record? */
|
253
|
+
if (*cfmt == 'x') {
|
254
|
+
struct blk_config *xblkp;
|
255
|
+
|
256
|
+
/*
|
257
|
+
* device has an aliased minor
|
258
|
+
* for now we only support on exception per major
|
259
|
+
* (catering to initrd: (1,250))
|
260
|
+
*/
|
261
|
+
if (ioconf[major] == NULL) {
|
262
|
+
fprintf(stderr, "%s: type 'x' record for"
|
263
|
+
" major #%u must follow the base record - ignored\n",
|
264
|
+
ioconf_name, major);
|
265
|
+
continue;
|
266
|
+
}
|
267
|
+
xblkp = ioconf[major]->blkp;
|
268
|
+
|
269
|
+
if (xblkp->ext) {
|
270
|
+
/*
|
271
|
+
* Enforce one minor exception per major policy
|
272
|
+
* note: this applies to each major number and
|
273
|
+
* all of it's indirect (short form) majors
|
274
|
+
*/
|
275
|
+
fprintf(stderr, "%s: duplicate 'x' record for"
|
276
|
+
" major #%u - ignored\ninput line: %s\n",
|
277
|
+
ioconf_name, major, buf);
|
278
|
+
continue;
|
279
|
+
}
|
280
|
+
/*
|
281
|
+
* Decorate the base major struct with the
|
282
|
+
* exception info
|
283
|
+
*/
|
284
|
+
xblkp->ext_minor = iocp->ctrlno;
|
285
|
+
strcpy(xblkp->ext_name, blkp->name);
|
286
|
+
xblkp->ext = 1;
|
287
|
+
continue;
|
288
|
+
}
|
289
|
+
|
290
|
+
/*
|
291
|
+
* Preformat the sprintf format strings for generating
|
292
|
+
* c-d-p info in ioc_name()
|
293
|
+
*/
|
294
|
+
|
295
|
+
/* basename of device + provided string + controller # */
|
296
|
+
if (*cfmt == '*') {
|
297
|
+
strcpy(blkp->cfmt, blkp->name);
|
298
|
+
}
|
299
|
+
else {
|
300
|
+
sprintf(blkp->cfmt, "%s%s%%d", blkp->name, cfmt);
|
301
|
+
++(blkp->ctrl_explicit);
|
302
|
+
}
|
303
|
+
|
304
|
+
/* Disk */
|
305
|
+
*blkp->dfmt = '\0';
|
306
|
+
switch (*dfmt) {
|
307
|
+
case 'a':
|
308
|
+
blkp->cconv = ioc_ito26;
|
309
|
+
strcpy(blkp->dfmt, "%s");
|
310
|
+
break;
|
311
|
+
|
312
|
+
case '%':
|
313
|
+
strcpy(blkp->dfmt, dfmt + 1);
|
314
|
+
case 'd':
|
315
|
+
blkp->cconv = ioc_ito10;
|
316
|
+
strcat(blkp->dfmt, "%s");
|
317
|
+
break;
|
318
|
+
}
|
319
|
+
|
320
|
+
/* Partition */
|
321
|
+
sprintf(blkp->pfmt, "%s%%d", (*pfmt == '*') ? "" : pfmt);
|
322
|
+
|
323
|
+
/*
|
324
|
+
* We're good to go.
|
325
|
+
* Stuff the ioc_entry and ref it.
|
326
|
+
*/
|
327
|
+
iocp->live = 1;
|
328
|
+
iocp->blkp = blkp;
|
329
|
+
iocp->desc = NULL;
|
330
|
+
iocp->basemajor = major;
|
331
|
+
ioconf[major] = iocp;
|
332
|
+
strncpy(blkp->desc, desc, IOC_DESCLEN);
|
333
|
+
blkp = NULL; iocp = NULL;
|
334
|
+
++count;
|
335
|
+
}
|
336
|
+
fclose(fp);
|
337
|
+
|
338
|
+
/*
|
339
|
+
* These will become leaks if we ever 'continue'
|
340
|
+
* after IOC_ALLOC( blkp->desc ... ).
|
341
|
+
* Right Now, we don't.
|
342
|
+
*/
|
343
|
+
if (blkp != NULL)
|
344
|
+
free(blkp);
|
345
|
+
if (iocp != NULL)
|
346
|
+
free(iocp);
|
347
|
+
|
348
|
+
/* Indicate that ioconf file has been parsed */
|
349
|
+
ioc_parsed = 1;
|
350
|
+
|
351
|
+
return (count);
|
352
|
+
}
|
353
|
+
|
354
|
+
/*
|
355
|
+
***************************************************************************
|
356
|
+
* ioc_name() - Generate a name from a maj,min pair
|
357
|
+
*
|
358
|
+
* IN:
|
359
|
+
* @major Device major number.
|
360
|
+
* @minor Device minor number.
|
361
|
+
*
|
362
|
+
* RETURNS:
|
363
|
+
* Returns NULL if major or minor are out of range
|
364
|
+
* otherwise returns a pointer to a static string containing
|
365
|
+
* the generated name.
|
366
|
+
***************************************************************************
|
367
|
+
*/
|
368
|
+
|
369
|
+
char *ioc_name(unsigned int major, unsigned int minor)
|
370
|
+
{
|
371
|
+
static char name[IOC_DEVLEN + 1];
|
372
|
+
struct ioc_entry *p;
|
373
|
+
int base, offset;
|
374
|
+
|
375
|
+
if ((MAX_BLKDEV <= major) || (IOC_MAXMINOR <= minor)) {
|
376
|
+
return (NULL);
|
377
|
+
}
|
378
|
+
|
379
|
+
if (!ioc_parsed && !ioc_init())
|
380
|
+
return (NULL);
|
381
|
+
|
382
|
+
p = ioconf[major];
|
383
|
+
|
384
|
+
/* Invalid major or minor numbers? */
|
385
|
+
if ((p == NULL) || ((minor & 0xff) >= (p->blkp->dcount * p->blkp->pcount))) {
|
386
|
+
/*
|
387
|
+
* That minor test is only there for IDE-style devices
|
388
|
+
* that have no minors over 128.
|
389
|
+
*/
|
390
|
+
strcpy(name, K_NODEV);
|
391
|
+
return (name);
|
392
|
+
}
|
393
|
+
|
394
|
+
/* Is this an extension record? */
|
395
|
+
if (p->blkp->ext && (p->blkp->ext_minor == minor)) {
|
396
|
+
strcpy(name, p->blkp->ext_name);
|
397
|
+
return (name);
|
398
|
+
}
|
399
|
+
|
400
|
+
/* OK. we're doing an actual device name... */
|
401
|
+
|
402
|
+
/*
|
403
|
+
* Assemble base + optional controller info
|
404
|
+
* this is of course too clever by half
|
405
|
+
* the parser has already cooked cfmt, dfmt to make this easy
|
406
|
+
* (we parse once but may generate lots of names)
|
407
|
+
*/
|
408
|
+
base = p->ctrlno * p->blkp->dcount;
|
409
|
+
if (minor >= 256) {
|
410
|
+
base += p->blkp->dcount * (ioc_refnr[p->basemajor] + 1) * (minor >> 8);
|
411
|
+
}
|
412
|
+
|
413
|
+
offset = (minor & 0xff) / p->blkp->pcount;
|
414
|
+
if (!p->blkp->ctrl_explicit) {
|
415
|
+
offset += base;
|
416
|
+
}
|
417
|
+
|
418
|
+
/*
|
419
|
+
* These sprintfs can't be coalesced because the first might
|
420
|
+
* ignore its first arg
|
421
|
+
*/
|
422
|
+
sprintf(name, p->blkp->cfmt, p->ctrlno);
|
423
|
+
sprintf(name + strlen(name), p->blkp->dfmt, p->blkp->cconv(offset));
|
424
|
+
|
425
|
+
if (!IS_WHOLE(major, minor)) {
|
426
|
+
/*
|
427
|
+
* Tack on partition info, format string cooked (curried?) by
|
428
|
+
* the parser
|
429
|
+
*/
|
430
|
+
sprintf(name + strlen(name), p->blkp->pfmt, minor % p->blkp->pcount);
|
431
|
+
}
|
432
|
+
return (name);
|
433
|
+
}
|
434
|
+
|
435
|
+
/*
|
436
|
+
***************************************************************************
|
437
|
+
* Check whether a device is a whole disk device or not.
|
438
|
+
*
|
439
|
+
* IN:
|
440
|
+
* @major Device major number.
|
441
|
+
* @minor Device minor number.
|
442
|
+
*
|
443
|
+
* RETURNS:
|
444
|
+
* Predicate: Returns 1 if dev (major,minor) is a whole disk device.
|
445
|
+
* Returns 0 otherwise.
|
446
|
+
***************************************************************************
|
447
|
+
*/
|
448
|
+
int ioc_iswhole(unsigned int major, unsigned int minor)
|
449
|
+
{
|
450
|
+
if (!ioc_parsed && !ioc_init())
|
451
|
+
return 0;
|
452
|
+
|
453
|
+
if (major >= MAX_BLKDEV)
|
454
|
+
/*
|
455
|
+
* Later: Handle Linux long major numbers here.
|
456
|
+
* Now: This is an error.
|
457
|
+
*/
|
458
|
+
return 0;
|
459
|
+
|
460
|
+
if (ioconf[major] == NULL)
|
461
|
+
/* Device not registered */
|
462
|
+
return 0 ;
|
463
|
+
|
464
|
+
return (IS_WHOLE(major, minor));
|
465
|
+
}
|
466
|
+
|
467
|
+
/*
|
468
|
+
***************************************************************************
|
469
|
+
* Transform device mapper name: Get the user assigned name of the logical
|
470
|
+
* device instead of the internal device mapper numbering.
|
471
|
+
*
|
472
|
+
* IN:
|
473
|
+
* @major Device major number.
|
474
|
+
* @minor Device minor number.
|
475
|
+
*
|
476
|
+
* RETURNS:
|
477
|
+
* Assigned name of the logical device.
|
478
|
+
***************************************************************************
|
479
|
+
*/
|
480
|
+
char *transform_devmapname(unsigned int major, unsigned int minor)
|
481
|
+
{
|
482
|
+
DIR *dm_dir;
|
483
|
+
struct dirent *dp;
|
484
|
+
char filen[MAX_FILE_LEN];
|
485
|
+
char *dm_name = NULL;
|
486
|
+
struct stat aux;
|
487
|
+
unsigned int dm_major, dm_minor;
|
488
|
+
|
489
|
+
if ((dm_dir = opendir(DEVMAP_DIR)) == NULL) {
|
490
|
+
fprintf(stderr, _("Cannot open %s: %s\n"), DEVMAP_DIR, strerror(errno));
|
491
|
+
exit(4);
|
492
|
+
}
|
493
|
+
|
494
|
+
while ((dp = readdir(dm_dir)) != NULL) {
|
495
|
+
/* For each file in DEVMAP_DIR */
|
496
|
+
|
497
|
+
snprintf(filen, MAX_FILE_LEN, "%s/%s", DEVMAP_DIR, dp->d_name);
|
498
|
+
filen[MAX_FILE_LEN - 1] = '\0';
|
499
|
+
|
500
|
+
if (stat(filen, &aux) == 0) {
|
501
|
+
/* Get its minor and major numbers */
|
502
|
+
|
503
|
+
dm_major = ((aux.st_rdev >> 8) & 0xff);
|
504
|
+
dm_minor = (aux.st_rdev & 0xff);
|
505
|
+
|
506
|
+
if ((dm_minor == minor) && (dm_major == major)) {
|
507
|
+
dm_name = dp->d_name;
|
508
|
+
break;
|
509
|
+
}
|
510
|
+
}
|
511
|
+
}
|
512
|
+
closedir(dm_dir);
|
513
|
+
|
514
|
+
return dm_name;
|
515
|
+
}
|