perfmonger 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/.dir-locals.el +2 -0
  3. data/.gitignore +4 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +12 -0
  6. data/COPYING +674 -0
  7. data/Gemfile +5 -0
  8. data/HOWTO.md +15 -0
  9. data/NEWS +115 -0
  10. data/README.md +61 -0
  11. data/Rakefile +8 -0
  12. data/bin/perfmonger +6 -0
  13. data/data/NOTICE +8 -0
  14. data/data/Twitter_Bootstrap_LICENSE.txt +176 -0
  15. data/data/assets/css/bootstrap-responsive.css +1109 -0
  16. data/data/assets/css/bootstrap.css +6167 -0
  17. data/data/assets/css/perfmonger.css +17 -0
  18. data/data/assets/dashboard.erb +319 -0
  19. data/data/assets/img/glyphicons-halflings-white.png +0 -0
  20. data/data/assets/img/glyphicons-halflings.png +0 -0
  21. data/data/assets/js/bootstrap.js +2280 -0
  22. data/data/assets/js/bootstrap.min.js +6 -0
  23. data/data/assets/js/canvasjs.js +9042 -0
  24. data/data/assets/js/canvasjs.min.js +271 -0
  25. data/data/sysstat.ioconf +268 -0
  26. data/ext/perfmonger/extconf.rb +19 -0
  27. data/ext/perfmonger/perfmonger.h +58 -0
  28. data/ext/perfmonger/perfmonger_record.c +754 -0
  29. data/ext/perfmonger/sysstat/common.c +627 -0
  30. data/ext/perfmonger/sysstat/common.h +207 -0
  31. data/ext/perfmonger/sysstat/ioconf.c +515 -0
  32. data/ext/perfmonger/sysstat/ioconf.h +84 -0
  33. data/ext/perfmonger/sysstat/iostat.c +1100 -0
  34. data/ext/perfmonger/sysstat/iostat.h +121 -0
  35. data/ext/perfmonger/sysstat/libsysstat.h +19 -0
  36. data/ext/perfmonger/sysstat/mpstat.c +953 -0
  37. data/ext/perfmonger/sysstat/mpstat.h +79 -0
  38. data/ext/perfmonger/sysstat/rd_stats.c +2388 -0
  39. data/ext/perfmonger/sysstat/rd_stats.h +651 -0
  40. data/ext/perfmonger/sysstat/sysconfig.h +13 -0
  41. data/lib/perfmonger/cli.rb +115 -0
  42. data/lib/perfmonger/command/base_command.rb +39 -0
  43. data/lib/perfmonger/command/fingerprint.rb +453 -0
  44. data/lib/perfmonger/command/plot.rb +429 -0
  45. data/lib/perfmonger/command/record.rb +32 -0
  46. data/lib/perfmonger/command/record_option.rb +149 -0
  47. data/lib/perfmonger/command/server.rb +294 -0
  48. data/lib/perfmonger/command/stat.rb +60 -0
  49. data/lib/perfmonger/command/stat_option.rb +29 -0
  50. data/lib/perfmonger/command/summary.rb +402 -0
  51. data/lib/perfmonger/config.rb +6 -0
  52. data/lib/perfmonger/version.rb +5 -0
  53. data/lib/perfmonger.rb +12 -0
  54. data/misc/release-howto.txt +17 -0
  55. data/misc/sample-cpu.png +0 -0
  56. data/misc/sample-read-iops.png +0 -0
  57. data/perfmonger.gemspec +44 -0
  58. data/test/run-test.sh +39 -0
  59. data/test/spec/bin_spec.rb +37 -0
  60. data/test/spec/data/2devices.expected +42 -0
  61. data/test/spec/data/2devices.output +42 -0
  62. data/test/spec/spec_helper.rb +20 -0
  63. data/test/spec/summary_spec.rb +193 -0
  64. data/test/test-perfmonger.c +145 -0
  65. data/test/test.h +9 -0
  66. 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
+ }