So as part of neweoe, IRIX needed a new uname command. The old command is problematic for a variety of reasons.
Firstly -r only reports 6.5 -- not a minor version. You have to use the -R to get a more specific version, which is not POSIX compliant or inline with what Linux or BSD does.
Secondly, uname -a does not report the minor version.
Thirdly, it lacks the -X flag found on some BSDs and Solaris (and possibly linux, who knows?)
Here's my findings, and my methods for solving various challenges. Follow along with me down the rabbit hole of SGI programming.
Warning! I share CDDL (Common Development and Distribution License) code here. If you're somehow offended by the anti-GPL nature of it's operation or your employer doesn't want you to, click away now. Everything from this point is that.
Illumos-Gate version of uname:
https://raw.githubusercontent.com/illumo...me/uname.c
I'll go through my diff chunk by chunk:
Code:
% cat uname.diff
--- uname.orig Wed Dec 22 20:03:14 2021
+++ uname.c Wed Dec 22 20:03:35 2021
@@ -35,7 +35,7 @@
* contributors.
*/
-#define __EXTENSIONS__
+#include <sys/syssgi.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
Ok, this is simply the addition of an extra header. illumos (and Solaris) really share a close relationship with IRIX, so other than removing the GCC preprocessor directive and <sys/syssgi.h> (The purpose of which will be discussed soon) there's little to talk about here.
Code:
@@ -48,7 +48,7 @@
#include <sys/utsname.h>
#include <sys/systeminfo.h>
-#define OS_NAME "illumos"
+#define OS_NAME "IRIX"
static void usage(void);
Simple change. The primary OS_NAME definition is hard coded in the C file, ostensibly for portability.
Code:
@@ -57,9 +57,9 @@
main(int argc, char *argv[], char *envp[])
{
char *nodename;
- char *optstring = "asnrpvmioS:X";
+ char *optstring = "asnrpvmoS:X";
int sflg = 0, nflg = 0, rflg = 0, vflg = 0, mflg = 0;
- int pflg = 0, iflg = 0, oflg = 0, Sflg = 0;
+ int pflg = 0, oflg = 0, Sflg = 0;
int errflg = 0, optlet;
int Xflg = 0;
struct utsname unstr, *un;
The first line (optstring) is a getopt bit. I removed -i from this for reasons I'll discuss later when we get to that section.
Same with the iflg!
Code:
@@ -71,18 +71,11 @@
un = &unstr;
(void) uname(un);
- (void) setlocale(LC_ALL, "");
-#if !defined(TEXT_DOMAIN)
-#define TEXT_DOMAIN "SYS_TEST"
-#endif
- (void) textdomain(TEXT_DOMAIN);
-
while ((optlet = getopt(argc, argv, optstring)) != EOF)
switch (optlet) {
case 'a':
sflg++; nflg++; rflg++; vflg++; mflg++;
pflg++;
- iflg++;
break;
case 's':
sflg++;
Two changes here: Removed gettext() related code, and removed the now absent iflg variable from part of the getopt.
I have nothing against gettext(), or err.h (which I often change to straight fprintf or perror calls) -- but they're extra dependencies that would need to be accounted for in it. I have gettext(), but I prefer to not overuse it, and for uname gettext() is 100% overkill. err.h too, but solaris doesn't use err.h. That's a BSDism.
The other change is self-explanatory.
Code:
@@ -102,9 +95,6 @@
case 'p':
pflg++;
break;
- case 'i':
- iflg++;
- break;
case 'o':
oflg++;
break;
@@ -124,7 +114,7 @@
usage();
if ((Sflg > 1) ||
- (Sflg && (sflg || nflg || rflg || vflg || mflg || pflg || iflg ||
+ (Sflg && (sflg || nflg || rflg || vflg || mflg || pflg ||
oflg || Xflg))) {
usage();
}
Similar stuff here i'm breezing through. More iflg stuff. We're getting to juicier stuff.
Code:
@@ -134,15 +124,15 @@
int len = strlen(nodename);
if (len > SYS_NMLN - 1) {
- (void) fprintf(stderr, gettext(
- "uname: name must be <= %d letters\n"),
+ (void) fprintf(stderr,
+ "uname: name must be <= %d letters\n",
SYS_NMLN-1);
exit(1);
}
if (sysinfo(SI_SET_HOSTNAME, nodename, len) < 0) {
int err = errno;
- (void) fprintf(stderr, gettext(
- "uname: error in setting name: %s\n"),
+ (void) fprintf(stderr,
+ "uname: error in setting name: %s\n",
strerror(err));
exit(1);
}
@@ -152,7 +142,7 @@
/*
* "uname -s" is the default
*/
- if (!(sflg || nflg || rflg || vflg || mflg || pflg || iflg ||
+ if (!(sflg || nflg || rflg || vflg || mflg || pflg ||
oflg || Xflg))
sflg++;
if (sflg) {
Two more changes. The first is an example of gettext() being used typically for error messages. Removed. Another iflg reference. Whenever you delete a variable, you gotta remove all references to it or the compiler will be like "WTF MAN!"
Code:
@@ -165,7 +155,9 @@
fs = fmt_string;
}
if (rflg) {
- (void) fprintf(stdout, fs, sizeof (un->release), un->release);
+ char releasename[256];
+ syssgi(SGI_RELEASE_NAME, sizeof(releasename), releasename);
+ (void) fprintf(stdout, fs, sizeof (releasename), releasename);
fs = fmt_string;
}
if (vflg) {
Ok. So here's where we get into a lengthy C discussion. I'll try to break it down. What the first fprintf statement (the removed one) does is:
Print to standard output, use the fs format string, make the buffer the size of the part of the un struct named release, and print the contents of the un->release.
Ok, so what is un you're asking? Well it's mapped to the utsname struct in sys/utsname.h, and yes, uname is short for utsname ostensibly. I don't know what exactly is the origin of the "uts" part but it's something I see in sysv all the time. in the struct located there is a char string called release. This releases ALWAYS prints 6.5 on any 6.5 release. This is problematic -- IRIX was at 6.5 from 1998-2006 so this varies greatly on C capabilities. Scripts expect -r to print this info, so this could cause issues.
Anyways, the correct way to fix this is to use sys/syssgi.h -- it has a great many options in its functionality. So you then can retrieve it after creating a buffer (I set it arbitrarily at 256, but this could likely be reduced.) and running syssgi(), then printing its stored string.
Ok, so that fixes -r. Solaris uname includes -X, so other stuff is easy in that regard, but we're not outta the woods yet!
Code:
@@ -178,17 +170,8 @@
}
if (pflg) {
if (sysinfo(SI_ARCHITECTURE, procbuf, sizeof (procbuf)) == -1) {
- (void) fprintf(stderr, gettext(
- "uname: sysinfo failed\n"));
- exit(1);
- }
- (void) fprintf(stdout, fs, strlen(procbuf), procbuf);
- fs = fmt_string;
- }
- if (iflg) {
- if (sysinfo(SI_PLATFORM, procbuf, sizeof (procbuf)) == -1) {
- (void) fprintf(stderr, gettext(
- "uname: sysinfo failed\n"));
+ (void) fprintf(stderr,
+ "uname: sysinfo failed\n");
exit(1);
}
(void) fprintf(stdout, fs, strlen(procbuf), procbuf);
The -i command uses Solaris-specific calls and isn't even used by IRIX's uname or any other part of the POSIX specification that I can see.
These calls are really janky, so I just deleted the code for it. That's why the iflg stuff is missing! Also a stray gettext().
Code:
@@ -200,28 +183,22 @@
}
if (Xflg) {
int val;
+ char releasename[256];
+
+ syssgi(SGI_RELEASE_NAME, sizeof(releasename), releasename);
(void) fprintf(stdout, "System = %.*s\n", sizeof (un->sysname),
un->sysname);
(void) fprintf(stdout, "Node = %.*s\n", sizeof (un->nodename),
un->nodename);
- (void) fprintf(stdout, "Release = %.*s\n", sizeof (un->release),
- un->release);
+ (void) fprintf(stdout, "Release = %.*s\n", sizeof (releasename),
+ releasename);
(void) fprintf(stdout, "KernelID = %.*s\n",
sizeof (un->version), un->version);
(void) fprintf(stdout, "Machine = %.*s\n", sizeof (un->machine),
un->machine);
- /* Not availible on Solaris so hardcode the output */
- (void) fprintf(stdout, "BusType = <unknown>\n");
-
- /* Serialization is not supported in 2.6, so hard code output */
- (void) fprintf(stdout, "Serial = <unknown>\n");
- (void) fprintf(stdout, "Users = <unknown>\n");
- (void) fprintf(stdout, "OEM# = 0\n");
- (void) fprintf(stdout, "Origin# = 1\n");
-
- val = sysconf(_SC_NPROCESSORS_CONF);
+ val = sysconf(_SC_NPROC_CONF);
(void) fprintf(stdout, "NumCPU = %d\n", val);
}
(void) putchar('\n');
Ok, so here's some other stuff to look at. I was thankful that for sysconf() it's very similar between IRIX and Solaris code. Easy to update that little bit.
Everything else, well, I first deleted the hardcoded stuff that illumos itself can't even use. If anyone has any suggestions, once I get the code submitted to neweoe, you can submit a pull req or something or reply here. I did duplicate the release code including buffer, probably bad form, but I didn't get any compiler warnings. I could probably move the variables up with the others though. Thoughts guys? Was that bad form?
Code:
@@ -232,9 +209,9 @@
usage(void)
{
{
- (void) fprintf(stderr, gettext(
+ (void) fprintf(stderr,
"usage: uname [-snrvmapioX]\n"
- " uname [-S system_name]\n"));
+ " uname [-S system_name]\n");
}
exit(1);
}
gettext() code removal here. That's it, other than a minor issue (I forgot to remove the i flag from usage).
Conclusions:
I hope everyone was able to learn something. I wanna do more of these, if you guys find it helpful. I would like to go through libxg functions, neweoe commands I build from scratch or gank from elsewhere and modify.
Can someone more familiar with sysv stuff explain to me if gettxt() (no e) is similar in capabilities on IRIX? If so, it may be possible to substitute/map some calls to it? Maybe? I don't know.
I have learned an AWFUL lot about kernel and sysconf variables, and may build a, well, /special/ command for IRIX. I dunno.