source: trunk/third/sysinfo/sysinfo.c @ 12269

Revision 12269, 16.7 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12268, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1992-1998 Michael A. Cooper.
3 * This software may be freely used and distributed provided it is not
4 * sold for profit or used in part or in whole for commercial gain
5 * without prior written agreement, and the author is credited
6 * appropriately.
7 */
8
9#ifndef lint
10static char *RCSid = "$Revision: 1.1.1.3 $";
11#endif
12
13/*
14 * Display System Information
15 */
16
17#include <stdio.h>
18#include <sys/types.h>
19
20#include "defs.h"
21
22/*
23 * Local declarations
24 */
25int                             Danger = FALSE;
26int                             DoPrintUnknown = FALSE;
27int                             DoPrintVersion = FALSE;
28int                             DoPrintLicense = FALSE;
29int                             MsgLevel = L_GENERAL;
30char                           *FormatStr = NULL;
31FormatType_t                    FormatType = FT_PRETTY;
32char                           *MsgClassStr = NULL;
33int                             MsgClassFlags = SIM_DEFAULT;
34int                             UseProm = 0;
35int                             DebugFlag = 0;
36int                             OffSetAmt = 4;
37int                             UseConfig = 1;
38char                           *ShowStr = NULL;
39char                           *ClassNames = NULL;
40char                           *TypeNames = NULL;
41char                           *MsgLevelStr = NULL;
42char                           *ListStr = NULL;
43char                           *UnSupported = NULL;
44char                           *ConfFile = NULL;
45char                           *ConfDir = CONFIG_DIR;
46char                           *MCLprogramName = "sysinfo";
47char                          **Environ = NULL;
48extern char                    *RepSep;
49int                             DoNothing = TRUE;
50
51#if     defined(OPTION_COMPAT)
52int                             Terse = FALSE;
53#endif  /* OPTION_COMPAT */
54
55/*
56 * Command line options table.
57 */
58OptionDescRec Opts[] = {
59    {"-cffile", SepArg,         OptStr, (OptPtr_t) &ConfFile,           NULL,
60         "file","Sysinfo config file"},
61    {"-cfdir",  SepArg,         OptStr, (OptPtr_t) &ConfDir,            NULL,
62         "directory","Sysinfo config directory"},
63    {"-class",  SepArg,         OptStr, (OptPtr_t) &ClassNames,         NULL,
64         "<see \"-list class\">",       "Class name"},
65    {"-danger",NoArg,           OptBool,(OptPtr_t) &Danger,             "1",
66         NULL,  "Disable runtime platform checks" },
67    {"-license",NoArg,          OptBool,(OptPtr_t) &DoPrintLicense,     "1",
68         NULL,  "Print license information" },
69    {"-list",   SepArg,         OptStr, (OptPtr_t) &ListStr,            "-",
70         "<what>",      "List information about <what>"},
71    {"-format", SepArg,         OptStr, (OptPtr_t) &FormatStr,          NULL,
72         "<see \"-list format\">",      "Format Type"},
73    {"-msgclass",SepArg,        OptStr, (OptPtr_t) &MsgClassStr,        NULL,
74         "<see \"-list msgclass\">",    "Message Classes to output"},
75    {"-msglevel",SepArg,        OptStr, (OptPtr_t) &MsgLevelStr,        NULL,
76         "<see \"-list msglevel\">",    "Message Levels to output"},
77    {"-offset", SepArg,         OptInt, (OptPtr_t) &OffSetAmt,          NULL,
78         "<amount>",    "Number of spaces to offset device info"},
79    {"-repsep", SepArg,         OptStr, (OptPtr_t) &RepSep,             NULL,
80         "<string>","Report field seperator"},
81    {"-show",   SepArg,         OptStr, (OptPtr_t) &ShowStr,            NULL,
82         "<see \"-list show\">",        "Show names"},
83    {"-type",   SepArg,         OptStr, (OptPtr_t) &TypeNames,          NULL,
84         "<see \"-list type\">",        "Type name"},
85    {"+unknown",NoArg,          OptBool,(OptPtr_t) &DoPrintUnknown,     "1",
86         NULL,  "Print unknown devices"},
87    {"-unknown",NoArg,          OptBool,(OptPtr_t) &DoPrintUnknown,     "0",
88         NULL,  "Don't print unknown devices"},
89    {"+useconfig",NoArg,        OptBool,(OptPtr_t) &UseConfig,          "1",
90         NULL,  "Use config (-cffile,-cfdir) files"},
91    {"-useconfig",NoArg,        OptBool,(OptPtr_t) &UseConfig,          "0",
92         NULL,  "Don't use config (-cffile,-cfdir) files"},
93    {"+useprom",NoArg,          OptBool,(OptPtr_t) &UseProm,            "1",
94         NULL,  "Use PROM values"},
95    {"-useprom",NoArg,          OptBool,(OptPtr_t) &UseProm,            "0",
96         NULL,  "Don't use PROM values"},
97    {"-version",NoArg,          OptBool,(OptPtr_t) &DoPrintVersion,     "1",
98         NULL,  "Print version of this program" },
99    /*
100     * These options are obsolete, but are present for backwards compatibility
101     * Some of the options still do things and some don't (see DoNothing).
102     */
103    {"-debug",ArgHidden|SepArg, OptInt, (OptPtr_t) &DebugFlag,          "1",
104        NULL,  "Enable debugging" },
105    {"-level",ArgHidden|SepArg, OptStr, (OptPtr_t) &MsgLevelStr,        NULL,
106         "<see \"-list msglevel\">",    "Message Levels to output"},
107    {"+all", ArgHidden|NoArg,   OptBool,(OptPtr_t) &DoNothing,          "1",
108         NULL,  "Print all information"},
109    {"-all", ArgHidden|NoArg,   OptBool,(OptPtr_t) &DoNothing,          "0",
110         NULL,  "Don't print all information"},
111#if     defined(OPTION_COMPAT)
112    /*
113     * Old options from version 2.x
114     * that can be enabled for backwards compatibility
115     */
116    {"+terse",  NoArg,OptBool,(OptPtr_t) &Terse,"1",NULL,"Print info in terse format"},
117    {"-terse",  NoArg,OptBool,(OptPtr_t) &Terse,"0",NULL,"Don't print info in terse format"},
118#endif  /* OPTION_COMPAT */
119};
120
121/*
122 * Values and names of levels
123 */
124ListInfo_t MsgLevelNames[] = {
125    { L_TERSE,          "terse",        "Values only (for parsing)" },
126    { L_BRIEF,          "brief",        "Brief, but human readable" },
127    { L_GENERAL,        "general",      "General info" },
128    { L_DESC,           "descriptions", "Show description info" },
129    { L_CONFIG,         "config",       "Show configuration info" },
130    { L_ALL,            "all",          "All information available" },
131    { 0 },
132};
133
134/*
135 * MsgClass options
136 */
137ListInfo_t MsgClassNames[] = {
138    { SIM_INFO,         "info",         "Normal information" },
139    { SIM_WARN,         "warn",         "Warnings" },
140    { SIM_GERR,         "gerror",       "General errors" },
141    { SIM_CERR,         "cerror",       "Critical errors" },
142    { SIM_UNKN,         "unknown",      "Messages about unknown values" },
143    { SIM_DBG,          "debug",        "Debugging information" },
144    { SIM_ALL,          "all",          "All message classes" },
145    { 0 },
146};
147
148/*
149 * Format options
150 */
151ListInfo_t FormatNames[] = {
152    { FT_PRETTY,        "pretty",       "Format output for humans" },
153    { FT_REPORT,        "report",       "Format output for programs" },
154    { 0 },
155};
156
157/*
158 * List options
159 */
160static void                     ListMsgLevel();
161static void                     ListFormat();
162static void                     ListMsgClass();
163static void                     ListShow();
164
165ListInfo_t ListInfo[] = {
166    { 0, "class",       "Values for `-class' option",   ClassList },
167    { 0, "format",      "Values for `-format' option",  ListFormat },
168    { 0, "msgclass",    "Values for `-msgclass' option",ListMsgClass },
169    { 0, "msglevel",    "Values for `-msglevel' option",ListMsgLevel },
170    { 0, "show",        "Values for `-show' option",    ClassCallList },
171    { 0, "type",        "Values for `-type' option",    TypeList },
172    { 0 },
173};
174
175/*
176 * List possible values for List
177 */
178static void ListInfoDesc(OptStr, List)
179    char                       *OptStr;
180    ListInfo_t                 *List;
181{
182    register ListInfo_t        *ListPtr;
183
184    if (OptStr)
185        SImsg(SIM_INFO,
186        "\nThe following values may be specified with the `%s' option:\n",
187        OptStr);
188
189    SImsg(SIM_INFO, "%-20s %s\n", "VALUE", "DESCRIPTION");
190
191    for (ListPtr = List; ListPtr->Name; ++ListPtr)
192        SImsg(SIM_INFO, "%-20s %s\n", ListPtr->Name,
193               (ListPtr->Desc) ? ListPtr->Desc : "");
194}
195
196/*
197 * List Format values
198 */
199static void ListFormat()
200{
201    ListInfoDesc("-format", FormatNames);
202}
203
204/*
205 * List MsgClass values
206 */
207static void ListMsgClass()
208{
209    ListInfoDesc("-msgclass", MsgClassNames);
210}
211
212/*
213 * List MsgLevel values
214 */
215static void ListMsgLevel()
216{
217    ListInfoDesc("-msglevel", MsgLevelNames);
218}
219
220/*
221 * List list values
222 */
223static void ListList()
224{
225    ListInfoDesc("-list", ListInfo);
226}
227
228/*
229 * List information about each word found in Str.
230 */
231static void List(Str)
232    char                       *Str;
233{
234    register ListInfo_t        *ListPtr;
235    char                       *Word;
236    int                         Found;
237
238    if (EQ(Str, "-")) {
239        ListList();
240        return;
241    }
242
243    for (Word = strtok(Str, ","); Word; Word = strtok((char *)NULL, ",")) {
244        for (ListPtr = ListInfo, Found = FALSE;
245             ListPtr->Name && !Found; ++ListPtr)
246            if (EQ(Word, ListPtr->Name)) {
247                Found = TRUE;
248                (*ListPtr->List)();
249            }
250
251        if (!Found) {
252            SImsg(SIM_CERR, "The word \"%s\" is invalid.", Word);
253            ListList();
254            return;
255        }
256    }
257}
258
259/*
260 * Get argument number "arg" from "str".
261 */
262static char *GetArg(Str, ArgNum)
263    char                       *Str;
264    int                         ArgNum;
265{
266    register char              *p, *start = NULL;
267    register int                c;
268
269    for (c = 1, p = Str; p && *p; ++c) {
270        /* set start of word */
271        start = p;
272
273        /* skip over word */
274        while (p && *p && *p != ' ' && *p != '\t' && *p != '\n')
275            ++p;
276
277        /* is this what we want? */
278        if (c == ArgNum) {
279            if (p) *p = C_NULL;
280            break;
281        }
282
283        /* skip white space */
284        while (*p == ' ' || *p == '\t')
285            ++p;
286    }
287
288    return(start);
289}
290
291/*
292 * Parse and set the level keyword list
293 */
294static int ParseMsgLevel(Str)
295    char                       *Str;
296{
297    ListInfo_t                 *ListPtr;
298    char                       *Word;
299    int                         Found;
300
301    /*
302     * Check each word in the MsgLevelNames table
303     */
304    for (Word = strtok(Str, ","); Word; Word = strtok((char *)NULL, ",")) {
305        for (ListPtr = MsgLevelNames, Found = FALSE;
306             ListPtr && ListPtr->Name && !Found; ListPtr++) {
307            if (strncasecmp(Word, ListPtr->Name, strlen(Word)) == 0) {
308                MsgLevel |= ListPtr->IntKey;
309                Found = TRUE;
310            }
311        }
312        if (!Found) {
313            SImsg(SIM_CERR, "The word \"%s\" is not a valid message level.",
314                  Word);
315            return(-1);
316        }
317    }
318
319    return(0);
320}
321
322/*
323 * Parse and set the Message Class Flags
324 */
325static int ParseMsgClass(Str)
326    char                       *Str;
327{
328    ListInfo_t                 *ListPtr;
329    char                       *Word;
330    int                         Found;
331    int                         NewFlags = 0;
332
333    /*
334     * Check each word in the MsgClassNames table
335     */
336    for (Word = strtok(Str, ","); Word; Word = strtok((char *)NULL, ",")) {
337        for (ListPtr = MsgClassNames, Found = FALSE;
338             ListPtr && ListPtr->Name && !Found; ListPtr++) {
339            if (EQN(Word, ListPtr->Name, strlen(Word))) {
340                NewFlags |= ListPtr->IntKey;
341                Found = TRUE;
342            }
343        }
344        if (!Found) {
345            SImsg(SIM_CERR, "The word \"%s\" is not a valid MsgClass flag.",
346                  Word);
347            return(-1);
348        }
349    }
350
351    if (NewFlags)
352        MsgClassFlags = NewFlags;
353
354    return(0);
355}
356
357/*
358 * Parse and set the format type
359 */
360static int ParseFormat(Str)
361    char                       *Str;
362{
363    register ListInfo_t        *ListPtr;
364    char                       *Word;
365    int                         Found;
366
367    /*
368     * Check each word in the FormatNames table
369     */
370    for (Word = strtok(Str, ","); Word; Word = strtok((char *)NULL, ",")) {
371        for (ListPtr = FormatNames, Found = FALSE; ListPtr->Name && !Found;
372             ListPtr++) {
373            if (strncasecmp(Word, ListPtr->Name, strlen(Word)) == 0) {
374                FormatType = ListPtr->IntKey;
375                Found = TRUE;
376            }
377        }
378        if (!Found) {
379            SImsg(SIM_CERR, "The word \"%s\" is not a valid format type.",
380                  Word);
381            return(-1);
382        }
383    }
384
385    return(0);
386}
387
388/*
389 * Check for license.
390 *
391 *      PLEASE DO NOT DISABLE.  DISABLING THIS CODE IS A VIOLATION OF
392 *      THE LICENSE.  AND IT'S NOT VERY NICE EITHER.
393 */
394static mcl_t *CheckMCL(Product)
395     char                      *Product;
396{
397    static mcl_t                Query;
398    static char                 FileBuff[MAXPATHLEN];
399
400    (void) snprintf(FileBuff, sizeof(FileBuff), "%s/license%s",
401                    ConfDir, MCL_FILE_EXT);
402    (void) memset(&Query, 0, sizeof(Query));
403    Query.File = FileBuff;
404    Query.Product = Product;
405
406    if (MCLcheck(&Query) < 0) {
407        if (Query.Status == MCL_STAT_NOTFOUND)
408            SImsg(SIM_CERR|SIM_NOLBL, "\
409You are running a free 60-day DEMO version of %s.  Please obtain a\n\
410permanent license or cease using this program within 60 days.  Licenses\n\
411may be obtained from http://www.MagniComp.com/sysinfo/#getlicense\n",
412                  Product);
413        SImsg(SIM_DBG, "Cannot obtain license: %s",
414              (Query.Msg) ? Query.Msg : "UNKNOWN REASON");
415        return((mcl_t *) NULL);
416    }
417
418    return(&Query);
419}
420
421#if     defined(OPTION_COMPAT)
422/*
423 * Set option compatibility
424 */
425static void SetOptionCompat()
426{
427    /*
428     * For backwards compatibility
429     */
430    if (Terse)
431        MsgLevel |= L_TERSE;
432}
433#endif  /* OPTION_COMPAT */
434
435/*
436 * Check to see if we're running with the right Root Access.
437 */
438static void CheckRunTimeAccess()
439{
440#if     defined(RA_LEVEL) && RA_LEVEL == RA_ADVISED
441    if (geteuid() != 0) {
442        SImsg(SIM_WARN,
443"This program should be run as `root' (uid=0) to obtain\n\t\
444all supported information.  Please either make setuid to\n\t\
445root (chown root sysinfo;chmod u+s sysinfo) or invoke as a\n\t\
446uid=0 user such as `root'.");
447    }
448#endif  /* RA_ADVISED */
449#if     defined(RA_LEVEL) && RA_LEVEL == RA_NONE
450    /* Do nothing */
451    return;
452#endif  /* RA_NONE */
453}
454
455/*
456 * Check to see if we're running on the same platform as we were
457 * compiled on.
458 */
459static void CheckRunTimePlatform()
460{
461    extern char                 BuildCPUType[];
462    extern char                 BuildCPUArch[];
463    extern char                 BuildOSname[];
464    extern char                 BuildOSver[];
465    static char                 What[512];
466
467    /*
468     * Skip this check if the user specified the -danger flag
469     */
470    if (Danger)
471        return;
472
473    /*
474     * Yes, it is possible for the OS name to be different.
475     * i.e. "IRIX" vs. "IRIX64"
476     */
477    if (!EQ(GetOSName(), BuildOSname))
478        (void) snprintf(What, sizeof(What),
479                "This program was built on `%s' but is being run on `%s'.",
480                        BuildOSname, GetOSName());
481    else if (!EQ(GetOSVer(), BuildOSver))
482        (void) snprintf(What, sizeof(What),
483"This program was built on `%s %s' \
484but is being run on `%s %s'.",
485                        BuildOSname, BuildOSver, GetOSName(), GetOSVer());
486#if     defined(sunos) && OSMVER == 4
487    else if (!EQ(GetKernArch(), BuildCPUArch))
488        (void) snprintf(What, sizeof(What),
489"This program was built on a `%s' kernel arch machine and is being\
490run on a `%s' machine.",
491                        BuildCPUArch, GetKernArch());
492#endif
493
494    if (What[0]) {
495        SImsg(SIM_CERR, "%s", What);
496        SImsg(SIM_CERR,
497        "%s may not be able to provide consistant information.",
498              ProgramName);
499        SImsg(SIM_CERR,
500        "If you wish to override and run anyway, use the `-danger'");
501        SImsg(SIM_CERR, "option.  This is generally not advised.");
502        exit(1);
503    }
504}
505
506/*
507 * Print version information
508 */
509void PrintVersion()
510{
511    extern char                 BuildDate[];
512    extern char                 BuildHost[];
513    extern char                 BuildUser[];
514    extern char                 BuildOSname[];
515    extern char                 BuildOSver[];
516    extern char                 BuildOStype[];
517    extern char                 BuildAppArch[];
518    extern char                 BuildCPUArch[];
519    int                         MsgFlags = SIM_INFO|SIM_DBG|SIM_NONL;
520    char                       *MCLinfo;
521
522    if (!VL_TERSE)
523        SImsg(MsgFlags, "SysInfo Version ");
524    if (PATCHLEVEL)
525        SImsg(MsgFlags, "%s.%d", VERSION_STR, PATCHLEVEL);
526    else
527        SImsg(MsgFlags, "%s", VERSION_STR);
528
529    if (!VL_TERSE) {
530        SImsg(MsgFlags, " (%s)\n", VERSION_STATUS);
531        SImsg(MsgFlags, "Binary Build Information:\n");
532#define bOFFSET 10
533        SImsg(MsgFlags, "\t%*s: %s\n", bOFFSET, "Build Date", BuildDate);
534        SImsg(MsgFlags, "\t%*s: %s on %s\n",
535              bOFFSET, "Built By", BuildUser, BuildHost);
536        SImsg(MsgFlags, "\t%*s: %s %s\n",
537              bOFFSET, "OS", BuildOSname, BuildOSver);
538        SImsg(MsgFlags, "\t%*s: %s\n", bOFFSET, "OS Type",  BuildOStype);
539        SImsg(MsgFlags, "\t%*s: %s\n", bOFFSET, "App Arch", BuildAppArch);
540        SImsg(MsgFlags, "\t%*s: %s\n", bOFFSET, "CPU Arch", BuildCPUArch);
541#undef bOFFSET
542        SImsg(MsgFlags, GENERAL_MSG);
543        SImsg(MsgFlags, COPYRIGHT_MSG);
544    }
545
546    SImsg(MsgFlags, "\n");
547}
548
549/*
550 * The beginning
551 */
552main(Argc, Argv, Envp)
553    int                         Argc;
554    char                      **Argv;
555    char                      **Envp;
556{
557    char                       *cp;
558    mcl_t                      *MClic;
559
560    Environ = Envp;
561
562    /*
563     * Parse command line arguments.
564     */
565    if (ParseOptions(Opts, Num_Opts(Opts), Argc, Argv) < 0)
566        exit(1);
567
568    /*
569     * Cleanup our program name used for error messages.
570     */
571    if (cp = strrchr(ProgramName, '/'))
572        ProgramName = ++cp;
573
574    /*
575     * Set Message Class Flags
576     */
577    if (MsgClassStr && ParseMsgClass(MsgClassStr))
578        exit(1);
579
580    /*
581     * For -debug backwards compatibile
582     */
583    if (DebugFlag)
584        MsgClassFlags |= SIM_DBG|SIM_GERR;
585
586    /*
587     * If we're setuid(root) and we're not being run by user "root",
588     * don't let unpriv'ed users try anything tricky.
589     */
590    if (UseConfig && (getuid() != 0 && geteuid() == 0) &&
591        (ConfFile || !EQ(ConfDir, CONFIG_DIR))) {
592        SImsg(SIM_CERR,
593        "Only \"root\" may specify \"-cfdir\" when %s is \"setuid root\".",
594              ProgramName);
595        exit(1);
596    }
597
598    UnSupported = (Debug) ? "**UNSUPPORTED**" : (char *)NULL;
599
600#if     defined(OPTION_COMPAT)
601    SetOptionCompat();
602#endif
603
604    /*
605     * Show version info
606     */
607    if (DoPrintVersion || Debug) {
608        PrintVersion();
609        if (!Debug)
610            exit(0);
611    }
612 
613    /*
614     * Parse config files
615     */
616    if (UseConfig) {
617        if (CFparse(ConfFile, ConfDir) != 0) {
618            SImsg(SIM_CERR, "Errors occured while parsing config file(s).");
619            exit(1);
620        }
621    }
622
623    /*
624     * Check MCL
625     */
626    MClic = CheckMCL(MCLprogramName);
627
628    if (DoPrintLicense) {
629        if (cp = MCLgetInfo(MClic))
630            SImsg(SIM_INFO|SIM_NONL|SIM_DBG, cp);
631        exit(0);
632    }
633
634    /*
635     * Do any list commands and exit
636     */
637    if (ListStr) {
638        List(ListStr);
639        exit(0);
640    }
641
642    /*
643     * Set verbosity strings
644     */
645    if (MsgLevelStr && ParseMsgLevel(MsgLevelStr))
646        exit(1);
647
648    /*
649     * Set format type
650     */
651    if (FormatStr && ParseFormat(FormatStr))
652        exit(1);
653
654    /*
655     * Check to see if runtime access is ok.
656     */
657    CheckRunTimeAccess();
658
659    /*
660     * Check to see if we're running on the right platform
661     */
662    CheckRunTimePlatform();
663
664    /*
665     * If a -show was specified but not -class, then
666     * default to "General".
667     */
668    if (ShowStr && !ClassNames)
669        ClassNames = "General";
670
671    /*
672     * Set class info
673     */
674    ClassSetInfo(ClassNames);
675
676    /*
677     * Set type info
678     */
679    TypeSetInfo(TypeNames);
680
681    SImsg(SIM_DBG, "Verbosity level = 0x%x\n", MsgLevel);
682
683    exit( ClassCall(ShowStr) );
684}
Note: See TracBrowser for help on using the repository browser.