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.
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
+ }