4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
30 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
33 * setuname [-t] [-s name] [-n node]
37 * Header files referenced:
38 * <stdio.h> Standard I/O
39 * <unistd.h> Standard UNIX definitions
40 * <string.h> String handling
41 * <fmtmsg.h> Standard message generation
42 * <ctype.h> Character types
43 * <errno.h> Error handling
44 * <signal.h> Signal handling
45 * <sys/types.h> Data types
46 * <sys/fcntl.h> File control
47 * <sys/utsname.h> System Name
48 * <sys/sys3b.h> sys3b() definitions
49 * <nlist.h> Definitions for Sun symbol table entries
59 #include <sys/types.h>
61 #include <sys/fcntl.h>
63 #include <sys/utsname.h>
65 #if u3b || u3b15 || u3b2
66 #include <sys/sys3b.h>
75 * Externals referenced (and not defined in a header)
76 * optind index to the next arg for getopt()
77 * opterr FLAG, TRUE tells getopt() to write messages
78 * optarg Ptr to an option's argument
79 * getopt() Gets an option from the command line
80 * putenv() Writes values into the environment
81 * exit() Exit the process
82 * access() Check accessibility of a file
83 * malloc() Allocate a block of main memory
84 * free() Free allocated space
85 * lseek() Seek within a file
87 * close() Close an open file
90 extern int optind
; /* argv[] index of next arg */
91 extern int opterr
; /* TRUE if getopt() is to print msgs */
92 extern char *optarg
; /* Argument to parsed option */
93 extern int getopt(); /* Get an option from the command line */
94 extern int putenv(); /* Put a value into the environment */
95 extern void exit(); /* Exit the process */
96 extern int access(); /* Check the accessibility of a file */
97 extern void *malloc(); /* Get a chunk of main memory */
98 extern void free(); /* Free alloc'd space */
99 extern long lseek(); /* Seek within a file */
100 extern int open(); /* Open a file */
101 extern int close(); /* Close an open a file */
104 * L O C A L D E F I N I T I O N S
123 #define OPTSTRING "tn:s:"
128 #define RC_FILENAME "/etc/rc2.d/S18setuname"
129 #define RC_DIRNAME "/etc/rc2.d"
136 #define E_USAGE "usage: setuname [-t] [-s name] [-n node]"
137 #define E_MISSING "Either -s name or -n node must be specified"
138 #define E_UNAME "Unable to get existing uname values"
139 #define E_INVNAME "System-name invalid: %s"
140 #define E_LONGNAME "System-name too long: %s"
141 #define E_INVNODE "Network node-name invalid: %s"
142 #define E_LONGNODE "Network node-name too long: %s"
143 #define E_NOPERMS "No permissions, request denied"
144 #define E_NOSUCHDIR "Directory doesn't exist: %s"
145 #define E_INTERNAL "Internal error: %d"
149 * stdmsg(r,l,s,t) Write a standard message.
150 * 'r' is the recoverability flag
152 * 's' is the severity
154 * strend(p) Return the address of the end of a string
155 * (This is supposed to be defined in <sys/inline.h>
156 * but that file has string-handing def'ns that
157 * conflict with <string.h>, so we can't use it!
158 * MR dn89-04701 requests this fix.
161 #define stdmsg(r,l,s,t) (void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)
162 #define strend(p) strrchr(p,'\0')
166 * setuname Changes the system name and the network node name
169 static int setuname(); /* This does the "real" work */
174 * lbl Buffer for the standard message label
175 * txt Buffer for the standard message text
178 static char lbl
[MM_MXLABELLN
+1]; /* Space for std msg label */
179 static char msg
[MM_MXTXTLN
+1]; /* Space for std msg text */
182 * int main(argc, argv)
189 int argc
; /* Argument count */
190 char *argv
[]; /* Argument vector */
193 char *n_arg
; /* Ptr to arg for -n */
194 char *s_arg
; /* Ptr to arg for -s */
195 int t_seen
; /* FLAG, -t option seen */
196 char *cmdname
; /* Ptr to the command's name */
197 char *p
; /* Temp pointer */
198 int usageerr
; /* FLAG, TRUE if usage error */
199 int exitcode
; /* Value to exit with */
200 int c
; /* Temp character */
201 int ok
; /* Flag, everything okay? */
203 /* Build the standard-message label */
204 if (p
= strrchr(argv
[0], '/')) cmdname
= p
+1;
205 else cmdname
= argv
[0];
206 (void) strcat(strcpy(lbl
, "UX:"), cmdname
);
208 /* Make only the text in standard messages appear (SVR4.0 only) */
209 (void) putenv("MSGVERB=text");
212 /* Initializations */
213 n_arg
= s_arg
= (char *) NULL
;
223 while (!usageerr
&& (c
= getopt(argc
, argv
, OPTSTRING
)) != EOF
) switch(c
) {
225 case 'n': /* -n node */
226 if (n_arg
) usageerr
= TRUE
;
230 case 's': /* -s name */
231 if (s_arg
) usageerr
= TRUE
;
236 if (t_seen
) usageerr
= TRUE
;
240 default: /* Something that doesn't exist */
244 /* If there was a usage error, report the error and exit */
245 if ((argc
>= (optind
+1)) || usageerr
) {
246 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, E_USAGE
);
250 /* Either -n <node> or -s <name> has to be specified */
251 if (!(n_arg
|| s_arg
)) {
252 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, E_MISSING
);
258 * Validate arguments:
259 * - The length of the system name must be less than SYS_NMLN-1
261 * - The length of the network node-name must be less than
262 * SYS_NMLN-1 characters,
263 * - The system name must equal [a-zA-Z0-9-_]+,
264 * - The network node-name must equal [a-zA-Z0-9-_]+.
267 /* Check the length and the character-set of the system name */
270 /* Check length of the system name */
271 if (strlen(s_arg
) > (size_t)(SYS_NMLN
-1)) {
272 (void) sprintf(msg
, E_LONGNAME
, s_arg
);
273 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, msg
);
277 /* Check the character-set */
279 for (p
= s_arg
; ok
&& *p
; p
++) {
280 if (!isalnum(*p
) && (*p
!= '-') && (*p
!= '_')) ok
= FALSE
;
282 if (!ok
|| (p
== s_arg
)) {
283 (void) sprintf(msg
, E_INVNAME
, s_arg
);
284 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, msg
);
289 /* Check the length and the character-set of the network node-name */
293 /* Check length of the network node-name */
294 if (strlen(n_arg
) > (size_t)(SYS_NMLN
-1)) {
295 (void) sprintf(msg
, E_LONGNODE
, n_arg
);
296 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, msg
);
300 /* Check the character-set */
302 for (p
= n_arg
; ok
&& *p
; p
++) {
303 if (!isalnum(*p
) && (*p
!= '-') && (*p
!= '_')) ok
= FALSE
;
305 if (!ok
|| (p
== n_arg
)) {
306 (void) sprintf(msg
, E_INVNODE
, n_arg
);
307 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, msg
);
314 * Make sure we have access to needed resources:
315 * - Read/write access to kernel memory (/dev/kmem)
316 * - If -t is not specified, read/write access to /etc/rc2.d
317 * - If -t is not specified, read access to /etc/rc2.d/S18setuname
320 if (access("/dev/kmem", R_OK
|W_OK
) == 0) {
321 if (access(RC_DIRNAME
, R_OK
|W_OK
) == 0) {
322 if ((access(RC_FILENAME
, R_OK
) != 0) &&
323 (access(RC_FILENAME
, F_OK
) == 0)) {
324 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, E_NOPERMS
);
329 if (access(RC_DIRNAME
, F_OK
) == 0) {
330 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, E_NOPERMS
);
334 (void) sprintf(msg
, E_NOSUCHDIR
, RC_DIRNAME
);
335 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, msg
);
341 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, E_NOPERMS
);
346 /* Attempt the setuname */
347 if (setuname(t_seen
, s_arg
, n_arg
) == 0) exitcode
= EX_OK
;
349 (void) sprintf(msg
, E_INTERNAL
, errno
);
350 stdmsg(MM_NRECOV
, lbl
, MM_ERROR
, msg
);
359 * int setuname(temp, name, node)
364 * Set any or all of the following machine parameters, either
365 * temporarily or permanently, depending on <temp>.
367 * - Network Node-name
371 setuname(temp
, sysname
, nodename
)
372 int temp
; /* Set in kernel only flag */
373 char *sysname
; /* System name */
374 char *nodename
; /* Network node-name */
377 struct utsname utsname
; /* Space for the kernel's utsname information */
378 #if u3b || u3b15 || u3b2
379 struct s3bsym
*symbtbl
; /* The kernel's symbol table */
382 struct nlist nl
[] = {
383 {"utsname", 0, 0, 0, 0, 0},
388 uintptr_t utsname_addr
; /* Addr of "utsname" in the kernel */
389 char *sysnm
= (char *)NULL
; /* System name to set (from file or arg) */
390 char *nodenm
= (char *)NULL
; /* Network node-name to set (from file or arg) */
391 FILE *fd
; /* Std I/O File Descriptor for /etc/rc2.d/S18setuname */
392 char *p
; /* Temp pointer */
393 void (*oldsighup
)(); /* Function to call for SIGHUP */
394 void (*oldsigint
)(); /* Function to call for SIGINT */
395 int rtncd
; /* Value to return to the caller */
396 unsigned long symbtblsz
; /* The size of the kernel's symbol table, in bytes */
397 int memfd
; /* File descriptor: open kernel memory */
398 int i
; /* Temp counter */
401 /* Nothing's gone wrong yet (but we've only just begun!) */
406 * Get the virtual address of the symbol "utsname" in the kernel
407 * so we can get set the system name and/or the network node-name
408 * directly in the kernel's memory space.
411 #if u3b || u3b15 || u3b2
412 if ((sys3b(S3BSYM
, (struct s3bsym
*) &symbtblsz
, sizeof(symbtblsz
)) == 0) &&
413 (symbtbl
= (struct s3bsym
*) malloc(symbtblsz
))) {
415 (void) sys3b(S3BSYM
, symbtbl
, symbtblsz
);
416 p
= (char *) symbtbl
;
417 for (i
= symbtbl
->count
; i
-- && (strcmp(p
, "utsname") != 0) ; p
= S3BNXTSYM(p
)) ;
418 if (i
>= 0) utsname_addr
= S3BSVAL(p
);
420 free((void *) symbtbl
);
425 /* Check out namelist and memory files. */
426 if ((kd
= kvm_open(NULL
, NULL
, NULL
, O_RDWR
, NULL
)) == NULL
)
428 else if (kvm_nlist(kd
, nl
) != 0)
430 else if (nl
[0].n_value
== 0)
433 utsname_addr
= (uintptr_t)nl
[0].n_value
;
435 if (nlist("/unix", nl
) != 0)
438 if (rtncd
!= 0) return(rtncd
);
441 * Open the kernel's memory, get the existing "utsname" structure,
442 * change the system name and/or the network node-name in that struct,
443 * write it back out to kernel memory, then close kernel memory.
446 if (kvm_kread(kd
, utsname_addr
, &utsname
, sizeof (utsname
)) ==
449 (void) strncpy(utsname
.sysname
, sysname
,
450 sizeof (utsname
.sysname
));
452 (void) strncpy(utsname
.nodename
, nodename
,
453 sizeof (utsname
.nodename
));
454 (void) kvm_kwrite(kd
, utsname_addr
, &utsname
, sizeof (utsname
));
459 if ((memfd
= open("/dev/kmem", O_RDWR
, 0)) > 0) {
460 if ((lseek(memfd
, (long) utsname_addr
, SEEK_SET
) != -1) &&
461 (read(memfd
, &utsname
, sizeof(utsname
)) == sizeof(utsname
))) {
462 if (sysname
) (void) strncpy(utsname
.sysname
, sysname
, sizeof(utsname
.sysname
));
463 if (nodename
) (void) strncpy(utsname
.nodename
, nodename
, sizeof(utsname
.nodename
));
464 (void) lseek(memfd
, (long) utsname_addr
, SEEK_SET
);
465 (void) write(memfd
, &utsname
, sizeof(utsname
));
469 if (rtncd
!= 0) return(rtncd
);
474 * If the "temp" flag is FALSE, we need to permanently set the
475 * system name in the file /etc/rc2.d/S18setuname
480 * If a name was specified by the caller, use that, otherwise, use
481 * whatever was in the "rc" file.
484 if (sysname
) sysnm
= sysname
;
485 if (nodename
) nodenm
= nodename
;
489 * Write the file /etc/rc2.d/S18setuname so that the system name is
490 * set on boots and state changes.
492 * DISABLED SIGNALS: SIGHUP, SIGINT
495 /* Give us a reasonable chance to complete without interruptions */
496 oldsighup
= signal(SIGHUP
, SIG_IGN
);
497 oldsigint
= signal(SIGINT
, SIG_IGN
);
499 /* Write the new setuname "rc" file */
500 if (sysname
!= NULL
) {
501 if ((fd
= fopen(RC_FILENAME
, "w")) != (FILE *) NULL
) {
502 (void) fprintf(fd
, "# %s\n", sysnm
);
503 (void) fprintf(fd
, "#\n");
504 (void) fprintf(fd
, "# This script, generated by the setuname command,\n");
505 (void) fprintf(fd
, "# sets the system's system-name\n");
506 (void) fprintf(fd
, "#\n");
508 (void) fprintf(fd
, "setuname -t -s %s\n", sysnm
);
510 } else return(rtncd
= -1);
513 if(nodename
!= NULL
) {
514 char curname
[SYS_NMLN
];
518 if ((file
= fopen("/etc/nodename", "r")) != NULL
) {
519 curlen
= fread(curname
, sizeof(char), SYS_NMLN
, file
);
520 for (i
= 0; i
< curlen
; i
++) {
521 if (curname
[i
] == '\n') {
527 curname
[curlen
] = '\0';
533 if (strcmp(curname
, nodenm
) != 0) {
534 if ((file
= fopen("/etc/nodename", "w")) == NULL
) {
535 (void) fprintf(stderr
, "setuname: error in writing name\n");
538 if (fprintf(file
, "%s\n", nodenm
) < 0) {
539 (void) fprintf(stderr
, "setuname: error in writing name\n");
545 /* Restore signal handling */
546 (void) signal(SIGHUP
, oldsighup
);
547 (void) signal(SIGINT
, oldsigint
);