ssh: Update to OpenSSH 9.4p1
[freebsd.git] / sbin / reboot / reboot.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1986, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #if 0
33 #ifndef lint
34 static const char copyright[] =
35 "@(#) Copyright (c) 1980, 1986, 1993\n\
36         The Regents of the University of California.  All rights reserved.\n";
37 #endif /* not lint */
38
39 #ifndef lint
40 static char sccsid[] = "@(#)reboot.c    8.1 (Berkeley) 6/5/93";
41 #endif /* not lint */
42 #endif
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include <sys/types.h>
47 #include <sys/boottrace.h>
48 #include <sys/reboot.h>
49 #include <sys/sysctl.h>
50 #include <sys/time.h>
51
52 #include <signal.h>
53 #include <err.h>
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <pwd.h>
57 #include <syslog.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62 #include <utmpx.h>
63
64 static void usage(void) __dead2;
65 static u_int get_pageins(void);
66
67 static int dohalt;
68
69 int
70 main(int argc, char *argv[])
71 {
72         struct utmpx utx;
73         const struct passwd *pw;
74         int ch, howto, i, fd, lflag, nflag, qflag, sverrno, Nflag;
75         u_int pageins;
76         const char *user, *kernel = NULL;
77
78         if (strstr(getprogname(), "halt") != NULL) {
79                 dohalt = 1;
80                 howto = RB_HALT;
81         } else
82                 howto = 0;
83         lflag = nflag = qflag = Nflag = 0;
84         while ((ch = getopt(argc, argv, "cdk:lNnpqr")) != -1)
85                 switch(ch) {
86                 case 'c':
87                         howto |= RB_POWERCYCLE;
88                         break;
89                 case 'd':
90                         howto |= RB_DUMP;
91                         break;
92                 case 'k':
93                         kernel = optarg;
94                         break;
95                 case 'l':
96                         lflag = 1;
97                         break;
98                 case 'n':
99                         nflag = 1;
100                         howto |= RB_NOSYNC;
101                         break;
102                 case 'N':
103                         nflag = 1;
104                         Nflag = 1;
105                         break;
106                 case 'p':
107                         howto |= RB_POWEROFF;
108                         break;
109                 case 'q':
110                         qflag = 1;
111                         break;
112                 case 'r':
113                         howto |= RB_REROOT;
114                         break;
115                 case '?':
116                 default:
117                         usage();
118                 }
119         argc -= optind;
120         argv += optind;
121         if (argc != 0)
122                 usage();
123
124         if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
125                 errx(1, "cannot dump (-d) when halting; must reboot instead");
126         if (Nflag && (howto & RB_NOSYNC) != 0)
127                 errx(1, "-N cannot be used with -n");
128         if ((howto & RB_POWEROFF) && (howto & RB_POWERCYCLE))
129                 errx(1, "-c and -p cannot be used together");
130         if ((howto & RB_REROOT) != 0 && howto != RB_REROOT)
131                 errx(1, "-r cannot be used with -c, -d, -n, or -p");
132         if (geteuid()) {
133                 errno = EPERM;
134                 err(1, NULL);
135         }
136
137         if (qflag) {
138                 reboot(howto);
139                 err(1, NULL);
140         }
141
142         if (kernel != NULL) {
143                 fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT | O_TRUNC,
144                     0444);
145                 if (fd > -1) {
146                         (void)write(fd, "nextboot_enable=\"YES\"\n", 22);
147                         (void)write(fd, "kernel=\"", 8L);
148                         (void)write(fd, kernel, strlen(kernel));
149                         (void)write(fd, "\"\n", 2);
150                         close(fd);
151                 }
152         }
153
154         /* Log the reboot. */
155         if (!lflag)  {
156                 if ((user = getlogin()) == NULL)
157                         user = (pw = getpwuid(getuid())) ?
158                             pw->pw_name : "???";
159                 if (dohalt) {
160                         openlog("halt", 0, LOG_AUTH | LOG_CONS);
161                         syslog(LOG_CRIT, "halted by %s", user);
162                 } else if (howto & RB_REROOT) {
163                         openlog("reroot", 0, LOG_AUTH | LOG_CONS);
164                         syslog(LOG_CRIT, "rerooted by %s", user);
165                 } else if (howto & RB_POWEROFF) {
166                         openlog("reboot", 0, LOG_AUTH | LOG_CONS);
167                         syslog(LOG_CRIT, "powered off by %s", user);
168                 } else if (howto & RB_POWERCYCLE) {
169                         openlog("reboot", 0, LOG_AUTH | LOG_CONS);
170                         syslog(LOG_CRIT, "power cycled by %s", user);
171                 } else {
172                         openlog("reboot", 0, LOG_AUTH | LOG_CONS);
173                         syslog(LOG_CRIT, "rebooted by %s", user);
174                 }
175         }
176         utx.ut_type = SHUTDOWN_TIME;
177         gettimeofday(&utx.ut_tv, NULL);
178         pututxline(&utx);
179
180         /*
181          * Do a sync early on, so disks start transfers while we're off
182          * killing processes.  Don't worry about writes done before the
183          * processes die, the reboot system call syncs the disks.
184          */
185         if (!nflag)
186                 sync();
187
188         /*
189          * Ignore signals that we can get as a result of killing
190          * parents, group leaders, etc.
191          */
192         (void)signal(SIGHUP,  SIG_IGN);
193         (void)signal(SIGINT,  SIG_IGN);
194         (void)signal(SIGQUIT, SIG_IGN);
195         (void)signal(SIGTERM, SIG_IGN);
196         (void)signal(SIGTSTP, SIG_IGN);
197
198         /*
199          * If we're running in a pipeline, we don't want to die
200          * after killing whatever we're writing to.
201          */
202         (void)signal(SIGPIPE, SIG_IGN);
203
204         /*
205          * Only init(8) can perform rerooting.
206          */
207         if (howto & RB_REROOT) {
208                 if (kill(1, SIGEMT) == -1)
209                         err(1, "SIGEMT init");
210
211                 return (0);
212         }
213
214         /* Just stop init -- if we fail, we'll restart it. */
215         BOOTTRACE("SIGTSTP to init(8)...");
216         if (kill(1, SIGTSTP) == -1)
217                 err(1, "SIGTSTP init");
218
219         /* Send a SIGTERM first, a chance to save the buffers. */
220         BOOTTRACE("SIGTERM to all other processes...");
221         if (kill(-1, SIGTERM) == -1 && errno != ESRCH)
222                 err(1, "SIGTERM processes");
223
224         /*
225          * After the processes receive the signal, start the rest of the
226          * buffers on their way.  Wait 5 seconds between the SIGTERM and
227          * the SIGKILL to give everybody a chance. If there is a lot of
228          * paging activity then wait longer, up to a maximum of approx
229          * 60 seconds.
230          */
231         sleep(2);
232         for (i = 0; i < 20; i++) {
233                 pageins = get_pageins();
234                 if (!nflag)
235                         sync();
236                 sleep(3);
237                 if (get_pageins() == pageins)
238                         break;
239         }
240
241         for (i = 1;; ++i) {
242                 BOOTTRACE("SIGKILL to all other processes(%d)...", i);
243                 if (kill(-1, SIGKILL) == -1) {
244                         if (errno == ESRCH)
245                                 break;
246                         goto restart;
247                 }
248                 if (i > 5) {
249                         (void)fprintf(stderr,
250                             "WARNING: some process(es) wouldn't die\n");
251                         break;
252                 }
253                 (void)sleep(2 * i);
254         }
255
256         reboot(howto);
257         /* FALLTHROUGH */
258
259 restart:
260         BOOTTRACE("SIGHUP to init(8)...");
261         sverrno = errno;
262         errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
263             strerror(sverrno));
264         /* NOTREACHED */
265 }
266
267 static void
268 usage(void)
269 {
270
271         (void)fprintf(stderr, dohalt ?
272             "usage: halt [-clNnpq] [-k kernel]\n" :
273             "usage: reboot [-cdlNnpqr] [-k kernel]\n");
274         exit(1);
275 }
276
277 static u_int
278 get_pageins(void)
279 {
280         u_int pageins;
281         size_t len;
282
283         len = sizeof(pageins);
284         if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
285             != 0) {
286                 warnx("v_swappgsin");
287                 return (0);
288         }
289         return pageins;
290 }