PageRenderTime 28ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/src/modes.c

https://gitlab.com/theinspire.eu/inspireSRV
C | 473 lines | 391 code | 73 blank | 9 comment | 106 complexity | cd7aab9d28b614dbea89d4e6225189e1 MD5 | raw file
  1. /*inspireSRV Serivce Manager.*/
  2. /**This file holds functions for the various things we can do, depending on argv[0].
  3. * Most are to be called by main() at some point or another.**/
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include <unistd.h>
  9. #include <signal.h>
  10. #include <ctype.h>
  11. #include <dirent.h>
  12. #include <fcntl.h>
  13. #include "inspireSRV.h"
  14. /*To shut up some weird compilers. I don't know what this thing wants from me.*/
  15. pid_t getsid(pid_t);
  16. ReturnCode SendPowerControl(const char *MembusCode)
  17. { /*Client side to send a request to halt/reboot/power off/disable or enable CAD/etc.*/
  18. char InitsResponse[MEMBUS_MSGSIZE], *PCode[2], *PErrMsg;
  19. if (!strcmp(MembusCode, MEMBUS_CODE_HALT))
  20. {
  21. PCode[0] = MEMBUS_CODE_ACKNOWLEDGED " " MEMBUS_CODE_HALT;
  22. PCode[1] = MEMBUS_CODE_FAILURE " " MEMBUS_CODE_HALT;
  23. PErrMsg = "Unable to halt.";
  24. }
  25. else if (!strcmp(MembusCode, MEMBUS_CODE_POWEROFF))
  26. {
  27. PCode[0] = MEMBUS_CODE_ACKNOWLEDGED " " MEMBUS_CODE_POWEROFF;
  28. PCode[1] = MEMBUS_CODE_FAILURE " " MEMBUS_CODE_POWEROFF;
  29. PErrMsg = "Unable to power off.";
  30. }
  31. else if (!strcmp(MembusCode, MEMBUS_CODE_REBOOT))
  32. {
  33. PCode[0] = MEMBUS_CODE_ACKNOWLEDGED " " MEMBUS_CODE_REBOOT;
  34. PCode[1] = MEMBUS_CODE_FAILURE " " MEMBUS_CODE_REBOOT;
  35. PErrMsg = "Unable to reboot.";
  36. }
  37. else if (!strcmp(MembusCode, MEMBUS_CODE_CADON))
  38. {
  39. PCode[0] = MEMBUS_CODE_ACKNOWLEDGED " " MEMBUS_CODE_CADON;
  40. PCode[1] = MEMBUS_CODE_FAILURE " " MEMBUS_CODE_CADON;
  41. PErrMsg = "Unable to enable CTRL-ALT-DEL instant reboot.";
  42. }
  43. else if (!strcmp(MembusCode, MEMBUS_CODE_CADOFF))
  44. {
  45. PCode[0] = MEMBUS_CODE_ACKNOWLEDGED " " MEMBUS_CODE_CADOFF;
  46. PCode[1] = MEMBUS_CODE_FAILURE " " MEMBUS_CODE_CADOFF;
  47. PErrMsg = "Unable to disable CTRL-ALT-DEL instant reboot.";
  48. }
  49. else
  50. {
  51. SpitError("Invalid MEMBUS_CODE passed to SendPowerControl().");
  52. return FAILURE;
  53. }
  54. if (!MemBus_Write(MembusCode, false))
  55. {
  56. SpitError("Failed to write to membus.");
  57. return FAILURE;
  58. }
  59. while (!MemBus_Read(InitsResponse, false)) usleep(1000); /*0.001 secs.*/
  60. MemBus_Write(MembusCode, false); /*Tells init it can shut down the membus.*/
  61. if (!strcmp(InitsResponse, PCode[0]))
  62. {
  63. ShutdownMemBus(false);
  64. return SUCCESS;
  65. }
  66. else if (!strcmp(InitsResponse, PCode[1]))
  67. { /*Nothing uses this right now.*/
  68. SpitError(PErrMsg);
  69. ShutdownMemBus(false);
  70. return FAILURE;
  71. }
  72. return SUCCESS;
  73. }
  74. ReturnCode ObjControl(const char *ObjectID, const char *MemBusSignal)
  75. { /*Start and stop or disable services.*/
  76. char RemoteResponse[MEMBUS_MSGSIZE];
  77. char OutMsg[MEMBUS_MSGSIZE];
  78. char PossibleResponses[4][MEMBUS_MSGSIZE];
  79. snprintf(OutMsg, sizeof OutMsg, "%s %s", MemBusSignal, ObjectID);
  80. if (!MemBus_Write(OutMsg, false))
  81. {
  82. return FAILURE;
  83. }
  84. while (!MemBus_Read(RemoteResponse, false)) usleep(1000); /*0.001 secs*/
  85. snprintf(PossibleResponses[0], sizeof PossibleResponses[0], "%s %s %s",
  86. MEMBUS_CODE_ACKNOWLEDGED, MemBusSignal, ObjectID);
  87. snprintf(PossibleResponses[1], sizeof PossibleResponses[1], "%s %s %s",
  88. MEMBUS_CODE_FAILURE, MemBusSignal, ObjectID);
  89. snprintf(PossibleResponses[2], sizeof PossibleResponses[2], "%s %s",
  90. MEMBUS_CODE_BADPARAM, OutMsg);
  91. snprintf(PossibleResponses[3], sizeof PossibleResponses[3], "%s %s %s",
  92. MEMBUS_CODE_WARNING, MemBusSignal, ObjectID);
  93. if (!strcmp(RemoteResponse, PossibleResponses[0]))
  94. {
  95. return SUCCESS;
  96. }
  97. else if (!strcmp(RemoteResponse, PossibleResponses[1]))
  98. {
  99. return FAILURE;
  100. }
  101. else if (!strcmp(RemoteResponse, PossibleResponses[3]))
  102. {
  103. return WARNING;
  104. }
  105. else if (!strcmp(RemoteResponse, PossibleResponses[2]))
  106. {
  107. SpitError("\nWe are being told that we sent a bad parameter.");
  108. return FAILURE;
  109. }
  110. else
  111. {
  112. SpitError("\nReceived invalid reply from membus.");
  113. return FAILURE;
  114. }
  115. }
  116. ReturnCode EmulKillall5(unsigned InSignal)
  117. { /*Used as the killall5 utility.*/
  118. DIR *ProcDir;
  119. struct dirent *CurDir;
  120. pid_t CurPID;
  121. const pid_t OurPID = getpid(), OurSID = getsid(0);
  122. if (InSignal > SIGSTOP || InSignal == 0) /*Won't be negative since we are unsigned.*/
  123. {
  124. SpitError("EmulKillall5() Bad value for unsigned InSignal.");
  125. }
  126. /*We get everything from /proc.*/
  127. if (!(ProcDir = opendir("/proc/")))
  128. {
  129. return FAILURE;
  130. }
  131. /*Stop everything.*/
  132. kill(-1, SIGSTOP);
  133. while ((CurDir = readdir(ProcDir)))
  134. {
  135. if (AllNumeric(CurDir->d_name) && CurDir->d_type == 4)
  136. {
  137. CurPID = atol(CurDir->d_name); /*Convert the new PID to a true number.*/
  138. if (CurPID == 1 || CurPID == OurPID)
  139. { /*Don't try to kill init, or us.*/
  140. continue;
  141. }
  142. if (getsid(CurPID) == OurSID)
  143. { /*It's in our session ID, so don't touch it.*/
  144. continue;
  145. }
  146. /*We made it this far, must be safe to nuke this process.*/
  147. kill(CurPID, InSignal); /*Actually send the kill, stop, whatever signal.*/
  148. }
  149. }
  150. closedir(ProcDir);
  151. /*Start it up again.*/
  152. kill(-1, SIGCONT);
  153. return SUCCESS;
  154. }
  155. void EmulWall(const char *InStream, Bool ShowUser)
  156. { /*We not only use this as a CLI applet, we use it to notify of impending shutdown too.*/
  157. char OutBuf[8192];
  158. char HMS[3][16];
  159. char MDY[3][16];
  160. const char *OurUser = getenv("USER");
  161. char OurHostname[512] = { '\0' };
  162. DIR *DevDir;
  163. DIR *PtsDir;
  164. struct dirent *DirPtr;
  165. char FileNameBuf[MAX_LINE_SIZE];
  166. int FileDescriptor = 0;
  167. if (getuid() != 0)
  168. { /*Not root?*/
  169. SpitWarning("You are not root. Only sending to ttys you have privileges on.");
  170. }
  171. GetCurrentTime(HMS[0], HMS[1], HMS[2], MDY[0], MDY[1], MDY[2]);
  172. snprintf(OutBuf, 64, "\007\n%s[%s:%s:%s | %s-%s-%s]%s ", CONSOLE_COLOR_RED, HMS[0], HMS[1], HMS[2],
  173. MDY[0], MDY[1], MDY[2], CONSOLE_ENDCOLOR);
  174. if (ShowUser)
  175. {
  176. int HostnameLen = 0;
  177. if (gethostname(OurHostname, sizeof OurHostname / 2) != 0)
  178. {
  179. strncpy(OurHostname, "(unknown)", sizeof "(unknown)");
  180. }
  181. HostnameLen = strlen(OurHostname);
  182. if (getdomainname(OurHostname + HostnameLen + 1, sizeof OurHostname / 2 - 1) == 0 &&
  183. strcmp(OurHostname + HostnameLen + 1, "(none)") != 0 &&
  184. strcmp(OurHostname + HostnameLen + 1, "") != 0)
  185. { /*If we DO have a domain name, set it.*/
  186. OurHostname[HostnameLen] = '.';
  187. }
  188. /*I really enjoy pulling stuff off like the line below.*/
  189. snprintf(&OutBuf[strlen(OutBuf)], sizeof OutBuf - strlen(OutBuf), "Broadcast message from %s@%s: ",
  190. (OurUser != NULL ? OurUser : "(unknown)"), OurHostname);
  191. }
  192. else
  193. {
  194. snprintf(&OutBuf[strlen(OutBuf)], sizeof OutBuf - strlen(OutBuf), "%s", "Broadcast message: ");
  195. }
  196. snprintf(&OutBuf[strlen(OutBuf)], sizeof OutBuf - strlen(OutBuf), "\n%s\n\n", InStream);
  197. if ((DevDir = opendir("/dev/")))
  198. { /*Now write to the ttys.*/
  199. while ((DirPtr = readdir(DevDir))) /*See, we use fopen() as a way to check if the file exists.*/
  200. { /*Your eyes bleeding yet?*/
  201. if (!strncmp(DirPtr->d_name, "tty", sizeof "tty" - 1) &&
  202. strlen(DirPtr->d_name) > sizeof "tty" - 1 &&
  203. isdigit(DirPtr->d_name[sizeof "tty" - 1]) &&
  204. atoi(DirPtr->d_name + sizeof "tty" - 1) > 0)
  205. {
  206. snprintf(FileNameBuf, MAX_LINE_SIZE, "/dev/%s", DirPtr->d_name);
  207. if ((FileDescriptor = open(FileNameBuf, O_WRONLY | O_NONBLOCK)) == -1)
  208. { /*Screw it, we don't care.*/
  209. continue;
  210. }
  211. write(FileDescriptor, OutBuf, strlen(OutBuf));
  212. close(FileDescriptor); FileDescriptor = 0;
  213. }
  214. }
  215. closedir(DevDir);
  216. }
  217. if ((PtsDir = opendir("/dev/pts/")))
  218. {
  219. while ((DirPtr = readdir(PtsDir)))
  220. {
  221. if (isdigit(DirPtr->d_name[0]))
  222. {
  223. snprintf(FileNameBuf, MAX_LINE_SIZE, "/dev/pts/%s", DirPtr->d_name);
  224. if ((FileDescriptor = open(FileNameBuf, O_WRONLY | O_NONBLOCK)) == -1)
  225. {
  226. continue;
  227. }
  228. write(FileDescriptor, OutBuf, strlen(OutBuf));
  229. close(FileDescriptor); FileDescriptor = 0;
  230. }
  231. }
  232. closedir(PtsDir);
  233. }
  234. }
  235. ReturnCode EmulShutdown(int ArgumentCount, const char **ArgStream)
  236. { /*Eyesore, but it works.*/
  237. const char **TPtr = ArgStream + 1; /*Skip past the equivalent of argv[0].*/
  238. unsigned TargetHr = 0, TargetMin = 0;
  239. const char *THalt = NULL;
  240. char PossibleResponses[3][MEMBUS_MSGSIZE];
  241. char TmpBuf[MEMBUS_MSGSIZE], InRecv[MEMBUS_MSGSIZE], TimeFormat[32];
  242. short Inc = 0;
  243. short TimeIsSet = 0, HaltModeSet = 0;
  244. Bool AbortingShutdown = false, ImmediateHalt = false;
  245. for (; Inc != (ArgumentCount - 1); ++TPtr, ++Inc)
  246. {
  247. if (!strcmp(*TPtr, "-h") || !strcmp(*TPtr, "--halt") || !strcmp(*TPtr, "-H"))
  248. {
  249. THalt = MEMBUS_CODE_HALT;
  250. ++HaltModeSet;
  251. continue;
  252. }
  253. else if (!strcmp(*TPtr, "-R") || !strcmp(*TPtr, "-r") || !strcmp(*TPtr, "--reboot"))
  254. {
  255. THalt = MEMBUS_CODE_REBOOT;
  256. ++HaltModeSet;
  257. continue;
  258. }
  259. else if (!strcmp(*TPtr, "-p") || !strcmp(*TPtr, "-P") || !strcmp(*TPtr, "--poweroff"))
  260. {
  261. THalt = MEMBUS_CODE_POWEROFF;
  262. ++HaltModeSet;
  263. continue;
  264. }
  265. else if (!strcmp(*TPtr, "-c") || !strcmp(*TPtr, "--cancel"))
  266. {
  267. AbortingShutdown = true;
  268. snprintf(TmpBuf, sizeof TmpBuf, "%s", MEMBUS_CODE_ABORTHALT);
  269. break;
  270. }
  271. else if (strchr(*TPtr, ':') && **TPtr != '-')
  272. {
  273. struct _HaltParams TempParams;
  274. if (sscanf(*TPtr, "%u:%u", &TargetHr, &TargetMin) != 2)
  275. {
  276. puts("Bad time format. Please enter in the format of \"hh:mm\"");
  277. return FAILURE;
  278. }
  279. DateDiff(TargetHr, TargetMin, &TempParams.TargetMonth, &TempParams.TargetDay, &TempParams.TargetYear);
  280. snprintf(TimeFormat, sizeof TimeFormat, "%u:%u:%d %u/%u/%u",
  281. TargetHr, TargetMin, 0, TempParams.TargetMonth, TempParams.TargetDay, TempParams.TargetYear);
  282. ++TimeIsSet;
  283. }
  284. else if (**TPtr == '+' && AllNumeric(*TPtr + 1))
  285. {
  286. struct _HaltParams TempParams;
  287. const char *TArg = *TPtr + 1; /*Targ manure!*/
  288. time_t TTime;
  289. struct tm TimeStruct;
  290. MinsToDate(atoi(TArg), &TempParams.TargetHour, &TempParams.TargetMin, &TempParams.TargetMonth,
  291. &TempParams.TargetDay, &TempParams.TargetYear);
  292. time(&TTime); /*Get this for the second.*/
  293. localtime_r(&TTime, &TimeStruct);
  294. snprintf(TimeFormat, sizeof TimeFormat, "%u:%u:%d %u/%u/%u",
  295. TempParams.TargetHour, TempParams.TargetMin, (int)TimeStruct.tm_sec, TempParams.TargetMonth,
  296. TempParams.TargetDay, TempParams.TargetYear);
  297. ++TimeIsSet;
  298. }
  299. else if (!strcmp(*TPtr, "now"))
  300. {
  301. ImmediateHalt = true;
  302. ++TimeIsSet;
  303. }
  304. else if (!strcmp(*TPtr, "--help"))
  305. {
  306. const char *HelpMsg =
  307. "Usage: shutdown -hrpc [12:00/+10/now] -c\n\n"
  308. "-h -H --halt: Halt the system, don't power down.\n"
  309. "-p -P --poweroff: Power down the system.\n"
  310. "-r -R --reboot: Reboot the system.\n"
  311. "-c --cancel: Cancel a pending shutdown.\n\n"
  312. "Specify time in hh:mm, +m, or \"now\".\n";
  313. puts(HelpMsg);
  314. return SUCCESS;
  315. }
  316. else
  317. {
  318. fprintf(stderr, "Invalid argument %s. See --help for usage.\n", *TPtr);
  319. return FAILURE;
  320. }
  321. }
  322. if (!AbortingShutdown)
  323. {
  324. if (HaltModeSet == 0)
  325. {
  326. fprintf(stderr, "%s\n", "You must specify one of -hrp.");
  327. return FAILURE;
  328. }
  329. if (HaltModeSet > 1)
  330. {
  331. fprintf(stderr, "%s\n", "Please specify only ONE of -hrp.");
  332. return FAILURE;
  333. }
  334. if (!TimeIsSet)
  335. {
  336. fprintf(stderr, "%s\n", "You must specify a time in the format of hh:mm: or +m.");
  337. return FAILURE;
  338. }
  339. if (TimeIsSet > 1)
  340. {
  341. fprintf(stderr, "%s\n", "Multiple time arguments specified. Please specify only one.");
  342. return FAILURE;
  343. }
  344. if (!ImmediateHalt)
  345. {
  346. snprintf(TmpBuf, sizeof TmpBuf, "%s %s", THalt, TimeFormat);
  347. }
  348. }
  349. if (ImmediateHalt)
  350. {
  351. snprintf(TmpBuf, sizeof TmpBuf, "%s", THalt);
  352. }
  353. snprintf(PossibleResponses[0], MEMBUS_MSGSIZE, "%s %s", MEMBUS_CODE_ACKNOWLEDGED, TmpBuf);
  354. snprintf(PossibleResponses[1], MEMBUS_MSGSIZE, "%s %s", MEMBUS_CODE_FAILURE, TmpBuf);
  355. snprintf(PossibleResponses[2], MEMBUS_MSGSIZE, "%s %s", MEMBUS_CODE_BADPARAM, TmpBuf);
  356. if (!InitMemBus(false))
  357. {
  358. SpitError("Failed to connect to membus.");
  359. return FAILURE;
  360. }
  361. if (!MemBus_Write(TmpBuf, false))
  362. {
  363. SpitError("Failed to write to membus.");
  364. ShutdownMemBus(false);
  365. return FAILURE;
  366. }
  367. while (!MemBus_Read(InRecv, false)) usleep(1000); /*Wait for a response.*/
  368. if (ImmediateHalt) MemBus_Write(" ", false); /*Tells init it can shut down the membus.*/
  369. if (!ShutdownMemBus(false))
  370. {
  371. SpitError("Failed to shut down membus! This could spell serious issues.");
  372. }
  373. if (!strcmp(InRecv, PossibleResponses[0]))
  374. {
  375. return SUCCESS;
  376. }
  377. else if (!strcmp(InRecv, PossibleResponses[1]))
  378. {
  379. if (!strcmp(TmpBuf, MEMBUS_CODE_ABORTHALT))
  380. {
  381. fprintf(stderr, "%s\n", "Failed to abort shutdown. Is a shutdown scheduled?");
  382. }
  383. else
  384. {
  385. fprintf(stderr, "%s\n", "Failed to schedule shutdown.\nIs another already scheduled? Use shutdown -c to cancel it.");
  386. }
  387. return FAILURE;
  388. }
  389. else if (!strcmp(InRecv, PossibleResponses[2]))
  390. {
  391. SpitError("We are being told that we sent a bad parameter over the membus!"
  392. "Please report this to inspireSRV, as it's likely a bug.");
  393. return FAILURE;
  394. }
  395. else
  396. {
  397. SpitError("Invalid response received from membus! Please report this to inspireSRV, as it's likely a bug.");
  398. return FAILURE;
  399. }
  400. }