- rewrote man page, help text & README (bnc #178662)
[opensuse:hwinfo.git] / hwinfo.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <getopt.h>
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10
11 #include "hd.h"
12 #include "hd_int.h"
13
14 typedef struct {
15   hd_hw_item_t type;
16   char *dev;
17   char *dev_old;
18   char *serial;
19   char *model;
20   uint64_t size;
21   char *id;
22   char *p_id;
23   unsigned model_ok:1;
24   unsigned serial_ok:1;
25   unsigned size_ok:1;
26   unsigned assigned:1;
27 } map_t;
28
29 static int get_probe_flags(int, char **, hd_data_t *);
30 static void progress2(char *, char *);
31
32 // ##### temporary solution, fix it later!
33 str_list_t *read_file(char *file_name, unsigned start_line, unsigned lines);
34 str_list_t *search_str_list(str_list_t *sl, char *str);
35 str_list_t *add_str_list(str_list_t **sl, char *str);
36 char *new_str(const char *);
37
38 static unsigned deb = 0;
39 static char *log_file = "";
40 static char *list = NULL;
41 static int listplus = 0;
42
43 static int test = 0;
44 static int is_short = 0;
45
46 static char *showconfig = NULL;
47 static char *saveconfig = NULL;
48 static hd_hw_item_t hw_item[100] = { };
49 static int hw_items = 0;
50
51 int braille_install_info(hd_data_t *hd_data);
52 int x11_install_info(hd_data_t *hd_data);
53 int oem_install_info(hd_data_t *hd_data);
54 void dump_packages(hd_data_t *hd_data);
55
56 void do_hw(hd_data_t *hd_data, FILE *f, hd_hw_item_t hw_item);
57 void do_hw_multi(hd_data_t *hd_data, FILE *f, hd_hw_item_t *hw_items);
58 void do_short(hd_data_t *hd_data, hd_t *hd, FILE *f);
59 void do_test(hd_data_t *hd_data);
60 void help(void);
61 void dump_db_raw(hd_data_t *hd_data);
62 void dump_db(hd_data_t *hd_data);
63 void do_chroot(hd_data_t *hd_data, char *dir);
64 void ask_db(hd_data_t *hd_data, char *query);
65 // void get_mapping(hd_data_t *hd_data);
66 int get_mapping2(void);
67 void write_udi(hd_data_t *hd_data, char *udi);
68
69 void do_saveconfig(hd_data_t *hd_data, hd_t *hd, FILE *f);
70
71 int map_cmp(const void *p0, const void *p1);
72 unsigned map_fill(map_t *map, hd_data_t *hd_data, hd_t *hd_manual);
73 void map_dump(map_t *map, unsigned map_len);
74
75 struct {
76   unsigned db_idx;
77   unsigned separate:1;
78   unsigned verbose:1;
79   char *root;
80 } opt;
81
82 struct option options[] = {
83   { "special", 1, NULL, 1 },
84   { "help", 0, NULL, 'h' },
85   { "debug", 1, NULL, 'd' },
86   { "version", 0, NULL, 400 },
87   { "log", 1, NULL, 'l' },
88   { "packages", 0, NULL, 'p' },
89   { "verbose", 0, NULL, 'v' },
90   { "test", 0, NULL, 300 },
91   { "format", 1, NULL, 301 },
92   { "show-config", 1, NULL, 302 },
93   { "save-config", 1, NULL, 303 },
94   { "short", 0, NULL, 304 },
95   { "fast", 0, NULL, 305 },
96   { "dump-db", 1, NULL, 306 },
97   { "dump-db-raw", 1, NULL, 307 },
98   { "separate", 0, NULL, 308 },
99   { "root", 1, NULL, 309 },
100   { "db", 1, NULL, 310 },
101   { "only", 1, NULL, 311 },
102   { "listmd", 0, NULL, 312 },
103   { "map", 0, NULL, 313 },
104   { "kernel-version", 1, NULL, 314 },
105   { "write-udi", 1, NULL, 315 },
106   { "hddb-dir", 1, NULL, 316 },
107   { "nowpa", 0, NULL, 317 },
108   { "map2", 0, NULL, 318 },
109   { "hddb-dir-new", 1, NULL, 319 },
110   { "cdrom", 0, NULL, 1000 + hw_cdrom },
111   { "floppy", 0, NULL, 1000 + hw_floppy },
112   { "disk", 0, NULL, 1000 + hw_disk },
113   { "network", 0, NULL, 1000 + hw_network },
114   { "display", 0, NULL, 1000 + hw_display },
115   { "gfxcard", 0, NULL, 1000 + hw_display },
116   { "framebuffer", 0, NULL, 1000 + hw_framebuffer },
117   { "monitor", 0, NULL, 1000 + hw_monitor },
118   { "camera", 0, NULL, 1000 + hw_camera },
119   { "mouse", 0, NULL, 1000 + hw_mouse },
120   { "joystick", 0, NULL, 1000 + hw_joystick },
121   { "keyboard", 0, NULL, 1000 + hw_keyboard },
122   { "chipcard", 0, NULL, 1000 + hw_chipcard },
123   { "sound", 0, NULL, 1000 + hw_sound },
124   { "isdn", 0, NULL, 1000 + hw_isdn },
125   { "modem", 0, NULL, 1000 + hw_modem },
126   { "storage-ctrl", 0, NULL, 1000 + hw_storage_ctrl },
127   { "storage_ctrl", 0, NULL, 1000 + hw_storage_ctrl },
128   { "netcard", 0, NULL, 1000 + hw_network_ctrl },
129   { "netcards", 0, NULL, 1000 + hw_network_ctrl },      // outdated, just kept for comaptibility
130   { "network-ctrl", 0, NULL, 1000 + hw_network_ctrl },
131   { "network_ctrl", 0, NULL, 1000 + hw_network_ctrl },
132   { "printer", 0, NULL, 1000 + hw_printer },
133   { "tv", 0, NULL, 1000 + hw_tv },
134   { "dvb", 0, NULL, 1000 + hw_dvb },
135   { "scanner", 0, NULL, 1000 + hw_scanner },
136   { "braille", 0, NULL, 1000 + hw_braille },
137   { "sys", 0, NULL, 1000 + hw_sys },
138   { "bios", 0, NULL, 1000 + hw_bios },
139   { "cpu", 0, NULL, 1000 + hw_cpu },
140   { "partition", 0, NULL, 1000 + hw_partition },
141   { "usb-ctrl", 0, NULL, 1000 + hw_usb_ctrl },
142   { "usb_ctrl", 0, NULL, 1000 + hw_usb_ctrl },
143   { "usb", 0, NULL, 1000 + hw_usb },
144   { "pci", 0, NULL, 1000 + hw_pci },
145   { "isapnp", 0, NULL, 1000 + hw_isapnp },
146   { "scsi", 0, NULL, 1000 + hw_scsi },
147   { "ide", 0, NULL, 1000 + hw_ide },
148   { "bridge", 0, NULL, 1000 + hw_bridge },
149   { "hub", 0, NULL, 1000 + hw_hub },
150   { "memory", 0, NULL, 1000 + hw_memory },
151   { "manual", 0, NULL, 1000 + hw_manual },
152   { "pcmcia", 0, NULL, 1000 + hw_pcmcia },
153   { "pcmcia_ctrl", 0, NULL, 1000 + hw_pcmcia_ctrl },
154   { "ieee1394", 0, NULL, 1000 + hw_ieee1394 },
155   { "ieee1394_ctrl", 0, NULL, 1000 + hw_ieee1394_ctrl },
156   { "firewire", 0, NULL, 1000 + hw_ieee1394 },
157   { "firewire_ctrl", 0, NULL, 1000 + hw_ieee1394_ctrl },
158   { "hotplug", 0, NULL, 1000 + hw_hotplug },
159   { "hotplug_ctrl", 0, NULL, 1000 + hw_hotplug_ctrl },
160   { "zip", 0, NULL, 1000 + hw_zip },
161   { "pppoe", 0, NULL, 1000 + hw_pppoe },
162   { "dsl", 0, NULL, 1000 + hw_dsl },
163   { "wlan", 0, NULL, 1000 + hw_wlan },
164   { "redasd", 0, NULL, 1000 + hw_redasd },
165   { "block", 0, NULL, 1000 + hw_block },
166   { "tape", 0, NULL, 1000 + hw_tape },
167   { "vbe", 0, NULL, 1000 + hw_vbe },
168   { "bluetooth", 0, NULL, 1000 + hw_bluetooth },
169   { "fingerprint", 0, NULL, 1000 + hw_fingerprint },
170   { "all", 0, NULL, 2000 },
171   { "reallyall", 0, NULL, 2001 },
172   { "smp", 0, NULL, 2002 },
173   { "arch", 0, NULL, 2003 },
174   { "uml", 0, NULL, 2004 },
175   { "xen", 0, NULL, 2005 },
176   { }
177 };
178
179
180 /*
181  * Just scan the hardware and dump all info.
182  */
183 int main(int argc, char **argv)
184 {
185   hd_data_t *hd_data;
186   hd_t *hd;
187   FILE *f = NULL;
188   int i;
189   unsigned first_probe = 1;
190   
191   hd_data = calloc(1, sizeof *hd_data);
192   hd_data->progress = isatty(1) ? progress2 : NULL;
193   hd_data->debug=~(HD_DEB_DRIVER_INFO | HD_DEB_HDDB);
194
195   for(i = 0; i < argc; i++) {
196     if(strstr(argv[i], "--") == argv[i]) break;
197   }
198
199   if(i != argc) {
200     /* new style interface */
201
202     opterr = 0;
203
204     while((i = getopt_long(argc, argv, "hd:l:pv", options, NULL)) != -1) {
205       switch(i) {
206         case 1:
207           if(!strcmp(optarg, "braille")) {
208             braille_install_info(hd_data);
209           }
210           else if(!strcmp(optarg, "x11")) {
211             x11_install_info(hd_data);
212           }
213           else if(!strcmp(optarg, "oem")) {
214             oem_install_info(hd_data);
215           }
216           else {
217             help();
218             return 1;
219           }
220           break;
221
222         case 'd':
223           hd_data->debug = strtol(optarg, NULL, 0);
224           break;
225
226         case 'l':
227           log_file = optarg;
228           break;
229
230         case 'p':
231           dump_packages(hd_data);
232           break;
233
234         case 'v':
235           opt.verbose = 1;
236           break;
237
238         case 300:
239           do_test(hd_data);
240           break;
241
242         case 301:
243           hd_data->flags.dformat = strtol(optarg, NULL, 0);
244           break;
245
246         case 302:
247           showconfig = optarg;
248           break;
249
250         case 303:
251           saveconfig = optarg;
252           break;
253
254         case 304:
255           is_short = 1;
256           break;
257
258         case 305:
259           hd_data->flags.fast = 1;
260           break;
261
262         case 306:
263           opt.db_idx = strtoul(optarg, NULL, 0);
264           dump_db(hd_data);
265           break;
266
267         case 307:
268           opt.db_idx = strtoul(optarg, NULL, 0);
269           dump_db_raw(hd_data);
270           break;
271
272         case 308:
273           /* basically for debugging */
274           opt.separate = 1;
275           break;
276
277         case 309:
278           opt.root = optarg;
279           break;
280
281         case 310:
282           ask_db(hd_data, optarg);
283           break;
284
285         case 311:
286           if(*optarg) add_str_list(&hd_data->only, optarg);
287           break;
288
289         case 312:
290           hd_data->flags.list_md = 1;
291           break;
292
293         case 313:
294           return get_mapping2();
295           break;
296
297         case 314:
298           if(*optarg) setenv("LIBHD_KERNELVERSION", optarg, 1);
299           break;
300
301         case 315:
302           write_udi(hd_data, optarg);
303           break;
304
305         case 316:
306           if(*optarg) setenv("LIBHD_HDDB_DIR", optarg, 1);
307           break;
308
309         case 317:
310           break;
311
312         case 318:
313           return get_mapping2();
314           break;
315
316         case 319:
317           if(*optarg) setenv("LIBHD_HDDB_DIR_NEW", optarg, 1);
318           break;
319
320         case 400:
321           printf("%s\n", hd_version());
322           break;
323
324         case 1000 ... 1100:
325           if(hw_items < sizeof hw_item / sizeof *hw_item - 1) {
326             hw_item[hw_items++] = i - 1000;
327           }
328           break;
329
330         case 2000 ... 2005:
331           if(hw_items < sizeof hw_item / sizeof *hw_item - 1) {
332             hw_item[hw_items++] = i;
333           }
334           break;
335
336         default:
337           help();
338           return 0;
339       }
340     }
341
342     if(!hw_items) hw_item[hw_items++] = 2000;   /* all */
343
344     if(hw_items >= 0 || showconfig || saveconfig) {
345       if(*log_file) {
346         if(!strcmp(log_file, "-")) {
347           f = fdopen(1, "w");
348         }
349         else {
350           f = fopen(log_file, "w+");
351         }
352       }
353
354       if(opt.root) do_chroot(hd_data, opt.root);
355
356       if(opt.separate || hw_items <= 1) {
357         for(i = 0; i < hw_items; i++) {
358           if(i) fputc('\n', f ? f : stdout);
359           do_hw(hd_data, f, hw_item[i]);
360         }
361       }
362       else {
363         hw_item[hw_items] = 0;
364         do_hw_multi(hd_data, f, hw_item);
365       }
366
367 #ifndef LIBHD_TINY
368       if(showconfig) {
369         hd = hd_read_config(hd_data, showconfig);
370         if(hd_data->debug == -1) {
371           fprintf(f ? f : stdout,
372             "============ start debug info ============\n%s=========== end debug info ============\n",
373             hd_data->log
374           );
375         }
376         if(hd) {
377           hd_dump_entry(hd_data, hd, f ? f : stdout);
378           hd = hd_free_hd_list(hd);
379         }
380         else {
381           fprintf(f ? f : stdout, "No config data: %s\n", showconfig);
382         }
383       }
384 #endif
385
386       if(f) fclose(f);
387     }
388
389     hd_free_hd_data(hd_data);
390     free(hd_data);
391
392     return 0;
393   }
394
395   /* old style interface */
396
397   argc--; argv++;
398
399   if(argc == 1 && !strcmp(*argv, "-h")) {
400     help();
401     return 0;
402   }
403
404   do {
405     if(first_probe)                             /* only for the 1st probing */
406       hd_set_probe_feature(hd_data, pr_default);
407     else {
408       hd_clear_probe_feature(hd_data, pr_all);
409     }
410
411     if((i = get_probe_flags(argc, argv, hd_data)) < 0) return 1;
412     deb = hd_data->debug;
413     argc -= i; argv += i;
414
415     if(opt.root && first_probe) do_chroot(hd_data, opt.root);
416
417     hd_scan(hd_data);
418     if(hd_data->progress) printf("\r%64s\r", "");
419
420     first_probe = 0;
421   } while(argc);
422
423   if(*log_file) {
424     if(!strcmp(log_file, "-")) {
425       f = fdopen(1, "w");
426     }
427     else {
428       f = fopen(log_file, "w+");
429     }
430   }
431
432   if((hd_data->debug & HD_DEB_SHOW_LOG) && hd_data->log) {
433     if(*log_file) {
434       fprintf(f ? f : stdout,
435         "============ start hardware log ============\n"
436       );
437     }
438     fprintf(f ? f : stdout,
439       "============ start debug info ============\n%s=========== end debug info ============\n",
440       hd_data->log
441     );
442   }
443
444   for(hd = hd_data->hd; hd; hd = hd->next) {
445     hd_dump_entry(hd_data, hd, f ? f : stdout);
446   }
447
448   if(*log_file) {
449     fprintf(f ? f : stdout,
450       "============ end hardware log ============\n"
451     );
452   }
453
454   i = -1;
455   if(list) {
456     if(!strcmp(list, "cdrom")) i = hw_cdrom;
457     if(!strcmp(list, "disk")) i = hw_disk;
458     if(!strcmp(list, "floppy")) i = hw_floppy;
459     if(!strcmp(list, "network")) i = hw_network;
460     if(!strcmp(list, "display")) i = hw_display;
461     if(!strcmp(list, "monitor")) i = hw_monitor;
462     if(!strcmp(list, "mouse")) i = hw_mouse;
463     if(!strcmp(list, "keyboard")) i = hw_keyboard;
464     if(!strcmp(list, "sound")) i = hw_sound;
465     if(!strcmp(list, "isdn")) i = hw_isdn;
466     if(!strcmp(list, "dsl")) i = hw_dsl;
467     if(!strcmp(list, "modem")) i = hw_modem;
468     if(!strcmp(list, "storage_ctrl")) i = hw_storage_ctrl;
469     if(!strcmp(list, "network_ctrl")) i = hw_network_ctrl;
470     if(!strcmp(list, "netcards")) i = hw_network_ctrl;
471     if(!strcmp(list, "printer")) i = hw_printer;
472     if(!strcmp(list, "tv")) i = hw_tv;
473     if(!strcmp(list, "scanner")) i = hw_scanner;
474     if(!strcmp(list, "braille")) i = hw_braille;
475     if(!strcmp(list, "sys")) i = hw_sys;
476     if(!strcmp(list, "cpu")) i = hw_cpu;
477
478     if(i >= 0) {
479       hd = hd_list(hd_data, i, listplus, NULL);
480       printf("\n");
481       printf("-- %s list --\n", list);
482       for(; hd; hd = hd->next) hd_dump_entry(hd_data, hd, stdout);
483       printf("-- %s list end --\n", list);
484       hd = hd_free_hd_list(hd);
485     }
486   }
487
488   if(f) fclose(f);
489
490   hd_free_hd_data(hd_data);
491   free(hd_data);
492
493   return 0;
494 }
495
496
497 void do_hw(hd_data_t *hd_data, FILE *f, hd_hw_item_t hw_item)
498 {
499   hd_t *hd, *hd0;
500   int smp = -1, uml = 0, xen = 0, i;
501   char *s, *t;
502   enum boot_arch b_arch;
503   enum cpu_arch c_arch;
504
505   hd0 = NULL;
506
507   switch(hw_item) {
508     case 2002:
509       smp = hd_smp_support(hd_data);
510       break;
511
512     case 2000:
513     case 2001:
514     case 2003:
515       i = -1;
516       switch((int) hw_item) {
517         case 2000: i = pr_default; break;
518         case 2001: i = pr_all; break;
519         case 2003: i = pr_cpu; break;
520       }
521       if(i != -1) {
522         hd_clear_probe_feature(hd_data, pr_all);
523         hd_set_probe_feature(hd_data, i);
524         hd_scan(hd_data);
525         hd0 = hd_data->hd;
526       }
527       break;
528
529     case 2004:
530       uml = hd_is_uml(hd_data);
531       break;
532
533     case 2005:
534       xen = hd_is_xen(hd_data);
535       break;
536
537     default:
538       hd0 = hd_list(hd_data, hw_item, 1, NULL);
539   }
540
541   if(hd_data->progress) {
542     printf("\r%64s\r", "");
543     fflush(stdout);
544   }
545
546   if(f) {
547     if((hd_data->debug & HD_DEB_SHOW_LOG) && hd_data->log) {
548       fprintf(f,
549         "============ start hardware log ============\n"
550       );
551       fprintf(f,
552         "============ start debug info ============\n%s=========== end debug info ============\n",
553         hd_data->log
554       );
555     }
556
557     i = hd_data->debug;
558     hd_data->debug = -1;
559     for(hd = hd_data->hd; hd; hd = hd->next) {
560       hd_dump_entry(hd_data, hd, f);
561     }
562     hd_data->debug = i;
563
564     fprintf(f,
565       "============ end hardware log ============\n"
566     );
567   }
568
569   if(hw_item == 2002) {
570     fprintf(f ? f : stdout,
571       "SMP support: %s",
572       smp < 0 ? "unknown" : smp > 0 ? "yes" : "no"
573     );
574     if(smp > 0) fprintf(f ? f : stdout, " (%u cpus)", smp);
575     fprintf(f ? f : stdout, "\n");
576   }
577   else if(hw_item == 2003) {
578     c_arch = hd_cpu_arch(hd_data);
579     b_arch = hd_boot_arch(hd_data);
580
581     s = t = "Unknown";
582     switch(c_arch) {
583       case arch_unknown:
584         break;
585       case arch_intel:
586         s = "X86 (32)";
587         break;
588       case arch_alpha:
589         s = "Alpha";
590         break;
591       case arch_sparc:
592         s = "Sparc (32)";
593         break;
594       case arch_sparc64:
595         s = "UltraSparc (64)";
596         break;
597       case arch_ppc:
598         s = "PowerPC";
599         break;
600       case arch_ppc64:
601         s = "PowerPC (64)";
602         break;
603       case arch_68k:
604         s = "68k";
605         break;
606       case arch_ia64:
607         s = "IA-64";
608         break;
609       case arch_s390:
610         s = "S390";
611         break;
612       case arch_s390x:
613         s = "S390x";
614         break;
615       case arch_arm:
616         s = "ARM";
617         break;
618       case arch_mips:
619         s = "MIPS";
620         break;
621       case arch_x86_64:
622         s = "X86_64";
623         break;
624     }
625
626     switch(b_arch) {
627       case boot_unknown:
628         break;
629       case boot_lilo:
630         t = "lilo";
631         break;
632       case boot_milo:
633         t = "milo";
634         break;
635       case boot_aboot:
636         t = "aboot";
637         break;
638       case boot_silo:
639         t = "silo";
640         break;
641       case boot_ppc:
642         t = "ppc";
643         break;
644       case boot_elilo:
645         t = "elilo";
646         break;
647       case boot_s390:
648         t = "s390";
649         break;
650       case boot_mips:
651         t = "mips";
652         break;
653       case boot_grub:
654         t = "grub";
655         break;
656     }
657
658     fprintf(f ? f : stdout, "Arch: %s/%s\n", s, t);
659   }
660   else if(hw_item == 2004) {
661     fprintf(f ? f : stdout, "UML: %s\n", uml ? "yes" : "no");
662   }
663   else if(hw_item == 2005) {
664     fprintf(f ? f : stdout, "Xen: %s\n", xen ? "yes" : "no");
665   }
666   else {
667     if(is_short) {
668       /* always to stdout */
669       do_short(hd_data, hd0, stdout);
670       if(f) do_short(hd_data, hd0, f);
671     }
672     else {
673       for(hd = hd0; hd; hd = hd->next) {
674         hd_dump_entry(hd_data, hd, f ? f : stdout);
675       }
676       do_saveconfig(hd_data, hd0, f ? f : stdout);
677     }
678   }
679
680   if(hw_item == hw_display && hd0) {
681     fprintf(f ? f : stdout, "\nPrimary display adapter: #%u\n", hd_display_adapter(hd_data));
682   }
683
684   if(hd0 != hd_data->hd) hd_free_hd_list(hd0);
685 }
686
687
688 void do_hw_multi(hd_data_t *hd_data, FILE *f, hd_hw_item_t *hw_items)
689 {
690   hd_t *hd, *hd0;
691   int i;
692
693   hd0 = hd_list2(hd_data, hw_items, 1);
694
695   if(hd_data->progress) {
696     printf("\r%64s\r", "");
697     fflush(stdout);
698   }
699
700   if(f) {
701     if((hd_data->debug & HD_DEB_SHOW_LOG) && hd_data->log) {
702       fprintf(f,
703         "============ start hardware log ============\n"
704       );
705       fprintf(f,
706         "============ start debug info ============\n%s=========== end debug info ============\n",
707         hd_data->log
708       );
709     }
710
711     i = hd_data->debug;
712     hd_data->debug = -1;
713     for(hd = hd_data->hd; hd; hd = hd->next) {
714       hd_dump_entry(hd_data, hd, f);
715     }
716     hd_data->debug = i;
717
718     fprintf(f,
719       "============ end hardware log ============\n"
720     );
721   }
722
723   if(is_short) {
724     /* always to stdout */
725     do_short(hd_data, hd0, stdout);
726     if(f) do_short(hd_data, hd0, f);
727   }
728   else {
729     for(hd = hd0; hd; hd = hd->next) {
730       hd_dump_entry(hd_data, hd, f ? f : stdout);
731     }
732     do_saveconfig(hd_data, hd0, f ? f : stdout);
733   }
734
735   hd_free_hd_list(hd0);
736 }
737
738
739 void do_short(hd_data_t *hd_data, hd_t *hd, FILE *f)
740 {
741 #ifndef LIBHD_TINY
742   hd_hw_item_t item;
743   hd_t *hd1;
744   int i;
745   char *s;
746
747   for(item = 1; item < hw_all; item++) {
748     i = 0;
749     s = hd_hw_item_name(item);
750     if(!s) continue;
751
752     if(item == hw_sys) continue;
753
754     for(hd1 = hd; hd1; hd1 = hd1->next) {
755       if(hd1->hw_class == item) {
756         if(!i++) fprintf(f, "%s:\n", s);
757         fprintf(f, "  %-20s %s\n",
758           hd1->unix_dev_name ? hd1->unix_dev_name : "",
759           hd1->model ? hd1->model : "???"
760         );
761       }
762     }
763   }
764 #endif
765 }
766
767
768 void do_test(hd_data_t *hd_data)
769 {
770   hd_t *hd;
771   char buf[10];
772   hd_hw_item_t hw_items[] = {
773     hw_sound, 0
774   };
775
776   for(hd = hd_list2(hd_data, hw_items, 1); hd; hd = hd->next) {
777     do {
778       *buf = 0;
779       fgets(buf, sizeof buf, stdin);
780       hd_add_driver_data(hd_data, hd);
781       hd_dump_entry(hd_data, hd, stderr);
782     } while(*buf == '\n');
783   }
784 }
785
786
787 void help()
788 {
789   fprintf(stderr,
790     "Usage: hwinfo [OPTIONS]\n"
791     "Probe for hardware.\n"
792     "Options:\n"
793     "    --<HARDWARE_ITEM>\n"
794     "        This option can be given more than once. Probe for a particular\n"
795     "        HARDWARE_ITEM. Available hardware items are:\n"
796     "        all, arch, bios, block, bluetooth, braille, bridge, camera,\n"
797     "        cdrom, chipcard, cpu, disk, dsl, dvb, fingerprint, floppy,\n"
798     "        framebuffer, gfxcard, hub, ide, isapnp, isdn, joystick, keyboard,\n"
799     "        memory, modem, monitor, mouse, netcard, network, partition,\n"
800     "        pci, pcmcia, pcmcia-ctrl, pppoe, printer, redasd,\n"
801     "        reallyall, scanner, scsi, smp, sound, storage-ctrl, sys, tape,\n"
802     "        tv, uml, usb, usb-ctrl, vbe, wlan, xen, zip\n"
803     "    --short\n"
804     "        Show only a summary. Use this option in addition to a hardware\n"
805     "        probing option.\n"
806     "    --listmd\n"
807     "        Normally hwinfo does not report RAID devices. Add this option to\n"
808     "        see them.\n"
809     "    --only DEVNAME\n"
810     "        This option can be given more than once. If you add this option,\n"
811     "        only data about devices with DEVNAME will be shown.\n"
812     "    --save-config SPEC\n"
813     "        Store config  for a particular device below /var/lib/hardware.\n"
814     "        SPEC can be a device name, an UDI, or 'all'. This option must be\n"
815     "        given in addition to a hardware probing option.\n"
816     "    --show-config UDI\n"
817     "        Show saved config data for a particular device.\n"
818     "    --map\n"
819     "        If disk names have  changed (e.g. after a kernel update) this\n"
820     "        prints a list of disk name mappings. Note  that  you must have\n"
821     "        used --save-config at some point before for this can work.\n"
822     "    --debug N\n"
823     "        Set debug level to N. The debug info is shown only in the log\n"
824     "        file. If you specify a log file, the debug level is implicitly\n"
825     "        set to a reasonable value.\n"
826     "    --verbose\n"
827     "        Increase verbosity. Only together with --map.\n"
828     "    --log FILE\n"
829     "        Write log info to FILE.\n"
830     "    --dump-db N\n"
831     "        Dump hardware data base. N is either 0 for the external data\n"
832     "        base in /var/lib/hardware, or 1 for the internal data base.\n"
833     "    --version\n"
834     "        Print libhd version.\n"
835     "    --help\n"
836     "        Print usage.\n"
837   );
838 }
839
840
841 /*
842  * Parse command line options.
843  */
844 int get_probe_flags(int argc, char **argv, hd_data_t *hd_data)
845 {
846   int i, j, k;
847   char *s, *t;
848   for(i = 0; i < argc; i++) {
849     s = argv[i];
850
851     if(!strcmp(s, ".")) {
852       return i + 1;
853     }
854
855     t = "debug=";
856     if(!strncmp(s, t, strlen(t))) {
857       hd_data->debug = strtol(s + strlen(t), NULL, 0);
858       continue;
859     }
860
861     t = "list=";
862     if(!strncmp(s, t, strlen(t))) {
863       list = s + strlen(t);
864       continue;
865     }
866
867     t = "list+=";
868     if(!strncmp(s, t, strlen(t))) {
869       list = s + strlen(t);
870       listplus = 1;
871       continue;
872     }
873
874     t = "log=";
875     if(!strncmp(s, t, strlen(t))) {
876       log_file = s + strlen(t);
877       continue;
878     }
879
880     t = "only=";
881     if(!strncmp(s, t, strlen(t))) {
882       add_str_list(&hd_data->only, s + strlen(t));
883       continue;
884     }
885
886     t = "root=";
887     if(!strncmp(s, t, strlen(t))) {
888       opt.root = s + strlen(t);
889       continue;
890     }
891
892     k = 1;
893     if(*s == '+')
894       s++;
895     else if(*s == '-')
896       k = 0, s++;
897
898     if((j = hd_probe_feature_by_name(s))) {
899       if(k)
900         hd_set_probe_feature(hd_data, j);
901       else
902         hd_clear_probe_feature(hd_data, j);
903       continue;
904     }
905
906     fprintf(stderr, "oops: don't know what to do with \"%s\"\n", s);
907     return -1;
908   }
909
910   return argc;
911 }
912
913 /*
914  * A simple progress function.
915  */
916 void progress2(char *pos, char *msg)
917 {
918   if(!test) printf("\r%64s\r", "");
919   printf("> %s: %s", pos, msg);
920   if(test) printf("\n");
921   fflush(stdout);
922 }
923
924
925 #define INSTALL_INF     "/etc/install.inf"
926
927 int braille_install_info(hd_data_t *hd_data)
928 {
929   hd_t *hd;
930   int ok = 0;
931   char *braille = NULL;
932   char *braille_dev = NULL;
933   str_list_t *sl0, *sl;
934   FILE *f;
935
936   hd = hd_list(hd_data, hw_braille, 1, NULL);
937
938   if(hd_data->progress) {
939     printf("\r%64s\r", "");
940     fflush(stdout);
941   }
942
943   for(; hd; hd = hd->next) {
944     if(
945       hd->base_class.id == bc_braille &&        /* is a braille display */
946       hd->unix_dev_name &&                      /* and has a device name */
947       (braille = hd->device.name)
948     ) {
949       braille_dev = hd->unix_dev_name;
950       ok = 1;
951       break;
952     }
953   }
954
955   if(!ok) return 1;
956
957   printf("found a %s at %s\n", braille, braille_dev);
958
959   sl0 = read_file(INSTALL_INF, 0, 0);
960   f = fopen(INSTALL_INF, "w");
961   if(!f) {
962     perror(INSTALL_INF);
963     return 1;
964   }
965   
966   for(sl = sl0; sl; sl = sl->next) {
967     if(
968       strstr(sl->str, "Braille:") != sl->str &&
969       strstr(sl->str, "Brailledevice:") != sl->str
970     ) {
971       fprintf(f, "%s", sl->str);
972     }
973   }
974
975   fprintf(f, "Braille: %s\n", braille);
976   fprintf(f, "Brailledevice: %s\n", braille_dev);
977   
978   fclose(f);
979
980   return 0;
981 }
982
983
984 /*
985  * get VGA parameter from /proc/cmdline
986  */
987 int get_fb_mode()
988 {
989 #ifndef __PPC__
990   FILE *f;
991   char buf[256], *s, *t;
992   int i, fb_mode = 0;
993
994   if((f = fopen("/proc/cmdline", "r"))) {
995     if(fgets(buf, sizeof buf, f)) {
996       t = buf;
997       while((s = strsep(&t, " "))) {
998         if(sscanf(s, "vga=%i", &i) == 1) fb_mode = i;
999         if(strstr(s, "vga=normal") == s) fb_mode = 0;
1000       }
1001     }
1002     fclose(f);
1003   }
1004
1005   return fb_mode > 0x10 ? fb_mode : 0;
1006 #else /* __PPC__ */
1007   /* this is the only valid test for active framebuffer ... */
1008   FILE *f = NULL;
1009   int fb_mode = 0;
1010   if((f = fopen("/dev/fb", "r"))) {
1011     fb_mode++;
1012     fclose(f);
1013   }
1014
1015   return fb_mode;
1016 #endif
1017 }
1018
1019
1020 /*
1021  * read "x11i=" entry from /proc/cmdline
1022  */
1023 char *get_x11i()
1024 {
1025   FILE *f;
1026   char buf[256], *s, *t;
1027   static char x11i[64] = { };
1028
1029   if(*x11i) return x11i;
1030
1031   if((f = fopen("/proc/cmdline", "r"))) {
1032     if(fgets(buf, sizeof buf, f)) {
1033       t = buf;
1034       while((s = strsep(&t, " "))) {
1035         if(sscanf(s, "x11i=%60s", x11i) == 1) break;
1036       }
1037     }
1038     fclose(f);
1039   }
1040
1041   return x11i;
1042 }
1043
1044
1045 /*
1046  * Assumes xf86_ver to be either "3" or "4" (or empty).
1047  */
1048 char *get_xserver(hd_data_t *hd_data, char **version, char **busid, driver_info_t **x11_driver)
1049 {
1050   static char display[16];
1051   static char xf86_ver[2];
1052   static char id[32];
1053   char c, *x11i = get_x11i();
1054   driver_info_t *di;
1055   hd_t *hd;
1056
1057   *x11_driver = NULL;
1058
1059   *display = *xf86_ver = *id = c = 0;
1060   *version = xf86_ver;
1061   *busid = id;
1062
1063   if(x11i) {
1064     if(*x11i == '3' || *x11i == '4') {
1065       c = *x11i;
1066     }
1067     else {
1068       if(*x11i >= 'A' && *x11i <= 'Z') {
1069         c = '3';
1070       }
1071       if(*x11i >= 'a' && *x11i <= 'z') {
1072         c = '4';
1073       }
1074       if(c) {
1075         strncpy(display, x11i, sizeof display - 1);
1076         display[sizeof display - 1] = 0;
1077       }
1078     }
1079   }
1080
1081   if(c) { xf86_ver[0] = c; xf86_ver[1] = 0; }
1082
1083   hd = hd_get_device_by_idx(hd_data, hd_display_adapter(hd_data));
1084
1085   if(hd && hd->bus.id == bus_pci)
1086     sprintf(id, "%d:%d:%d", hd->slot >> 8, hd->slot & 0xff, hd->func);
1087
1088   if(!hd || *display) return display;
1089
1090   for(di = hd->driver_info; di; di = di->next) {
1091     if(di->any.type == di_x11 && di->x11.server && di->x11.xf86_ver && !di->x11.x3d) {
1092       if(c == 0 || c == di->x11.xf86_ver[0]) {
1093         xf86_ver[0] = di->x11.xf86_ver[0];
1094         xf86_ver[1] = 0;
1095         strncpy(display, di->x11.server, sizeof display - 1);
1096         display[sizeof display - 1] = 0;
1097         *x11_driver = di;
1098         break;
1099       }
1100     }
1101   }
1102
1103   if(*display) return display;
1104
1105   if(c == 0) c = '4';   /* default to XF 4, if nothing else is known  */
1106
1107   xf86_ver[0] = c;
1108   xf86_ver[1] = 0;
1109   strcpy(display, c == '3' ? "FBDev" : "fbdev");
1110
1111   return display;
1112 }
1113
1114 int x11_install_info(hd_data_t *hd_data)
1115 {
1116   hd_t *hd;
1117   driver_info_t *di;
1118   char *x11i;
1119   int fb_mode, kbd_ok = 0;
1120   unsigned yast2_color = 0;
1121   char *xkbrules = NULL, *xkbmodel = NULL, *xkblayout = NULL;
1122   char *xserver, *version, *busid;
1123   driver_info_t *x11_driver;
1124   str_list_t *sl0, *sl;
1125   FILE *f;
1126
1127   /* get color info */
1128   hd_set_probe_feature(hd_data, pr_cpu);
1129   hd_set_probe_feature(hd_data, pr_prom);
1130   hd_scan(hd_data);
1131
1132   x11i = get_x11i();
1133   fb_mode = get_fb_mode();
1134
1135   hd_list(hd_data, hw_display, 1, NULL);
1136
1137   for(hd = hd_list(hd_data, hw_keyboard, 1, NULL); hd; hd = hd->next) {
1138     kbd_ok = 1;
1139     di = hd->driver_info;
1140     if(di && di->any.type == di_kbd) {
1141       xkbrules = di->kbd.XkbRules;
1142       xkbmodel = di->kbd.XkbModel;
1143       xkblayout = di->kbd.XkbLayout;
1144       break;
1145     }
1146     /* don't free di */
1147   }
1148
1149   xserver = get_xserver(hd_data, &version, &busid, &x11_driver);
1150
1151   switch(hd_mac_color(hd_data)) {
1152     case 0x01:
1153       yast2_color = 0x5a4add;
1154       break;
1155     case 0x04:
1156       yast2_color = 0x32cd32;
1157       break;
1158     case 0x05:
1159       yast2_color = 0xff7f50;
1160       break;
1161     case 0x07:
1162       yast2_color = 0x000000;
1163       break;
1164     case 0xff:
1165       yast2_color = 0x7f7f7f;
1166       break;
1167   }
1168
1169   if(hd_data->progress) {
1170     printf("\r%64s\r", "");
1171     fflush(stdout);
1172   }
1173
1174   sl0 = read_file(INSTALL_INF, 0, 0);
1175   f = fopen(INSTALL_INF, "w");
1176   if(!f) {
1177     perror(INSTALL_INF);
1178     return 1;
1179   }
1180   
1181   for(sl = sl0; sl; sl = sl->next) {
1182     if(
1183       strstr(sl->str, "Framebuffer:") != sl->str &&
1184       strstr(sl->str, "XServer:") != sl->str &&
1185       strstr(sl->str, "XVersion:") != sl->str &&
1186       strstr(sl->str, "XBusID:") != sl->str &&
1187       strstr(sl->str, "X11i:") != sl->str &&
1188       strstr(sl->str, "Keyboard:") != sl->str &&
1189       strstr(sl->str, "XkbRules:") != sl->str &&
1190       strstr(sl->str, "XkbModel:") != sl->str &&
1191       strstr(sl->str, "XkbLayout:") != sl->str &&
1192       strstr(sl->str, "XF86Ext:") != sl->str &&
1193       strstr(sl->str, "XF86Raw:") != sl->str
1194     ) {
1195       fprintf(f, "%s", sl->str);
1196     }
1197   }
1198
1199   fprintf(f, "Keyboard: %d\n", kbd_ok);
1200   if(fb_mode) fprintf(f, "Framebuffer: 0x%04x\n", fb_mode);
1201   if(x11i) fprintf(f, "X11i: %s\n", x11i);
1202   if(xserver && *xserver) {
1203     fprintf(f, "XServer: %s\n", xserver);
1204     if(*version) fprintf(f, "XVersion: %s\n", version);
1205     if(*busid) fprintf(f, "XBusID: %s\n", busid);
1206   }
1207   if(xkbrules && *xkbrules) fprintf(f, "XkbRules: %s\n", xkbrules);
1208   if(xkbmodel && *xkbmodel) fprintf(f, "XkbModel: %s\n", xkbmodel);
1209   if(xkblayout && *xkblayout) fprintf(f, "XkbLayout: %s\n", xkblayout);
1210
1211   if(x11_driver) {
1212     for(sl = x11_driver->x11.extensions; sl; sl = sl->next) {
1213       if(*sl->str) fprintf(f, "XF86Ext:   Load\t\t\"%s\"\n", sl->str);
1214     }
1215     for(sl = x11_driver->x11.options; sl; sl = sl->next) {
1216       if(*sl->str) fprintf(f, "XF86Raw:   Option\t\"%s\"\n", sl->str);
1217     }
1218     for(sl = x11_driver->x11.raw; sl; sl = sl->next) {
1219       if(*sl->str) fprintf(f, "XF86Raw:   %s\n", sl->str);
1220     }
1221   }
1222
1223   fclose(f);
1224
1225   return 0;
1226 }
1227
1228
1229 char *xserver3map[] =
1230 {
1231 #ifdef __i386__
1232   "VGA16", "xvga16",
1233   "RUSH", "xrush",
1234 #endif
1235 #if defined(__i386__) || defined(__alpha__) || defined(__ia64__)
1236   "SVGA", "xsvga",
1237   "3DLABS", "xglint",
1238 #endif
1239 #if defined(__i386__) || defined(__alpha__)
1240   "MACH64", "xmach64",
1241   "P9000", "xp9k",
1242   "S3", "xs3",
1243 #endif
1244 #ifdef __alpha__
1245   "TGA", "xtga",
1246 #endif
1247 #ifdef __sparc__
1248   "SUNMONO", "xsunmono",
1249   "SUN", "xsun",
1250   "SUN24", "xsun24",
1251 #endif
1252 #if 0
1253   "VMWARE", "xvmware",
1254 #endif
1255   0, 0
1256 };
1257
1258
1259 void dump_packages(hd_data_t *hd_data)
1260 {
1261   str_list_t *sl;
1262   int i;
1263
1264   hd_data->progress = NULL;
1265   hd_scan(hd_data);
1266
1267   sl = hddb_get_packages(hd_data);
1268
1269   for(i = 0; xserver3map[i]; i += 2) {
1270     if (!search_str_list(sl, xserver3map[i + 1]))
1271       add_str_list(&sl, new_str(xserver3map[i + 1]));
1272   }
1273
1274   for(; sl; sl = sl->next) {
1275     printf("%s\n", sl->str);
1276   }
1277 }
1278
1279
1280 struct x11pack {
1281   struct x11pack *next;
1282   char *pack;
1283 };
1284
1285 int oem_install_info(hd_data_t *hd_data)
1286 {
1287   hd_t *hd;
1288   str_list_t *str;
1289   str_list_t *x11packs = 0;
1290   str_list_t *sl0, *sl;
1291   FILE *f;
1292   int pcmcia, i;
1293
1294   driver_info_x11_t *di, *drvinfo;
1295
1296   hd_set_probe_feature(hd_data, pr_pci);
1297   hd_scan(hd_data);
1298   pcmcia = hd_has_pcmcia(hd_data);
1299
1300   for(hd = hd_list(hd_data, hw_display, 1, NULL); hd; hd = hd->next) {
1301     for(str = hd->requires; str; str = str->next) {
1302       if(!search_str_list(x11packs, str->str)) {
1303         add_str_list(&x11packs, str->str);
1304       }
1305     }
1306     drvinfo = (driver_info_x11_t *) hd->driver_info;
1307     for (di = drvinfo; di; di = (driver_info_x11_t *)di->next) {
1308       if (di->type != di_x11)
1309         continue;
1310       if (di->xf86_ver[0] == '3') {
1311         char *server = di->server;
1312         if (server) {
1313           for (i = 0; xserver3map[i]; i += 2)
1314             if (!strcmp(xserver3map[i], server))
1315               break;
1316           if (xserver3map[i])
1317             if (!search_str_list(x11packs, xserver3map[i + 1]))
1318               add_str_list(&x11packs, xserver3map[i + 1]);
1319         }
1320       }
1321     }
1322   }
1323
1324   if(hd_data->progress) {
1325     printf("\r%64s\r", "");
1326     fflush(stdout);
1327   }
1328
1329   sl0 = read_file(INSTALL_INF, 0, 0);
1330   f = fopen(INSTALL_INF, "w");
1331   if(!f) {
1332     perror(INSTALL_INF);
1333     return 1;
1334   }
1335   for(sl = sl0; sl; sl = sl->next) {
1336     if(
1337       strstr(sl->str, "X11Packages:") != sl->str &&
1338       strstr(sl->str, "Pcmcia:") != sl->str
1339     ) {
1340       fprintf(f, "%s", sl->str);
1341     }
1342   }
1343   if (x11packs) {
1344     fprintf(f, "X11Packages: ");
1345     for (sl = x11packs; sl; sl = sl->next) {
1346       if (sl != x11packs)
1347         fputc(',', f);
1348       fprintf(f, "%s", sl->str);
1349     }
1350     fputc('\n', f);
1351   }
1352   if (pcmcia)
1353     fprintf(f, "Pcmcia: %d\n", pcmcia);
1354   fclose(f);
1355   return 0;
1356 }
1357
1358
1359 void dump_db_raw(hd_data_t *hd_data)
1360 {
1361   hd_data->progress = NULL;
1362   hd_clear_probe_feature(hd_data, pr_all);
1363   hd_scan(hd_data);
1364
1365   if(opt.db_idx >= sizeof hd_data->hddb2 / sizeof *hd_data->hddb2) return;
1366
1367   hddb_dump_raw(hd_data->hddb2[opt.db_idx], stdout);
1368 }
1369
1370
1371 void dump_db(hd_data_t *hd_data)
1372 {
1373   hd_data->progress = NULL;
1374   hd_clear_probe_feature(hd_data, pr_all);
1375   hd_scan(hd_data);
1376
1377   if(opt.db_idx >= sizeof hd_data->hddb2 / sizeof *hd_data->hddb2) return;
1378
1379   hddb_dump(hd_data->hddb2[opt.db_idx], stdout);
1380 }
1381
1382
1383 void do_chroot(hd_data_t *hd_data, char *dir)
1384 {
1385   int i;
1386
1387   i = chroot(dir);
1388   ADD2LOG("chroot %s: %s\n", dir, i ? strerror(errno) : "ok");
1389
1390   if(!i) chdir("/");
1391 }
1392
1393
1394 void ask_db(hd_data_t *hd_data, char *query)
1395 {
1396   hd_t *hd;
1397   driver_info_t *di;
1398   str_list_t *sl, *query_sl;
1399   unsigned tag = 0, u, cnt;
1400   char buf[256];
1401
1402   setenv("hwprobe", "-all", 1);
1403   hd_scan(hd_data);
1404
1405   hd = add_hd_entry(hd_data, __LINE__, 0);
1406
1407   query_sl = hd_split(' ', query);
1408
1409   for(sl = query_sl; sl; sl = sl->next) {
1410     if(!strcmp(sl->str, "pci")) { tag = TAG_PCI; continue; }
1411     if(!strcmp(sl->str, "usb")) { tag = TAG_USB; continue; }
1412     if(!strcmp(sl->str, "pnp")) { tag = TAG_EISA; continue; }
1413     if(!strcmp(sl->str, "isapnp")) { tag = TAG_EISA; continue; }
1414     if(!strcmp(sl->str, "special")) { tag = TAG_SPECIAL; continue; }
1415     if(!strcmp(sl->str, "pcmcia")) { tag = TAG_PCMCIA; continue; }
1416
1417     if(sscanf(sl->str, "class=%i%n", &u, &cnt) >= 1 && !sl->str[cnt]) {
1418       hd->base_class.id = u >> 16;
1419       hd->sub_class.id = (u >> 8) & 0xff;
1420       hd->prog_if.id = u & 0xff;
1421       continue;
1422     }
1423
1424     if(sscanf(sl->str, "vendor=%i%n", &u, &cnt) >= 1 && !sl->str[cnt]) {
1425       hd->vendor.id = MAKE_ID(tag, u);
1426       continue;
1427     }
1428
1429     if(sscanf(sl->str, "vendor=%3s%n", buf, &cnt) >= 1 && !sl->str[cnt]) {
1430       u = name2eisa_id(buf);
1431       if(u) hd->vendor.id = u;
1432       tag = TAG_EISA;
1433       continue;
1434     }
1435
1436     if(sscanf(sl->str, "device=%i%n", &u, &cnt) >= 1 && !sl->str[cnt]) {
1437       hd->device.id = MAKE_ID(tag, u);
1438       continue;
1439     }
1440
1441     if(sscanf(sl->str, "subvendor=%i%n", &u, &cnt) >= 1 && !sl->str[cnt]) {
1442       hd->sub_vendor.id = MAKE_ID(tag, u);
1443       continue;
1444     }
1445
1446     if(sscanf(sl->str, "subvendor=%3s%n", buf, &cnt) >= 1 && !sl->str[cnt]) {
1447       u = name2eisa_id(buf);
1448       if(u) hd->sub_vendor.id = u;
1449       tag = TAG_EISA;
1450       continue;
1451     }
1452
1453     if(sscanf(sl->str, "subdevice=%i%n", &u, &cnt) >= 1 && !sl->str[cnt]) {
1454       hd->sub_device.id = MAKE_ID(tag, u);
1455       continue;
1456     }
1457
1458     if(sscanf(sl->str, "revision=%i%n", &u, &cnt) >= 1 && !sl->str[cnt]) {
1459       hd->revision.id = u;
1460       continue;
1461     }
1462
1463     if(sscanf(sl->str, "serial=%255s%n", buf, &cnt) >= 1 && !sl->str[cnt]) {
1464       hd->serial = new_str(buf);
1465       continue;
1466     }
1467
1468   }
1469
1470   free_str_list(query_sl);
1471
1472   hddb_add_info(hd_data, hd);
1473
1474   for(di = hd->driver_info; di; di = di->next) {
1475     if(di->any.type == di_module && di->module.modprobe) {
1476       for(sl = di->module.names; sl; sl = sl->next) {
1477         printf("%s%c", sl->str, sl->next ? ' ' : '\n');
1478       }
1479     }
1480   }
1481 }
1482
1483
1484 #if 0
1485
1486 int is_same_block_dev(hd_t *hd1, hd_t *hd2)
1487 {
1488   if(!hd1 || !hd2 || hd1 == hd2) return 0;
1489
1490   if(
1491     hd1->base_class.id != hd2->base_class.id ||
1492     hd1->sub_class.id != hd2->sub_class.id
1493   ) return 0;
1494
1495   if(
1496     !hd1->model ||
1497     !hd2->model ||
1498     strcmp(hd1->model, hd2->model)
1499   ) return 0;
1500
1501   if(hd1->revision.name || hd2->revision.name) {
1502     if(
1503       !hd1->revision.name ||
1504       !hd2->revision.name ||
1505       strcmp(hd1->revision.name, hd2->revision.name)
1506     ) return 0;
1507   }
1508
1509   if(hd1->serial || hd2->serial) {
1510     if(
1511       !hd1->serial ||
1512       !hd2->serial ||
1513       strcmp(hd1->serial, hd2->serial)
1514     ) return 0;
1515   }
1516
1517   return 1;
1518 }
1519
1520
1521 hd_t *get_same_block_dev(hd_t *hd_list, hd_t *hd, hd_status_value_t status)
1522 {
1523   for(; hd_list; hd_list = hd_list->next) {
1524     if(hd_list->status.available != status) continue;
1525     if(is_same_block_dev(hd_list, hd)) return hd_list;
1526   }
1527
1528   return NULL;
1529 }
1530
1531
1532 void get_mapping(hd_data_t *hd_data)
1533 {
1534   hd_t *hd_manual, *hd, *hd2;
1535   struct {
1536     hd_t *hd;
1537     unsigned unknown:1;
1538   } map[256] = { };
1539   unsigned maps = 0, u;
1540   int broken, first;
1541   hd_hw_item_t hw_items[] = { hw_disk, hw_cdrom, 0 };
1542
1543   hd_data->progress = NULL;
1544
1545   hd_data->flags.list_all = 1;
1546
1547   hd_manual = hd_list2(hd_data, hw_items, 1);
1548   for(hd = hd_manual; hd && maps < sizeof map / sizeof *map; hd = hd->next) {
1549     if(!hd->unix_dev_name) continue;
1550
1551     if(hd->status.available == status_yes) {
1552       /* check if we already have an active device with the same name */
1553       for(broken = u = 0; u < maps; u++) {
1554         if(!strcmp(map[u].hd->unix_dev_name, hd->unix_dev_name)) {
1555           map[u].unknown = 1;
1556           broken = 1;
1557         }
1558       }
1559       if(broken) continue;
1560
1561       /* ensure we really can tell different devices apart */
1562       if(get_same_block_dev(hd_manual, hd, status_yes)) {
1563         map[maps].hd = hd;
1564         map[maps].unknown = 1;
1565       }
1566       else {
1567         map[maps].hd = hd;
1568       }
1569       maps++;
1570     }
1571   }
1572
1573   /* ok, we have a list of all new devs */
1574
1575   for(u = 0; u < maps; u++) {
1576     if(map[u].unknown) {
1577       printf("%s\n", map[u].hd->unix_dev_name);
1578     }
1579     else {
1580       first = 1;
1581       for(hd2 = hd_manual; (hd2 = get_same_block_dev(hd2, map[u].hd, status_no)); hd2 = hd2->next) {
1582         if(hd2->unix_dev_name && strcmp(map[u].hd->unix_dev_name, hd2->unix_dev_name)) {
1583           printf("%s\t%s", first ? map[u].hd->unix_dev_name : "", hd2->unix_dev_name);
1584           first = 0;
1585         }
1586       }
1587       if(!first) printf("\n");
1588     }
1589
1590   }
1591 }
1592
1593 #endif
1594
1595
1596 void write_udi(hd_data_t *hd_data, char *udi)
1597 {
1598   hal_prop_t prop = {};
1599   int i;
1600
1601   prop.type = p_string;
1602   prop.key = "foo.bar";
1603   prop.val.str = "test XXX";
1604
1605   i = hd_write_properties(udi, &prop);
1606
1607   fprintf(stderr, "write = %d\n", i);
1608 }
1609
1610
1611
1612 void do_saveconfig(hd_data_t *hd_data, hd_t *hd, FILE *f)
1613 {
1614 #ifndef LIBHD_TINY
1615   int i;
1616
1617   if(!saveconfig) return;
1618
1619   fprintf(f, "\nSave Configuration:\n");
1620   for(; hd; hd = hd->next) {
1621     if(
1622       !strcmp(saveconfig, "all") ||
1623       (hd->udi && !strcmp(hd->udi, saveconfig)) ||
1624       (hd->unique_id && !strcmp(hd->unique_id, saveconfig)) ||
1625       (hd->unix_dev_name && !strcmp(hd->unix_dev_name, saveconfig)) ||
1626       (hd->unix_dev_name2 && !strcmp(hd->unix_dev_name2, saveconfig)) ||
1627       search_str_list(hd->unix_dev_names, saveconfig)
1628     ) {
1629       i = hd_write_config(hd_data, hd);
1630       fprintf(f, "  %s: %s\n",
1631         hd->udi ?: hd->unique_id ?: saveconfig,
1632         i ? "failed" : "ok"
1633       );
1634     }
1635   }
1636 #endif
1637 }
1638
1639
1640 int map_cmp(const void *p0, const void *p1)
1641 {
1642   const map_t *m0, *m1;
1643
1644   m0 = p0;
1645   m1 = p1;
1646
1647   if(!m0->dev && !m1->dev) return 0;
1648   if(!m0->dev && m1->dev) return 1;
1649   if(m0->dev && !m1->dev) return -1;
1650
1651   return strcmp(m0->dev, m1->dev);
1652 }
1653
1654
1655 unsigned map_fill(map_t *map, hd_data_t *hd_data, hd_t *hd_manual)
1656 {
1657   hd_t *hd, *hd_ctrl;
1658   hd_hw_item_t type;
1659   hd_res_t *res;
1660   unsigned map_len = 0;
1661   int i, j;
1662
1663   if(!map) return 0;
1664
1665   for(hd = hd_manual; hd; hd = hd->next) {
1666     type = hw_none;
1667     if(hd_is_hw_class(hd, hw_cdrom)) type = hw_cdrom;
1668     if(hd_is_hw_class(hd, hw_disk)) type = hw_disk;
1669
1670     if(type == hw_none || !hd->unix_dev_name) continue;
1671
1672     if(hd->status.available_orig == status_no) continue;
1673
1674     hd_ctrl = hd_get_device_by_idx(hd_data, hd->attached_to);
1675     map[map_len].type = type;
1676     map[map_len].dev = hd->unix_dev_name;
1677     map[map_len].id = hd->unique_id;
1678     if(hd_ctrl) map[map_len].p_id = hd_ctrl->unique_id;
1679     if(hd->serial && *hd->serial) map[map_len].serial = hd->serial;
1680     if(hd->model) map[map_len].model = hd->model;
1681
1682     for(res = hd->res; res; res = res->next) {
1683       if(
1684         res->any.type == res_size &&
1685         res->size.unit == size_unit_sectors
1686       ) {
1687         map[map_len].size = res->size.val1;
1688         break;
1689       }
1690     }
1691
1692     map_len++;
1693   }
1694
1695   if(map_len) qsort(map, map_len, sizeof *map, map_cmp);
1696
1697   /* check whether model, serial and size are unique */
1698
1699   for(i = 0; i < map_len; i++) {
1700     if(map[i].model) {
1701       map[i].model_ok = 1;
1702       for(j = i + 1; j < map_len; j++) {
1703         if(map[j].model && !strcmp(map[i].model, map[j].model)) {
1704           map[i].model_ok = 0;
1705           break;
1706         }
1707       }
1708     }
1709
1710     if(map[i].serial) {
1711       map[i].serial_ok = 1;
1712       for(j = i + 1; j < map_len; j++) {
1713         if(map[j].serial && !strcmp(map[i].serial, map[j].serial)) {
1714           map[i].serial_ok = 0;
1715           break;
1716         }
1717       }
1718     }
1719
1720     if(map[i].size) {
1721       map[i].size_ok = 1;
1722       for(j = i + 1; j < map_len; j++) {
1723         if(map[i].size == map[j].size) {
1724           map[i].size_ok = 0;
1725           break;
1726         }
1727       }
1728     }
1729   }
1730
1731   return map_len;
1732 }
1733
1734
1735 void map_dump(map_t *map, unsigned map_len)
1736 {
1737   int i;
1738
1739   for(i = 0; i < map_len; i++) {
1740     fprintf(stderr,
1741       "%s: %s = %s\n\t%smodel \"%s\", %sserial \"%s\"\n\t%ssize %"PRIu64" sectors\n\t%s @ %s\n\n",
1742       map[i].type == hw_disk ? " disk" : "cdrom",
1743       map[i].dev, map[i].dev_old,
1744       map[i].model_ok ? "*" : "",
1745       map[i].model,
1746       map[i].serial_ok ? "*" : "",
1747       map[i].serial,
1748       map[i].size_ok ? "*" : "",
1749       map[i].size,
1750       map[i].id, map[i].p_id
1751     );
1752   }
1753 }
1754
1755
1756 int get_mapping2()
1757 {
1758   hd_data_t *hd_data, *hd_data_new;
1759   hd_t *hd_manual, *hd;
1760   hd_hw_item_t hw_items[] = { hw_disk, hw_storage_ctrl, 0 };
1761   map_t *map, *map_old;
1762   unsigned cnt, map_len, map_old_len;
1763   int err = 0, i, j;
1764   char *s;
1765
1766   hd_data = calloc(1, sizeof *hd_data);
1767   hd_data->flags.list_all = 1;
1768
1769   hd_data_new = calloc(1, sizeof *hd_data_new);
1770   hd_data_new->flags.list_all = 1;
1771   hd_data_new->debug = -1;
1772
1773   /* first, old data */
1774
1775   hd_list(hd_data, hw_manual, 1, NULL);
1776   hd_manual = hd_list2(hd_data, hw_items, 0);
1777
1778   for(cnt = 0, hd = hd_manual; hd; hd = hd->next) cnt++;
1779   map_old = cnt ? calloc(cnt, sizeof *map_old) : NULL;
1780   map_old_len = map_fill(map_old, hd_data, hd_manual);
1781
1782   /* now, new data */
1783
1784   s = getenv("LIBHD_HDDB_DIR_NEW");
1785   if(s) {
1786     setenv("LIBHD_HDDB_DIR", s, 1);
1787
1788     hd_list(hd_data_new, hw_manual, 1, NULL);
1789     hd_manual = hd_list2(hd_data_new, hw_items, 0);
1790   }
1791   else {
1792     hd_data_new->flags.list_all = 0;
1793     hd_manual = hd_list2(hd_data_new, hw_items, 1);
1794   }
1795
1796   for(cnt = 0, hd = hd_manual; hd; hd = hd->next) cnt++;
1797   map = cnt ? calloc(cnt, sizeof *map) : NULL;
1798   map_len = map_fill(map, hd_data_new, hd_manual);
1799
1800   if(map_len) {
1801
1802     /* try based on serial... */
1803     for(i = 0; i < map_len; i++) {
1804       if(map[i].assigned || !map[i].serial_ok) continue;
1805       for(j = 0; j < map_old_len; j++) {
1806         if(map_old[j].assigned || !map_old[j].serial_ok) continue;
1807         if(!strcmp(map[i].serial, map_old[j].serial)) {
1808           map[i].dev_old = map_old[j].dev;
1809           map[i].assigned = map_old[j].assigned = 1;
1810         }
1811       }
1812     }
1813
1814     /* ... then based on model... */
1815     for(i = 0; i < map_len; i++) {
1816       if(map[i].assigned || !map[i].model_ok) continue;
1817       for(j = 0; j < map_old_len; j++) {
1818         if(map_old[j].assigned || !map_old[j].model_ok) continue;
1819         if(!strcmp(map[i].model, map_old[j].model)) {
1820           map[i].dev_old = map_old[j].dev;
1821           map[i].assigned = map_old[j].assigned = 1;
1822         }
1823       }
1824     }
1825
1826     /* ... and finally based on disk size */
1827     for(i = 0; i < map_len; i++) {
1828       if(map[i].assigned || !map[i].size_ok) continue;
1829       for(j = 0; j < map_old_len; j++) {
1830         if(map_old[j].assigned || !map_old[j].size_ok) continue;
1831         if(map[i].size == map_old[j].size) {
1832           map[i].dev_old = map_old[j].dev;
1833           map[i].assigned = map_old[j].assigned = 1;
1834         }
1835       }
1836     }
1837
1838     if(opt.verbose) {
1839       map_dump(map_old, map_old_len);
1840       fprintf(stderr, "- - - - - - - - - - - - - - - - - - - -\n");
1841       map_dump(map, map_len);
1842     }
1843
1844     for(i = 0; i < map_len; i++) {
1845       if(map[i].dev_old && strcmp(map[i].dev, map[i].dev_old)) {
1846         printf("%s\t%s\n", map[i].dev, map[i].dev_old);
1847       }
1848     }
1849
1850   }
1851
1852 #if 0
1853
1854   // based on controller
1855
1856   for(hd = hd_manual; hd; hd = hd->next) {
1857     type = hw_none;
1858     if(hd_is_hw_class(hd, hw_cdrom)) type = hw_cdrom;
1859     if(hd_is_hw_class(hd, hw_disk)) type = hw_disk;
1860
1861     if(type == hw_none || !hd->unix_dev_name) continue;
1862
1863     hd_ctrl = hd_get_device_by_idx(hd_data_new, hd->attached_to);
1864
1865     if(hd_ctrl) {
1866       for(i = 0; i < map_len; i++) {
1867         if(
1868           map[i].type == type &&
1869           !map[i].dev_new &&
1870           map[i].p_id &&
1871           !strcmp(map[i].p_id, hd_ctrl->unique_id)
1872         ) {
1873           map[i].dev_new = hd->unix_dev_name;
1874           break;
1875         }
1876       }
1877       if(i == map_len) unassigned++;
1878     }
1879   }
1880 #endif
1881
1882   free(map);
1883   free(map_old);
1884
1885   hd_free_hd_data(hd_data_new);
1886   free(hd_data_new);
1887
1888   hd_free_hd_data(hd_data);
1889   free(hd_data);
1890
1891   return err;
1892 }
1893
1894