1 /*
2  * Copyright (c) 2024 Meta
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <unistd.h>
8 
9 #include "posix_shell.h"
10 
11 #include <zephyr/posix/sys/utsname.h>
12 #include <zephyr/shell/shell.h>
13 
14 #define UNAME_KERNEL   BIT(0)
15 #define UNAME_NODE     BIT(1)
16 #define UNAME_RELEASE  BIT(2)
17 #define UNAME_VERSION  BIT(3)
18 #define UNAME_MACHINE  BIT(4)
19 #define UNAME_PLATFORM BIT(5)
20 #define UNAME_UNKNOWN  BIT(6)
21 #define UNAME_ALL                                                                                  \
22 	(UNAME_KERNEL | UNAME_NODE | UNAME_RELEASE | UNAME_VERSION | UNAME_MACHINE | UNAME_PLATFORM)
23 
24 #define HELP_USAGE                                                                                 \
25 	"Usage: uname [OPTION]\n"                                                                  \
26 	"Print system information\n"                                                               \
27 	"\n"                                                                                       \
28 	"    -a,  all informationn\n"                                                              \
29 	"    -s,  kernel name\n"                                                                   \
30 	"    -o,  operating system\n"                                                              \
31 	"    -n,  network node hostname\n"                                                         \
32 	"    -r,  kernel release\n"                                                                \
33 	"    -v,  kernel version\n"                                                                \
34 	"    -m,  machine hardware name\n"                                                         \
35 	"    -p,  processor type\n"                                                                \
36 	"    -i,  hardware platform\n"
37 
uname_print_usage(const struct shell * sh)38 static void uname_print_usage(const struct shell *sh)
39 {
40 	shell_print(sh, HELP_USAGE);
41 }
42 
uname_cmd_handler(const struct shell * sh,size_t argc,char ** argv)43 static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv)
44 {
45 	struct getopt_state *state = getopt_state_get();
46 	struct utsname info;
47 	unsigned int set;
48 	int option;
49 	char badarg = 0;
50 	int ret;
51 
52 	set = 0;
53 
54 	/* Get the uname options */
55 
56 	optind = 1;
57 	while ((option = getopt(argc, argv, "asonrvmpi")) != -1) {
58 		switch (option) {
59 		case 'a':
60 			set = UNAME_ALL;
61 			break;
62 
63 		case 'o':
64 		case 's':
65 			set |= UNAME_KERNEL;
66 			break;
67 
68 		case 'n':
69 			set |= UNAME_NODE;
70 			break;
71 
72 		case 'r':
73 			set |= UNAME_RELEASE;
74 			break;
75 
76 		case 'v':
77 			set |= UNAME_VERSION;
78 			break;
79 
80 		case 'm':
81 			set |= UNAME_MACHINE;
82 			break;
83 
84 		case 'p':
85 			if (set != UNAME_ALL) {
86 				set |= UNAME_UNKNOWN;
87 			}
88 			break;
89 
90 		case 'i':
91 			set |= UNAME_PLATFORM;
92 			break;
93 
94 		case '?':
95 		default:
96 			badarg = (char)state->optopt;
97 			break;
98 		}
99 	}
100 
101 	if (argc != optind) {
102 		shell_error(sh, "uname: extra operand %s", argv[optind]);
103 		uname_print_usage(sh);
104 		return -1;
105 	}
106 
107 	/* If a bad argument was encountered, then return without processing the
108 	 * command
109 	 */
110 
111 	if (badarg != 0) {
112 		shell_error(sh, "uname: illegal option -- %c", badarg);
113 		uname_print_usage(sh);
114 		return -1;
115 	}
116 
117 	/* If nothing is provided on the command line, the default is -s */
118 
119 	if (set == 0) {
120 		set = UNAME_KERNEL;
121 	}
122 
123 	/* Get uname data */
124 
125 	ret = uname(&info);
126 	if (ret < 0) {
127 		shell_error(sh, "cannot get system name");
128 		return -1;
129 	}
130 
131 	/* Process each option */
132 
133 	/* print the kernel/operating system name */
134 	if (set & UNAME_KERNEL) {
135 		shell_fprintf(sh, SHELL_NORMAL, "%s ", info.sysname);
136 	}
137 
138 	/* Print nodename */
139 	if (set & UNAME_NODE) {
140 		shell_fprintf(sh, SHELL_NORMAL, "%s ", info.nodename);
141 	}
142 
143 	/* Print the kernel release */
144 	if (set & UNAME_RELEASE) {
145 		shell_fprintf(sh, SHELL_NORMAL, "%s ", info.release);
146 	}
147 
148 	/* Print the kernel version */
149 	if (set & UNAME_VERSION) {
150 		shell_fprintf(sh, SHELL_NORMAL, "%s ", info.version);
151 	}
152 
153 	/* Print the machine hardware name */
154 	if (set & UNAME_MACHINE) {
155 		shell_fprintf(sh, SHELL_NORMAL, "%s ", info.machine);
156 	}
157 
158 	/* Print the machine platform name */
159 	if (set & UNAME_PLATFORM) {
160 		shell_fprintf(sh, SHELL_NORMAL, "%s ", CONFIG_BOARD);
161 	}
162 
163 	/* Print "unknown" */
164 	if (set & UNAME_UNKNOWN) {
165 		shell_fprintf(sh, SHELL_NORMAL, "%s ", "unknown");
166 	}
167 
168 	shell_fprintf(sh, SHELL_NORMAL, "\n");
169 
170 	return 0;
171 }
172 
173 POSIX_CMD_ADD(uname, NULL, "Print system information", uname_cmd_handler, 1, 1);
174