android_reboot.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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/types.h>
  19. #include <sys/stat.h>
  20. #include <fcntl.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <cutils/android_reboot.h>
  24. /* Check to see if /proc/mounts contains any writeable filesystems
  25. * backed by a block device.
  26. * Return true if none found, else return false.
  27. */
  28. static int remount_ro_done(void)
  29. {
  30. FILE *f;
  31. char mount_dev[256];
  32. char mount_dir[256];
  33. char mount_type[256];
  34. char mount_opts[256];
  35. int mount_freq;
  36. int mount_passno;
  37. int match;
  38. int found_rw_fs = 0;
  39. f = fopen("/proc/mounts", "r");
  40. if (! f) {
  41. /* If we can't read /proc/mounts, just give up */
  42. return 1;
  43. }
  44. do {
  45. match = fscanf(f, "%255s %255s %255s %255s %d %d\n",
  46. mount_dev, mount_dir, mount_type,
  47. mount_opts, &mount_freq, &mount_passno);
  48. mount_dev[255] = 0;
  49. mount_dir[255] = 0;
  50. mount_type[255] = 0;
  51. mount_opts[255] = 0;
  52. if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw")) {
  53. found_rw_fs = 1;
  54. break;
  55. }
  56. } while (match != EOF);
  57. fclose(f);
  58. return !found_rw_fs;
  59. }
  60. /* Remounting filesystems read-only is difficult when there are files
  61. * opened for writing or pending deletes on the filesystem. There is
  62. * no way to force the remount with the mount(2) syscall. The magic sysrq
  63. * 'u' command does an emergency remount read-only on all writable filesystems
  64. * that have a block device (i.e. not tmpfs filesystems) by calling
  65. * emergency_remount(), which knows how to force the remount to read-only.
  66. * Unfortunately, that is asynchronous, and just schedules the work and
  67. * returns. The best way to determine if it is done is to read /proc/mounts
  68. * repeatedly until there are no more writable filesystems mounted on
  69. * block devices.
  70. */
  71. static void remount_ro(void)
  72. {
  73. int fd, cnt = 0;
  74. /* Trigger the remount of the filesystems as read-only,
  75. * which also marks them clean.
  76. */
  77. fd = open("/proc/sysrq-trigger", O_WRONLY);
  78. if (fd < 0) {
  79. return;
  80. }
  81. write(fd, "u", 1);
  82. close(fd);
  83. /* Now poll /proc/mounts till it's done */
  84. while (!remount_ro_done() && (cnt < 50)) {
  85. usleep(100000);
  86. cnt++;
  87. }
  88. return;
  89. }
  90. extern int write_misc(char *reason);
  91. int android_reboot(int cmd, int flags, char *arg)
  92. {
  93. int ret;
  94. if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
  95. sync();
  96. if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
  97. remount_ro();
  98. switch (cmd) {
  99. case ANDROID_RB_RESTART:
  100. ret = reboot(RB_AUTOBOOT);
  101. break;
  102. case ANDROID_RB_POWEROFF:
  103. ret = reboot(RB_POWER_OFF);
  104. break;
  105. case ANDROID_RB_RESTART2:
  106. //ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
  107. // LINUX_REBOOT_CMD_RESTART2, arg);
  108. write_misc(arg);
  109. ret = reboot(RB_AUTOBOOT);
  110. break;
  111. default:
  112. ret = -1;
  113. }
  114. return ret;
  115. }