72 static void modesetting_track_value (
const char *path,
const char *text);
73 void modesetting_verify_values (
void);
74 static char *modesetting_strip (
char *str);
75 static char *modesetting_read_from_file (
const char *path,
size_t maxsize);
76 int modesetting_write_to_file_real (
const char *file,
int line,
const char *func,
const char *path,
const char *text);
77 bool modesetting_is_mounted (
const char *mountpoint);
78 bool modesetting_mount (
const char *mountpoint);
79 bool modesetting_unmount (
const char *mountpoint);
80 static gchar *modesetting_mountdev (
const char *mountpoint);
82 static storage_info_t *modesetting_get_storage_info (
size_t *pcount);
83 static bool modesetting_enter_mass_storage_mode (
const modedata_t *data);
84 static int modesetting_leave_mass_storage_mode (
const modedata_t *data);
85 static void modesetting_report_mass_storage_blocker(
const char *mountpoint,
int try);
86 bool modesetting_enter_dynamic_mode (
void);
87 void modesetting_leave_dynamic_mode (
void);
95 static GHashTable *tracked_values = 0;
101 static void modesetting_track_value(
const char *path,
const char *text)
103 LOG_REGISTER_CONTEXT;
105 if( !tracked_values || !path )
109 g_hash_table_replace(tracked_values, g_strdup(path), g_strdup(text));
111 g_hash_table_remove(tracked_values, path);
117 void modesetting_verify_values(
void)
119 LOG_REGISTER_CONTEXT;
124 if( !tracked_values )
127 g_hash_table_iter_init(&iter, tracked_values);
128 while( g_hash_table_iter_next(&iter, &key, &value) )
130 const char *path = key;
131 const char *text = value;
133 char *curr = modesetting_read_from_file(path, 0x1000);
135 if( g_strcmp0(text, curr) ) {
139 if( text && curr && !g_ascii_strcasecmp(text, curr) ) {
140 log_debug(
"unexpected change '%s' : '%s' -> '%s' (case diff only)", path,
145 log_warning(
"unexpected change '%s' : '%s' -> '%s'", path,
149 modesetting_track_value(path, curr);
159 static char *modesetting_strip(
char *str)
161 LOG_REGISTER_CONTEXT;
163 unsigned char *src = (
unsigned char *)str;
164 unsigned char *dst = (
unsigned char *)str;
166 while( *src > 0 && *src <= 32 ) ++src;
170 while( *src > 32 ) *dst++ = *src++;
171 while( *src > 0 && *src <= 32 ) ++src;
172 if( *src == 0 )
break;
179 static char *modesetting_read_from_file(
const char *path,
size_t maxsize)
181 LOG_REGISTER_CONTEXT;
188 if((fd = open(path, O_RDONLY)) == -1)
192 if( errno != ENOENT && errno != EACCES )
193 log_warning(
"%s: open: %m", path);
197 if( !(data = malloc(maxsize + 1)) )
200 if((done = read(fd, data, maxsize)) == -1)
202 log_warning(
"%s: read: %m", path);
206 text = realloc(data, done + 1), data = 0;
208 modesetting_strip(text);
212 if(fd != -1) close(fd);
216 int modesetting_write_to_file_real(
const char *file,
int line,
const char *func,
217 const char *path,
const char *text)
219 LOG_REGISTER_CONTEXT;
244 if( !strcmp(path, ANDROID0_FUNCTIONS) ) {
245 if( !strcmp(text,
"") || !strcmp(text,
"none") ) {
251 repr = g_strdup(text);
252 modesetting_strip(repr);
256 if( (prev = modesetting_read_from_file(path, 0x1000)) )
257 modesetting_track_value(path, clear ?
"" : repr);
259 log_debug(
"%s:%d: %s(): WRITE '%s' : '%s' --> '%s'",
261 path, prev ?:
"???", repr);
266 if( (fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY))) == -1 )
268 log_warning(
"open(%s): %m", path);
274 ssize_t n = TEMP_FAILURE_RETRY(write(fd, text, todo));
277 if( clear && errno == EINVAL )
278 log_debug(
"write(%s): %m (expected failure)", path);
280 log_warning(
"write(%s): %m", path);
291 if( fd != -1 ) TEMP_FAILURE_RETRY(close(fd));
299 bool modesetting_is_mounted(
const char *mountpoint)
301 LOG_REGISTER_CONTEXT;
304 snprintf(cmd,
sizeof cmd,
"/bin/mountpoint -q '%s'", mountpoint);
305 return common_system(cmd) == 0;
308 bool modesetting_mount(
const char *mountpoint)
310 LOG_REGISTER_CONTEXT;
313 snprintf(cmd,
sizeof cmd,
"/bin/mount '%s'", mountpoint);
314 return common_system(cmd) == 0;
317 bool modesetting_unmount(
const char *mountpoint)
319 LOG_REGISTER_CONTEXT;
322 snprintf(cmd,
sizeof cmd,
"/bin/umount '%s'", mountpoint);
323 return common_system(cmd) == 0;
326 static gchar *modesetting_mountdev(
const char *mountpoint)
328 LOG_REGISTER_CONTEXT;
334 if( !(fh = setmntent(
"/etc/fstab",
"r")) )
337 while( (me = getmntent(fh)) ) {
338 if( !strcmp(me->mnt_dir, mountpoint) ) {
339 res = g_strdup(me->mnt_fsname);
348 log_debug(
"%s -> %s", mountpoint, res);
356 LOG_REGISTER_CONTEXT;
360 g_free(info[i].si_mountpoint);
361 g_free(info[i].si_mountdevice);
368 modesetting_get_storage_info(
size_t *pcount)
370 LOG_REGISTER_CONTEXT;
379 if( !(setting = config_find_mounts()) ) {
380 log_warning(
"no mount points configuration");
385 array = g_strsplit(setting,
",", 0);
386 while( array[count] )
390 log_warning(
"no mount points configured");
397 for(
size_t i = 0; i < count; ++i ) {
398 const gchar *mountpnt = info[i].
si_mountpoint = g_strdup(array[i]);
400 if( access(mountpnt, F_OK) == -1 ) {
401 log_warning(
"mountpoint %s does not exist", mountpnt);
405 const gchar *mountdev = info[i].
si_mountdevice = modesetting_mountdev(mountpnt);
408 log_warning(
"can't find device for %s", mountpnt);
412 if( access(mountdev, F_OK) == -1 ) {
413 log_warning(
"mount device %s does not exist", mountdev);
422 modesetting_free_storage_info(info), info = 0, count = 0;
427 return *pcount = count, info;
430 static bool modesetting_enter_mass_storage_mode(
const modedata_t *data)
432 LOG_REGISTER_CONTEXT;
442 if( !(info = modesetting_get_storage_info(&count)) )
449 nofua = config_find_sync();
452 if( android_in_use()&& count > 1 ) {
453 log_warning(
"ignoring excess mountpoints");
458 for(
size_t i = 0 ; i < count; ++i )
461 for(
int tries = 0; ; ) {
463 if( !modesetting_is_mounted(mountpnt) ) {
464 log_debug(
"%s is not mounted", mountpnt);
468 if( modesetting_unmount(mountpnt) ) {
469 log_debug(
"unmounted %s", mountpnt);
474 log_err(
"failed to unmount %s - giving up", mountpnt);
475 modesetting_report_mass_storage_blocker(mountpnt, 2);
480 log_warning(
"failed to unmount %s - wait a bit", mountpnt);
481 modesetting_report_mass_storage_blocker(mountpnt, 1);
487 if( android_in_use() ) {
489 android_set_enabled(
false);
490 android_set_function(
"mass_storage");
493 android_set_enabled(
true);
495 else if( configfs_in_use() ) {
496 configfs_set_udc(
false);
497 configfs_set_function(0);
499 for(
size_t i = 0 ; i < count; ++i ) {
501 if( configfs_add_mass_storage_lun(i) ) {
502 configfs_set_mass_storage_attr(i,
"cdrom",
"0");
503 configfs_set_mass_storage_attr(i,
"nofua", nofua ?
"1" :
"0");
504 configfs_set_mass_storage_attr(i,
"removable",
"1");
505 configfs_set_mass_storage_attr(i,
"ro",
"0");
506 configfs_set_mass_storage_attr(i,
"file", mountdev);
509 configfs_set_function(
"mass_storage");
510 configfs_set_udc(
true);
512 else if( modules_in_use() ) {
516 snprintf(tmp,
sizeof tmp,
517 "/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/file",
520 if( access(tmp, R_OK) == -1 )
522 log_debug(
"%s does not exist, unloading and reloading mass_storage\n", tmp);
524 snprintf(tmp,
sizeof tmp,
"modprobe %s luns=%zd", MODULE_MASS_STORAGE, count);
525 log_debug(
"usb-load command = %s", tmp);
526 if( common_system(tmp) != 0 )
533 for(
size_t i = 0 ; i < count; ++i ) {
536 snprintf(tmp,
sizeof tmp,
"/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/nofua", i);
537 write_to_file(tmp, nofua ?
"1" :
"0");
539 snprintf(tmp,
sizeof tmp,
"/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/file", i);
540 write_to_file(tmp, mountdev);
541 log_debug(
"usb lun = %s active\n", mountdev);
545 log_err(
"no suitable backend for mass-storage mode");
554 modesetting_free_storage_info(info);
562 modesetting_leave_mass_storage_mode(data);
568 static int modesetting_leave_mass_storage_mode(
const modedata_t *data)
570 LOG_REGISTER_CONTEXT;
582 if( !(info = modesetting_get_storage_info(&count)) )
586 if( android_in_use() ) {
587 log_debug(
"Disable android mass storage\n");
588 android_set_enabled(
false);
591 else if( configfs_in_use() ) {
592 log_debug(
"Disable configfs mass storage\n");
593 configfs_set_udc(
false);
594 configfs_set_function(0);
597 for(
size_t i = 0 ; i < count; ++i ) {
599 configfs_set_mass_storage_attr(i,
"cdrom",
"0");
600 configfs_set_mass_storage_attr(i,
"nofua",
"0");
601 configfs_set_mass_storage_attr(i,
"removable",
"1");
602 configfs_set_mass_storage_attr(i,
"ro",
"0");
603 configfs_set_mass_storage_attr(i,
"file",
"");
606 configfs_remove_mass_storage_lun(i);
609 else if( modules_in_use() ) {
610 for(
size_t i = 0 ; i < count; ++i ) {
611 snprintf(tmp,
sizeof tmp,
"/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/file", i);
612 write_to_file(tmp,
"");
613 log_debug(
"usb lun = %s inactive\n", tmp);
617 log_err(
"no suitable backend for mass-storage mode");
627 alt_path = config_find_alt_mount();
629 for(
size_t i = 0 ; i < count; ++i ) {
632 if( modesetting_is_mounted(mountpnt) ) {
633 log_debug(
"%s is already mounted", mountpnt);
637 if( modesetting_mount(mountpnt) ) {
638 log_debug(
"mounted %s", mountpnt);
646 log_err(
"failed to mount %s - no alt mountpoint defined", mountpnt);
650 log_err(
"failed to mount %s - trying ro tmpfs as %s", mountpnt, alt_path);
651 snprintf(tmp,
sizeof tmp,
"mount -t tmpfs tmpfs -o ro --size=512K %s", alt_path);
656 modesetting_free_storage_info(info);
665 static void modesetting_report_mass_storage_blocker(
const char *mountpoint,
int try)
667 LOG_REGISTER_CONTEXT;
670 gchar *lsof_command = 0;
673 lsof_command = g_strconcat(
"lsof ", mountpoint, NULL);
675 if( (stream = common_popen(lsof_command,
"r")) )
680 while( getline(&text, &size, stream) >= 0 )
686 split = g_strsplit((
const gchar*)text,
" ", 2);
687 log_err(
"Mass storage blocked by process %s\n", split[0]);
696 g_free(lsof_command);
698 log_err(
"Setting Mass storage blocked. Giving up.\n");
702 bool modesetting_enter_dynamic_mode(
void)
704 LOG_REGISTER_CONTEXT;
710 log_debug(
"DYNAMIC MODE: SETUP");
717 log_debug(
"No dynamic mode data to setup");
721 log_debug(
"data->mode_name = %s", data->
mode_name);
722 log_debug(
"data->mass_storage = %d", data->
mass_storage);
724 log_debug(
"data->connman_tethering = %s", data->connman_tethering ?:
"n/a");
726 log_debug(
"data->appsync = %d", data->
appsync);
727 log_debug(
"data->network = %d", data->
network);
729 log_debug(
"data->idProduct = %s", data->
idProduct ?:
"n/a");
731 log_debug(
"data->nat = %d", data->
nat);
732 log_debug(
"data->dhcp_server = %d", data->
dhcp_server);
739 log_debug(
"Dynamic mode is mass storage");
740 ack = modesetting_enter_mass_storage_mode(data);
750 log_debug(
"Dynamic mode is appsync: do pre actions");
752 log_debug(
"Appsync failure");
762 if( configfs_in_use() ) {
766 char *
id = config_get_android_vendor_id();
769 if( !configfs_set_udc(
true) )
772 else if( android_in_use() ) {
776 char *
id = config_get_android_vendor_id();
781 if( !android_set_enabled(
true) )
784 else if( modules_in_use() ) {
791 log_crit(
"no backend is selected, can't set dynamic mode");
802 log_debug(
"Dynamic mode is network");
807 common_system(command);
813 for(
int i = 0; error && i < 3; ++i ) {
814 log_warning(
"Retry setting up the network");
815 if( !common_msleep(1000) )
818 log_warning(
"Setting up the network succeeded");
821 log_err(
"Setting up the network failed");
845 log_debug(
"Dynamic mode is appsync: do post actions");
856 if( data->connman_tethering ) {
857 log_debug(
"Dynamic mode is tethering");
858 if( !connman_set_tethering(data->connman_tethering,
true) )
871 void modesetting_leave_dynamic_mode(
void)
873 LOG_REGISTER_CONTEXT;
875 log_debug(
"DYNAMIC MODE: CLEANUP");
883 log_debug(
"No dynamic mode data to cleanup");
887 log_debug(
"data->mass_storage = %d", data->
mass_storage);
889 log_debug(
"data->connman_tethering = %s", data->connman_tethering ?:
"n/a");
891 log_debug(
"data->appsync = %d", data->
appsync);
892 log_debug(
"data->network = %d", data->
network);
899 log_debug(
"Dynamic mode is mass storage");
900 modesetting_leave_mass_storage_mode(data);
909 if( data->connman_tethering ) {
910 log_debug(
"Dynamic mode was tethering");
911 connman_set_tethering(data->connman_tethering,
false);
920 log_debug(
"Dynamic mode was appsync: undo post actions");
930 log_debug(
"Dynamic mode was network");
938 if( configfs_in_use() ) {
943 else if( android_in_use() ) {
948 else if( modules_in_use() ) {
952 log_crit(
"no backend is selected, can't unset dynamic mode");
961 log_debug(
"Dynamic mode was appsync: undo all actions");
975 LOG_REGISTER_CONTEXT;
977 if( !tracked_values ) {
978 tracked_values = g_hash_table_new_full(g_str_hash, g_str_equal,
987 LOG_REGISTER_CONTEXT;
989 if( tracked_values ) {
990 g_hash_table_unref(tracked_values), tracked_values = 0;