• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/state.c

  1 /*
  2  * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3  * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU Lesser General Public License version 2.1
  7  * as published by the Free Software Foundation
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  */
 14 
 15 #include <fcntl.h>
 16 #include <pwd.h>
 17 #include <sys/reboot.h>
 18 #include <stdio.h>
 19 #include <stdlib.h>
 20 #include <unistd.h>
 21 #include <sys/types.h>
 22 #include <signal.h>
 23 
 24 #include "container.h"
 25 #include "procd.h"
 26 #include "syslog.h"
 27 #include "plug/hotplug.h"
 28 #include "watchdog.h"
 29 #include "service/service.h"
 30 #include "utils/utils.h"
 31 
 32 enum {
 33         STATE_NONE = 0,
 34         STATE_EARLY,
 35         STATE_UBUS,
 36         STATE_INIT,
 37         STATE_RUNNING,
 38         STATE_SHUTDOWN,
 39         STATE_HALT,
 40         __STATE_MAX,
 41 };
 42 
 43 static int state = STATE_NONE;
 44 static int reboot_event;
 45 
 46 static void set_stdio(const char* tty)
 47 {
 48         if (patch_stdio(tty))
 49                 ERROR("failed to set stdio\n");
 50         else
 51                 fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK);
 52 }
 53 
 54 static void set_console(void)
 55 {
 56         const char* tty;
 57         char* split;
 58         char line[ 20 ];
 59         const char* try[] = { "tty0", "console", NULL }; /* Try the most common outputs */
 60         int f, i = 0;
 61 
 62         tty = get_cmdline_val("console",line,sizeof(line));
 63         if (tty != NULL) {
 64                 split = strchr(tty, ',');
 65                 if ( split != NULL )
 66                         *split = '\0';
 67         } else {
 68                 // Try a default
 69                 tty=try[i];
 70                 i++;
 71         }
 72 
 73         if (chdir("/dev")) {
 74                 ERROR("failed to change dir to /dev: %m\n");
 75                 return;
 76         }
 77         while (tty!=NULL) {
 78                 f = open(tty, O_RDONLY|O_NOCTTY);
 79                 if (f >= 0) {
 80                         close(f);
 81                         break;
 82                 }
 83 
 84                 tty=try[i];
 85                 i++;
 86         }
 87         if (chdir("/"))
 88                 ERROR("failed to change dir to /: %m\n");
 89 
 90         if (tty != NULL)
 91                 set_stdio(tty);
 92 }
 93 
 94 static void perform_halt()
 95 {
 96         if (reboot_event == RB_POWER_OFF)
 97                 LOG("- power down -\n");
 98         else
 99                 LOG("- reboot -\n");
100 
101         /* Allow time for last message to reach serial console, etc */
102         sleep(1);
103 
104         if (is_container()) {
105                 reboot(reboot_event);
106                 exit(EXIT_SUCCESS);
107                 return;
108         }
109 
110         /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
111          * in linux/kernel/sys.c, which can cause the machine to panic when
112          * the init process exits... */
113         if (!vfork()) { /* child */
114                 reboot(reboot_event);
115                 _exit(EXIT_SUCCESS);
116         }
117 
118         while (1)
119                 sleep(1);
120 }
121 
122 static void state_enter(void)
123 {
124         char ubus_cmd[] = "/sbin/ubusd";
125         struct passwd *p;
126 
127         switch (state) {
128         case STATE_EARLY:
129                 LOG("- early -\n");
130                 watchdog_init(0);
131                 hotplug("/etc/hotplug.json");
132                 procd_coldplug();
133                 break;
134 
135         case STATE_UBUS:
136                 // try to reopen incase the wdt was not available before coldplug
137                 watchdog_init(0);
138                 set_stdio("console");
139                 p = getpwnam("ubus");
140                 if (p) {
141                         int ret;
142                         LOG("- ubus -\n");
143                         mkdir(p->pw_dir, 0755);
144                         ret = chown(p->pw_dir, p->pw_uid, p->pw_gid);
145                         if (ret)
146                                 LOG("- ubus - failed to chown(%s)\n", p->pw_dir);
147                 } else {
148                         LOG("- ubus (running as root!) -\n");
149                 }
150 
151                 procd_connect_ubus();
152                 service_start_early("ubus", ubus_cmd, p?"ubus":NULL, p?"ubus":NULL);
153                 break;
154 
155         case STATE_INIT:
156                 LOG("- init -\n");
157                 procd_inittab();
158                 procd_inittab_run("respawn");
159                 procd_inittab_run("askconsole");
160                 procd_inittab_run("askfirst");
161                 procd_inittab_run("sysinit");
162 
163                 // switch to syslog log channel
164                 ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd");
165                 break;
166 
167         case STATE_RUNNING:
168                 LOG("- init complete -\n");
169                 procd_inittab_run("respawnlate");
170                 procd_inittab_run("askconsolelate");
171                 break;
172 
173         case STATE_SHUTDOWN:
174                 ulog_open(ULOG_KMSG, LOG_DAEMON, "procd");
175                 /* Redirect output to the console for the users' benefit */
176                 set_console();
177                 LOG("- shutdown -\n");
178                 procd_inittab_run("shutdown");
179                 sync();
180                 break;
181 
182         case STATE_HALT:
183                 // To prevent killed processes from interrupting the sleep
184                 signal(SIGCHLD, SIG_IGN);
185                 LOG("- SIGTERM processes -\n");
186                 kill(-1, SIGTERM);
187                 sync();
188                 sleep(1);
189                 LOG("- SIGKILL processes -\n");
190                 kill(-1, SIGKILL);
191                 sync();
192                 sleep(1);
193 #ifndef DISABLE_INIT
194                 perform_halt();
195 #else
196                 exit(EXIT_SUCCESS);
197 #endif
198                 break;
199 
200         default:
201                 ERROR("Unhandled state %d\n", state);
202                 return;
203         };
204 }
205 
206 void procd_state_next(void)
207 {
208         DEBUG(4, "Change state %d -> %d\n", state, state + 1);
209         state++;
210         state_enter();
211 }
212 
213 void procd_state_ubus_connect(void)
214 {
215         if (state == STATE_UBUS)
216                 procd_state_next();
217 }
218 
219 void procd_shutdown(int event)
220 {
221         if (state >= STATE_SHUTDOWN)
222                 return;
223         DEBUG(2, "Shutting down system with event %x\n", event);
224         reboot_event = event;
225         state = STATE_SHUTDOWN;
226         state_enter();
227 }
228 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt