GoogleGit

blob: 6ae23c1f00f59b92c1b1a03a30ee4f597d444373 [file] [log] [blame]
  1. /*
  2. * Copyright 2011, The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <unistd.h>
  17. #include <sys/reboot.h>
  18. #include <sys/syscall.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <fcntl.h>
  22. #include <mntent.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <cutils/android_reboot.h>
  26. #define UNUSED __attribute__((unused))
  27. /* Check to see if /proc/mounts contains any writeable filesystems
  28. * backed by a block device.
  29. * Return true if none found, else return false.
  30. */
  31. static int remount_ro_done(void)
  32. {
  33. FILE* fp;
  34. struct mntent* mentry;
  35. int found_rw_fs = 0;
  36. if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
  37. /* If we can't read /proc/mounts, just give up. */
  38. return 1;
  39. }
  40. while ((mentry = getmntent(fp)) != NULL) {
  41. if (!strncmp(mentry->mnt_fsname, "/dev/block", 10) && strstr(mentry->mnt_opts, "rw,")) {
  42. found_rw_fs = 1;
  43. break;
  44. }
  45. }
  46. endmntent(fp);
  47. return !found_rw_fs;
  48. }
  49. /* Remounting filesystems read-only is difficult when there are files
  50. * opened for writing or pending deletes on the filesystem. There is
  51. * no way to force the remount with the mount(2) syscall. The magic sysrq
  52. * 'u' command does an emergency remount read-only on all writable filesystems
  53. * that have a block device (i.e. not tmpfs filesystems) by calling
  54. * emergency_remount(), which knows how to force the remount to read-only.
  55. * Unfortunately, that is asynchronous, and just schedules the work and
  56. * returns. The best way to determine if it is done is to read /proc/mounts
  57. * repeatedly until there are no more writable filesystems mounted on
  58. * block devices.
  59. */
  60. static void remount_ro(void)
  61. {
  62. int fd, cnt = 0;
  63. /* Trigger the remount of the filesystems as read-only,
  64. * which also marks them clean.
  65. */
  66. fd = open("/proc/sysrq-trigger", O_WRONLY);
  67. if (fd < 0) {
  68. return;
  69. }
  70. write(fd, "u", 1);
  71. close(fd);
  72. /* Now poll /proc/mounts till it's done */
  73. while (!remount_ro_done() && (cnt < 50)) {
  74. usleep(100000);
  75. cnt++;
  76. }
  77. return;
  78. }
  79. int android_reboot(int cmd, int flags UNUSED, const char *arg)
  80. {
  81. int ret;
  82. sync();
  83. remount_ro();
  84. switch (cmd) {
  85. case ANDROID_RB_RESTART:
  86. ret = reboot(RB_AUTOBOOT);
  87. break;
  88. case ANDROID_RB_POWEROFF:
  89. ret = reboot(RB_POWER_OFF);
  90. break;
  91. case ANDROID_RB_RESTART2:
  92. ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
  93. LINUX_REBOOT_CMD_RESTART2, arg);
  94. break;
  95. default:
  96. ret = -1;
  97. }
  98. return ret;
  99. }