1/* check share_info in all partitions and update smb.conf and reload smbd.
2 *
3 *  Copyright (C) 2008 - 2009, Delta Networks, Inc.
4 *
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <errno.h>
11#include <string.h>
12#include <sys/time.h>
13#include <time.h>
14#include <signal.h>
15#include <ctype.h>
16
17/*
18  * The 'USB_Functionality_specification_v0.2.doc' is modified too much, so I don't want to
19  * touch the original code .... :)
20  */
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/statfs.h>
24#include <unistd.h>
25#include <mntent.h>
26#include <linux/magic.h>
27
28#include "list.h"
29
30#define PARTITION_CAPACITY_VIA_DF
31
32#ifdef PARTITION_CAPACITY_VIA_DF
33#include <libgen.h>
34#endif
35
36#if 0
37#define USB_DEBUGP(format, args...) printf(format, ## args)
38#else
39#define USB_DEBUGP(format, args...)
40#endif
41
42struct disk_partition_info
43{
44	struct list_head list;
45
46	int mounted;
47	char label;	/* `U` ~ ... */
48	char name[15]; /* `sda1` `sda2` */
49	char vendor[128];  /*device name :SigmaTel MSCN*/
50	char vol_name[64]; /* Volume Name */
51	char device_id[128]; /* serialNum_partitionNum */
52
53	unsigned long long capacity; /* capacity size in MB */
54};
55
56struct share_info
57{
58	struct list_head list;
59
60	char name[];
61};
62
63#define USB_SESSION		"[USB Storage]"
64#define USB_INFO_FILE	".NETGEAR_disk_share_info"
65#define USB_SMB_CONF	"/etc/samba/smb.conf"
66#define USB_SMB_NAME	"NETGEAR R7800"
67#define TMP_SAMBA_LOCK  "/tmp/tmp_samba_lock"
68#define SHARE_FILE_INFO "shared_usb_folder"
69#define SHARE_AUTH_INFO "shared_usb_folder_users"
70#define APPROVED_DISK	"USB_approved_device"
71#define READYCLOUD_ACCESS "readycloud_access"
72#define READYCLOUD_ENABLE "readycloud_enable"
73
74#define USER_ADMIN "admin"
75#define USER_GUEST "guest"
76#define USER_ANONYMOUS "anonymous"
77#define USER_EVERYONE "everyone"
78#ifdef USB_CONFIG_ADD
79#define USER_ALL "all-no password"
80#endif
81#define USB_PATH_SIZE	4096
82#define USB_STORAGE_KEYWORD "/dev/sd"
83
84extern char *config_get(char* name);
85extern void config_set(char *name, char *value);
86extern int config_match(char *name, char *match);
87
88char SATA_DEV_NAME[32];
89char SATA_DEV_SERIAL_NO[128];
90
91char SD_CARD_DEV_NAME[32];
92
93static void reload_services(void)
94{
95	int ret;
96	int has_usb_storage = 0;
97	struct mntent *ent;
98	struct statfs stat;
99	FILE *fp = setmntent("/proc/mounts", "r");
100	while ((ent = getmntent(fp))) {
101		if (strncmp(ent->mnt_fsname, USB_STORAGE_KEYWORD, strlen(USB_STORAGE_KEYWORD)))
102			continue;
103
104		bzero(&stat, sizeof(struct statfs));
105		if (-1 == statfs(ent->mnt_dir, &stat)) {
106			continue;
107		}
108		has_usb_storage = 1;
109		break;
110	}
111	endmntent(fp);
112
113	if (!has_usb_storage) {
114		system("/usr/bin/killall smbd > /dev/null 2>&1");
115		system("/usr/bin/killall nmbd > /dev/null 2>&1");
116		system("/sbin/cmdftp stop");
117		goto outer;
118	}
119
120 	/* directly return, when disable the usb network for samba access */
121	if (config_match("usb_enableNet", "1"))
122		goto outer;
123
124	/* Sync with locking file, and wait 1s to not miss SIGUP for `smbd` */
125	sleep(1);
126	ret = system("/bin/pidof smbd > /dev/zero 2>&1");
127	if (ret == 0)
128		system("/usr/bin/killall -SIGHUP smbd");
129	else
130		system("/bin/nice -n 19 /usr/sbin/smbd -D");
131
132	/* NETBIOS Name */
133	system("/usr/bin/killall nmbd > /dev/null 2>&1");
134	//ret = system("/bin/pidof nmbd > /dev/zero 2>&1");
135	//if (ret != 0)
136	system("/usr/sbin/nmbd -D");
137
138outer:
139	/* Tell 'uhttpd' to update HTTP share information */
140	//system("/usr/bin/killall -SIGUSR1 uhttpd");
141	return;
142}
143
144static void add_smbd_global(FILE *fp)
145{
146	char *p;
147
148	/* Readycloud app need to listen to LeafNets */
149	//fprintf(fp, "[global]\n"
150	//		"  interfaces=lo br0 LeafNets\n");
151
152	p = config_get("usb_workGroup");
153	if (*p == '\0')
154		p = "Workgroup";
155	fprintf(fp, "  workgroup = %s\n", p);
156
157	p = config_get("Readyshare_name");
158	if (*p == '\0')
159		p = config_get("usb_deviceName");
160	fprintf(fp, "  netbios name = %s\n", p);
161
162	fprintf(fp, "  bind interfaces only = yes\n"
163			"  server string = " USB_SMB_NAME "\n"
164			"  security = user\n"
165			"  host msdfs = no\n"	/* Fix [BUG 12866] */
166			"  hostname lookups = no\n"
167			"  load printers = no\n"
168			"  printing = bsd\n"
169			"  printcap name = /dev/null\n"
170			"  disable spoolss = yes\n"
171 			"  guest account=guest\n"
172			"  encrypt passwords = yes\n"
173			"  name resolve order = lmhosts hosts bcast\n"
174			"  smb passwd file = /etc/samba/smbpasswd\n"
175			"  display charset = UTF-8\n"
176			"  unix charset = UTF-8\n"
177			"  dos charset = UTF-8\n"
178		        "  map to guest = bad user\n"
179
180
181			"  domain master = yes\n"
182        		"  local master = yes\n"
183        		"  preferred master = yes\n"
184        		"  os level = 0\n"
185        		"  encrypt passwords = yes\n"
186        		"  passdb backend = smbpasswd\n"
187        		"  use client driver = yes\n"
188        		"  use sendfile = yes\n"
189        		"  panic action = /bin/sleep 90000\n"
190     			"  max connections = 50\n"
191      			"  dns proxy = no\n"
192      			"  max log size = 1000\n"
193      			"  max xmit = 131072\n"
194			"  server signing = disabled\n"
195			"  follow symlinks = no\n"
196			"  wide links = no\n"
197			"  socket options = IPTOS_LOWDELAY TCP_NODELAY\n"
198			"\n");
199}
200
201static inline char *user_name(char *code)
202{
203	if (*code == '1')
204		return USER_ADMIN;
205#ifdef USB_CONFIG_ADD
206	else if (*code == '2')
207		return USER_ALL;
208#endif
209	else
210		return USER_GUEST;
211}
212
213char * get_user_name(int num)
214{
215	char *p, *username, name[32];
216
217	sprintf(name, "sharename%d", num);
218	username = config_get(name);
219	if(*username == '\0'){
220		return username;
221	}
222	p = username;
223	while(*p != ' ')
224		p++;
225	*p = '\0';
226	return username;
227}
228
229/*
230shared_usb_folder_users0=0*0*0*0
231expend user 0: undefine
232	    1: defined but has not right in the folder
233	    2; defined and has read right in the folder
234	    3; defined and has read and write right in the folder
235 */
236static void add_smbd_share_info(FILE *fp, char *displayname, char *reader, char *writer, char *path, int share_floder_num)
237{
238	/* The max length of the name of 4 user is 60, 4*60=240, use 256 bytes of string */
239	char writelist[256] = {0}, readlist[256] = {0}, invalidlist[256] = {0};
240	char shared_auth_info[8], show_disk_name[8], name[32];
241	int i = 0;
242	char accessmode;
243
244	char name_enable[64],name_access[64],name_user[64];
245	char readycloud_enable_info[512] = {0},readycloud_access_info[512] = {0},readycloud_user_value[512] = {0};
246	char *preadycloud_user, *pread_access, *pwrite_access, *pr, *pw;
247
248	strncpy(show_disk_name, displayname, 7);
249	show_disk_name[7] = '\0';
250	if (!strncmp(show_disk_name, "SD_Card",7))
251		fprintf(fp, "[%s]\n"
252			"  path=%s\n"
253			"  browsable=yes\n",
254			displayname, path);
255	else
256		fprintf(fp, "[%s]\n"
257			"  path=%s\n"
258			"  browsable=yes\n"
259			"  strict allocate=yes\n",
260			displayname, path);
261
262
263	/*judgement readycloud_enable_info*/
264	sprintf(name_enable, READYCLOUD_ENABLE);
265	strncpy(readycloud_enable_info, config_get(name_enable), sizeof(readycloud_enable_info));
266
267	sprintf(name_access, READYCLOUD_ACCESS"%d", share_floder_num);
268	strncpy(readycloud_access_info, config_get(name_access), sizeof(readycloud_access_info));
269
270	if((strcmp(readycloud_enable_info,"1") != 0) || (readycloud_access_info[0] == '\0')){
271		sprintf(name, SHARE_AUTH_INFO"%d", share_floder_num);
272		strncpy(shared_auth_info, config_get(name), sizeof(shared_auth_info));
273
274		for (i = 0; i <= 3; ++i) {
275			accessmode = shared_auth_info[i*2];
276			if (accessmode == '3')
277				sprintf(writelist + strlen(writelist), "%s ", get_user_name(i+1));
278			else if (accessmode == '2')
279				sprintf(readlist + strlen(readlist), "%s ", get_user_name(i+1));
280			else
281				sprintf(invalidlist + strlen(invalidlist), "%s ", get_user_name(i+1));
282		}
283
284
285	        if (strcmp(reader, USER_GUEST))
286			fprintf(fp, "  invalid users=%s %s\n", USER_GUEST, invalidlist);
287
288		if (!strcmp(config_get("usb_passwdNet"), "1")) {
289			fprintf(fp, "  guest ok=no\n");
290			fprintf(fp, "  read only=yes\n");
291			fprintf(fp, "  write list=%s %s\n", USER_ADMIN, writelist);
292		}
293		else if (strcmp(writer, USER_GUEST) == 0){
294			fprintf(fp, "  guest ok=yes\n");
295			fprintf(fp, "  read only=no\n");
296		}
297		else {
298			fprintf(fp, "  guest ok=no\n");
299			fprintf(fp, "  read only=yes\n");
300			fprintf(fp, "  write list=%s %s\n", USER_ADMIN, writelist);
301		}
302	}
303	else{
304		pread_access=strtok(readycloud_access_info, ":");
305		pwrite_access=strtok(NULL, ":");
306
307		for(i=0; i<=9; i++){
308			sprintf(name_user, "readycloud_user%d", i);
309			preadycloud_user = config_get(name_user);
310
311			if (*preadycloud_user == '\0')
312			{
313				break;
314			}
315			sprintf(readycloud_user_value+strlen(readycloud_user_value), "%s ", strtok(preadycloud_user, " "));
316		}
317
318		if(strstr(pread_access, USER_ANONYMOUS)){
319			fprintf(fp, "  guest ok=yes\n");
320		}
321		else if(strstr(pread_access, USER_EVERYONE)){
322			sprintf(readlist + strlen(readlist), "%s ", readycloud_user_value);
323			fprintf(fp, "  guest ok=no\n");
324			//fprintf(fp, "  invalid users=%s %s\n", USER_ANONYMOUS, invalidlist);
325			fprintf(fp, "  invalid users=%s\n", USER_GUEST);
326		}
327		else {
328			pr = strtok(pread_access, ",");
329			while(1){
330				if(pr == NULL)
331					break;
332				if(NULL != strstr(readycloud_user_value, pr)){
333					sprintf(readlist + strlen(readlist), "%s   ", pr);
334				}
335				pr = strtok(NULL, ",");
336			}
337			fprintf(fp, "  guest ok=no\n");
338			//fprintf(fp, "  invalid users=%s %s\n", USER_ANONYMOUS, invalidlist);
339			fprintf(fp, "  invalid users=%s\n", USER_GUEST);
340		}
341
342		if (!strcmp(config_get("usb_passwdNet"), "1")) {
343			sprintf(writelist + strlen(writelist), "%s ", readycloud_user_value);
344			fprintf(fp, "  read only=yes\n");
345			fprintf(fp, "  write list=%s %s\n", USER_ADMIN, writelist);
346		}
347		else if(strstr(pwrite_access, USER_ANONYMOUS)){
348			fprintf(fp, "  read only=no\n");
349		}
350		else if(strstr(pwrite_access, USER_EVERYONE)){
351			sprintf(writelist + strlen(writelist), "%s ", readycloud_user_value);
352			fprintf(fp, "  read only=yes\n");
353			fprintf(fp, "  write list=%s %s\n", USER_ADMIN, writelist);
354		}
355		else{
356			pw = strtok(pwrite_access, ",");
357			while(1){
358				if(pw == NULL)
359					break;
360				if(NULL != strstr(readycloud_user_value, pw)){
361					sprintf(writelist + strlen(writelist), "%s ", pw);
362				}
363				pw = strtok(NULL, ",");
364			}
365			fprintf(fp, "  read only=yes\n");
366			fprintf(fp, "  write list=%s %s\n", USER_ADMIN, writelist);
367		}
368
369	}
370
371	return;
372}
373
374int is_sda(char * dev)
375{
376	int count = 0;
377	FILE *fp;
378	char part_name[16], line[128];
379	int major, minors;
380	unsigned long long capacity;
381
382	fp = fopen("/proc/partitions", "r");
383	if (fp == NULL)
384		goto ret;
385
386	/*
387	 *           * major minor  #blocks  name
388	 *           *
389	 *           *  31     0        320 mtdblock0
390	 *           * ....
391	 *           *   8     0    3968000 sda
392	 *           *   8     1    3963968 sda1
393	 *
394	 */
395
396	while (fgets(line, sizeof(line), fp)) {
397		if (sscanf(line, " %d %d %llu %[^\n ]",
398					&major, &minors, &capacity, part_name) != 4)
399			continue;
400		if (strncmp(part_name, dev, 3))
401			continue;
402		else
403			count++;
404	}
405
406ret:
407	if (fp != NULL)
408		fclose(fp);
409
410	return ((count == 1)?1:0);
411}
412static char *get_device_vendor(char *dev)
413{
414	int i,j;
415	FILE *fp;
416	char line[100];
417	static char vendor[128];
418	char path[64], *ven_mod[] = {"vendor", "model"};
419
420	vendor[0] = '\0';
421
422	for(i=0; i<2; i++){
423		snprintf(path, sizeof(path), "/sys/block/%s/device/%s", dev, ven_mod[i]);
424		if(!(fp = fopen(path, "r")))
425			continue;
426		fgets(line, sizeof(line), fp);
427		fclose(fp);
428
429		j = 0;
430		while (line[j] != '\0' && line[j] != '\r' && line[j] != '\n')
431			j++;
432		line[j] = '\0';
433
434		strcat(vendor, line);
435		strcat(vendor, " ");
436	}
437	j = 127;
438	while(vendor[j] == '\t' || vendor[j] == ' ' || vendor[j] == '\0')
439		j--;
440	vendor[j + 1] = '\0';
441
442        return vendor;
443}
444
445/*
446  * When presenting the Capacity of a device, the appropriate units should be used.
447  * If a device is 1GB in size this should be displayed as 1GB, however a 300MB device
448  * should be displayed as 300MB and not 0.3GB. (29.66GB, 44.53GB).
449  */
450static void format_capacity(char *buf, int buflen, unsigned long long megabytes)
451{
452	if (megabytes >= 1024) {
453		unsigned long long left = ((megabytes & 0x3FF) * 100) >> 10; // (leftMB / 1024) * 100
454		if (left == 0)
455			snprintf(buf, buflen, "%llu GB", (megabytes >> 10));
456		else
457			snprintf(buf, buflen, "%llu.%02llu GB", (megabytes >> 10), left);
458	} else {
459		snprintf(buf, buflen, "%llu MB", megabytes);
460	}
461}
462
463static char * get_usb_serial_num(char *part_name)
464{
465	static char serial_num[128];
466	char disk_name[8], path[64], line[128], cmd[256];
467	char *bus_num = NULL;;
468	char *p;
469	int j = 0;
470	FILE *fp;
471
472	serial_num[0] = '\0';
473
474	snprintf(disk_name, 8, "%s", part_name);
475	disk_name[3] = '\0';
476	sprintf(cmd, "/bin/ls /sys/block/%s/device/scsi_device/ > /tmp/%s_info_tmp", disk_name, disk_name);
477	system(cmd);
478
479	sprintf(path, "/tmp/%s_info_tmp", disk_name);
480	fp= fopen(path, "r");
481	if (fp == NULL)
482		goto ret;
483	while (fgets(line, sizeof(line), fp)) {
484		line[15] = '\0';
485		char *tok = ":\n";
486		bus_num = strtok(line, tok);
487		fclose(fp);
488	}
489
490	if(bus_num != NULL){
491		snprintf(path, 64, "/proc/scsi/usb-storage/%s", bus_num);
492		fp= fopen(path, "r");
493		if (fp == NULL)
494			goto ret;
495
496		while (fgets(line, sizeof(line), fp)) {
497			if(strncmp(line, "Serial Number:", 14) == 0){
498				while (line[j] != '\r' && line[j] != '\n')
499					j++;
500				line[j] = '\0';
501
502				/* delete the space/tab at the end of the Serial Number */
503				p = line + 14;
504				while (*p != '\0')
505					++p;
506				--p;
507				while (*p == ' ' || *p == '\t')
508					--p;
509				*(p + 1) = '\0';
510				/* skip the space/tab at the head of the Serial Number */
511				p = line + 14;
512				while (*p == ' ' || *p == '\t')
513					p++;
514				strcpy(serial_num, p);
515			}
516		}
517	}
518
519ret:
520	if (fp != NULL)
521		fclose(fp);
522	return serial_num;
523}
524
525/* use filesystem uuid instead serial num of sd card */
526static char * get_sd_card_serial_num(char *part_name)
527{
528#define SD_CARD_UUID_FILE "/tmp/sd_card_uuid"
529	static char uuid[128];
530	char cmd[64], buf[128];
531	int i = 0;
532	FILE *fp;
533        buf[0] = '\0';
534
535     	snprintf(cmd, sizeof(cmd), "/usr/sbin/vol_id -u /dev/%s > "SD_CARD_UUID_FILE, part_name);
536       	system(cmd);
537	if(!(fp = fopen(SD_CARD_UUID_FILE, "r")))
538               	return get_usb_serial_num(part_name);
539
540      	fgets(buf, sizeof(buf), fp);
541      	fclose(fp);
542
543      	while (buf[i] != '\0' && buf[i] != '\r' && buf[i] != '\n')
544              	i++;
545      	buf[i] = '\0';
546	if (i == 0)
547		return get_usb_serial_num(part_name);
548	strncpy(uuid, buf, sizeof(uuid));
549
550	return uuid;
551}
552
553static char * get_sata_serial_num(void)
554{
555	return SATA_DEV_SERIAL_NO;
556}
557
558static void get_device_id(struct disk_partition_info *disk)
559{
560	char *id;
561	id = disk->device_id;
562	if(strncmp(disk->name, SATA_DEV_NAME, 3) == 0)
563		snprintf(id, sizeof(disk->device_id), "%s*%s", get_sata_serial_num(), disk->name + 3);
564	else if(strncmp(disk->name, SD_CARD_DEV_NAME, 3) == 0)
565		snprintf(id, sizeof(disk->device_id), "%s*%s", get_sd_card_serial_num(disk->name), disk->name + 3);
566	else
567		if ( atoi(disk->name + 3) > 0 ){
568			snprintf(id, sizeof(disk->device_id), "%s*%s", get_usb_serial_num(disk->name), disk->name + 3);
569		} else {
570//			fprintf(stderr, "[get_device_id]: Disk %s without device id, so we'll set it to 0!\n", disk->name + 3);
571//			snprintf(id, sizeof(disk->device_id), "%s*0", get_usb_serial_num(disk->name));
572			/* After use GUI to modify sharefolder information, the partition name set to the last letter,
573			 * So follow net-cgi.
574			 */
575			printf("[get_device_id]: set the last latter as a partition name!\n");
576			snprintf(id, sizeof(disk->device_id), "%s*%s", get_usb_serial_num(disk->name), disk->name + 2);
577		}
578
579}
580
581static void  get_disk_volume(struct disk_partition_info *disk, char *part_name)
582{
583//#define VOLUME_ID_FILE "/tmp/vol_id"
584/* FIX Bug 28761 - [USB]sometimes some drives appear as "Not Shared"
585   cause:
586       Module net-cgi and samba-script will read and write the
587       same file, sometimes it will cause conflict.
588   solution:
589       Use two tmp file to avoid the conflict.
590        Module net-cgi use "vol_id"
591        Module samba-script use "vol_id_1"
592*/
593#define VOLUME_ID_FILE "/tmp/vol_id_1"
594
595	int i;
596	FILE *fp;
597	char *buf, disknum[4], diskname[4], capacity[32], cmd[256];
598        buf = disk->vol_name;
599        buf[0] = '\0';
600
601	snprintf(cmd, sizeof(cmd), "/usr/sbin/vol_id -L /dev/%s > " VOLUME_ID_FILE, part_name);
602       	system(cmd);
603	if(!(fp = fopen(VOLUME_ID_FILE, "r"))){
604		printf("[get_disk_volume vol_id] open file vol_id_1 error!!\n");
605		fclose(fp);
606               	goto ret;
607	}
608       	fgets(buf, sizeof(disk->vol_name), fp);
609       	fclose(fp);
610
611       	i = 0;
612       	while (buf[i] != '\0' && buf[i] != '\r' && buf[i] != '\n')
613               	i++;
614       	buf[i] = '\0';
615
616	if (buf[0] == '\0'){
617		//printf("[smb: get_disk_volume vol_id] Get info by vol_id failed!!\n");
618		memset(cmd,0,sizeof(cmd));
619		strncpy(diskname, part_name, 3);
620		diskname[3] = '\0';
621		disknum[0] = part_name[3];
622		disknum[1] = '\0';
623		snprintf(cmd, sizeof(cmd), "/bin/echo $\(/usr/sbin/parted -s /dev/%s print | grep \"Number\" -A16 | sed -n '2,16p' | sed -n %dp | awk 'NF>=6{for(n=6;n<=NF;n++)printf $n\" \";print \"\"}') > "  VOLUME_ID_FILE, diskname, atoi(disknum));
624		system(cmd);
625		if(!(fp = fopen(VOLUME_ID_FILE, "r"))){
626			printf("[get_disk_volume parted] open file vol_id_1 error!!\n");
627			fclose(fp);
628			goto ret;
629		}
630		fgets(buf, sizeof(disk->vol_name), fp);
631		fclose(fp);
632
633		i = 0;
634		while (buf[i] != '\0' && buf[i] != '\r' && buf[i] != '\n')
635			i++;
636		buf[i] = '\0';
637	}
638
639ret:
640        /*
641 *           * If Volume Name is empty, then use <USB Device Letter> Drive (<Capacity>)
642 *                     * e.g U Drive (512MB)
643 *                               */
644
645        format_capacity(capacity, sizeof(capacity), disk->capacity);
646        if (buf[0] == '\0'){
647		printf("[vol_id_1]get_disk_volume error, goto ret!!!\n");
648		if(strncmp(part_name, SATA_DEV_NAME, 3) == 0) {
649                	snprintf(buf, sizeof(disk->vol_name), "%c External_Disk(%s)", disk->label, capacity);
650	        }else if(strncmp(part_name, SD_CARD_DEV_NAME, 3) == 0){
651                	snprintf(buf, sizeof(disk->vol_name), "%c Sd_Card (%s)", disk->label, capacity);
652		}else{
653                	snprintf(buf, sizeof(disk->vol_name), "%c Drive (%s)", disk->label, capacity);
654		}
655	}
656
657
658}
659
660static void turn_usb_led(int on)
661{
662	char cmdled[128];
663
664	snprintf(cmdled, sizeof(cmdled), "/sbin/ledcontrol -n usb -c green -s %s",
665			on ? "on" : "off");
666	system(cmdled);
667
668	/*
669	  * To avoid USB blinking may lead to LED be turned off by accident when usb storage module
670	  * toggles usb led, run a a process "usbled" to set "/proc/usbled/state" periodically.
671	  *
672	  * Firstly, try to kill this process; then if the LED is turned on, re-start it to keep the LED *on*
673	  * status.
674	  */
675	//system("/usr/bin/killall usbled > /dev/null 2>&1");
676	//if (on)
677	//	system("/usr/sbin/usbled");
678}
679
680static int is_loop_partition(char *dev)
681{
682#define DISK_LOOP_PARTITION "/tmp/disk_loop_partition"
683       int  ret = 0;
684       int  i = 0;
685       char diskname[4], cmd[128], buf[256];
686       FILE *fp;
687
688       memset(cmd,0,128);
689       memset(buf,0,256);
690
691       strncpy(diskname, dev, 3);
692       diskname[3] = '\0';
693       snprintf(cmd, sizeof(cmd), "/usr/sbin/parted -s /dev/%s print | grep \"Partition Table\" | awk '{print $3}' > " DISK_LOOP_PARTITION, diskname);
694       system(cmd);
695       if (!(fp = fopen(DISK_LOOP_PARTITION, "r"))) {
696               fclose(fp);
697               return 0;
698       }
699       fgets(buf, sizeof(buf), fp);
700       fclose(fp);
701
702       i = 0;
703       while (buf[i] != '\0' && buf[i] != '\r' && buf[i] != '\n')
704               i++;
705       buf[i] = '\0';
706
707       if ( !strcmp(buf,"loop") ){
708               fprintf(stderr, "[is_loop_partition]: Disk %s is a loop partition!\n", dev);
709               ret = 1;
710       }
711
712       return ret;
713}
714
715static int is_noshare_partition(char *dev)
716{
717	FILE *fp;
718	char diskname[4], cmd[128], result[8];
719
720	if (strlen(dev) != 4)
721		return 0;
722
723	strncpy(diskname, dev, 3);
724	diskname[3] = '\0';
725
726	snprintf(cmd, sizeof(cmd), "/usr/sbin/parted -s /dev/%s print noshare | grep %s", diskname, dev);
727	fp = popen(cmd, "r");
728	if (!fp) {
729		perror("popen");
730		return 0;
731	}
732
733	memset(result, 0, sizeof(result));
734	fgets(result, sizeof(result), fp);
735
736	pclose(fp);
737
738	return strlen(result) >= 4 ? 1 : 0;
739}
740
741static void scan_disk_entries(struct list_head *head)
742{
743	FILE *fp;
744	struct statfs statbuf;
745	int i = 0, j = 0, k = 0,major,minors;
746	int have_usb_mouted = 0;
747	unsigned long long capacity;
748	char mnt_path[32],*vendor = NULL;
749	char *s, part_name[128], line[256];
750	struct disk_partition_info *partinfo;
751
752#ifdef PARTITION_CAPACITY_VIA_DF
753	char *dfout = "/tmp/df_out";
754	char path_name[100] = {0};
755	unsigned long long cap;
756	FILE *dfp;
757	system("df > /tmp/df_out");
758#endif
759
760	fp = fopen("/proc/partitions","r");
761	if (fp == NULL )
762		return;
763
764	/*
765	  * major minor  #blocks  name
766	  *
767	  *  31     0        320 mtdblock0
768	  * ....
769	  *   8     0    3968000 sda
770	  *   8     1    3963968 sda1
771	  */
772	while (fgets(line,sizeof(line),fp)) {
773		if (sscanf(line, " %d %d %llu %[^\n ]",
774				&major, &minors, &capacity, part_name) != 4)
775			continue;
776		if (strncmp(part_name, "sd", 2))
777			continue;
778#ifdef PARTITION_CAPACITY_VIA_DF
779		/**
780		 * *** Fix bug 27693
781		 * For a 3TB USB storage (WD My Book Essential):
782		 * output of command `cat /proc/partition` like as
783		 *	major minor  #blocks  name
784		 *	   8     0  782749696 sda
785		 *	   8     1  782748672 sda1
786		 * output of command `df` like as:
787		 *	Filesystem           1k-blocks      Used Available Use% Mounted on
788		 *	/dev/mtdblock8            5568      5568         0 100% /
789		 *	/dev/sda1            2930232316    155288 2930077028   0% /tmp/mnt/sda1
790		 *
791		 * Some storage use 4096-bytes sectors, but not the old standerd with 512-bytes sectors.
792		 * We can get block count of partition from file "/proc/partition", but size of the block
793		 * is not const, like as WD My Book Essential is 4096 bytes.
794		 * Command `df` will display partition's block count as 1Kbytes size.
795		 */
796		if ((dfp = fopen(dfout, "r")) != NULL) {
797			while (fgets(line, sizeof(line), dfp)) {
798				if (sscanf(line, "%s %llu %*llu %*llu %*s %*s", path_name, &cap) != 2)
799					continue;
800
801				if (strcmp(part_name, basename(path_name)) == 0)
802					capacity = cap;
803			}
804			fclose(dfp);
805		}
806#endif
807
808		for (s = part_name; *s; s++)
809			;
810		if (!isdigit(s[-1])){
811			vendor = get_device_vendor(part_name);
812
813			if(!is_sda(part_name))
814				continue;
815		}
816
817		if (!is_loop_partition(part_name))
818		{
819			if (is_noshare_partition(part_name))
820				continue;
821		}
822
823		capacity >>= 10;        /* unit: 1KB .. >> 1   size /512 (long *arg) */
824		if (capacity == 0)
825			continue; /*It indicates that this partition should be an extended partition. */
826
827		partinfo = malloc(sizeof(struct disk_partition_info));
828		if (partinfo == NULL)
829			continue;
830		/* SEE: hotplug2.mount ==> mount /dev/$1 /mnt/$1 */
831		snprintf(mnt_path, sizeof(mnt_path), "/mnt/%s", part_name);
832		/* NO Disk, the mount point directory is NOT removed, this magic value is `0x858458F6` */
833		if (statfs(mnt_path, &statbuf) == 0 && (unsigned int)statbuf.f_type != 0x858458F6 && (unsigned int)statbuf.f_type != TMPFS_MAGIC) {
834			partinfo->mounted = 1;
835			if(strncmp(part_name, SATA_DEV_NAME, 3) != 0 && strncmp(part_name, SD_CARD_DEV_NAME, 3) != 0)
836				 have_usb_mouted = 1;
837		}
838		else
839			partinfo->mounted = 0;
840		partinfo->capacity = capacity;
841		if(strncmp(part_name, SATA_DEV_NAME, 3) == 0){
842			partinfo->label = 's' - j;
843			j++;
844		}else if(strncmp(part_name, SD_CARD_DEV_NAME, 3) == 0){
845			partinfo->label = '0' + k;
846			k++;
847		}else{
848			partinfo->label = 'U' - i;
849			i++;
850		}
851		snprintf(partinfo->name, sizeof(partinfo->name),"%s", part_name);
852		if(vendor)
853			strcpy(partinfo->vendor,vendor);
854
855		get_device_id(partinfo);
856		get_disk_volume(partinfo, part_name);
857
858		list_add_tail(&partinfo->list, head);
859
860		USB_DEBUGP("[USB-SMB]: Found partition %s, mounted %s!!!\n", part_name,
861					partinfo->mounted ? "Yes" : "No");
862	}
863
864	fclose(fp);
865#ifdef PARTITION_CAPACITY_VIA_DF
866	remove(dfout);
867#endif
868	USB_DEBUGP("[USB-SMB]: Total %d partitions are FOUND!\n", i);
869
870/*
871 	if (have_usb_mouted)
872 		turn_usb_led(1);
873 	else
874 		turn_usb_led(0);
875*/
876}
877
878static inline int duplicate_share_name(char *name, struct list_head *head)
879{
880	struct list_head *pos;
881	struct share_info *share;
882
883	list_for_each(pos, head) {
884		share = list_entry(pos, struct share_info, list);
885		if (strcmp(share->name, name) == 0)
886			return 1;
887	}
888
889	return 0;
890}
891
892static inline void add_share_info_list(char *name, struct list_head *head)
893{
894	struct share_info *share;
895
896	share = malloc(sizeof(struct share_info) + strlen(name) + 1);
897	if (share == NULL)
898		return;
899	strcpy(share->name, name);
900	list_add_tail(&share->list, head);
901}
902
903static int count_star(char *share_file_info)
904{
905	char *p;
906	int count = 0;
907
908	p = share_file_info;
909	while(*p != '\0'){
910		if(*p == '*')
911			count++;
912		p++;
913	}
914	return count;
915}
916
917static int check_approved_disk(struct disk_partition_info *diskinfo)
918{
919	int i = 0, len = 0;
920	char *p;
921	char approved_info[32], value[512], device_id[128];
922
923        if(config_match("usb_enableUSB", "0"))
924		return 0;
925
926	strncpy(device_id, diskinfo->device_id, 128);
927	for( ; device_id[i] != '*'; i++);
928	device_id[i] = '\0';
929
930	i = 1;
931        for (; ; i++) {
932                sprintf(approved_info, "%s%d", APPROVED_DISK, i);
933                len = sprintf(value, "%s", config_get(approved_info));
934                if (len < 1)
935                        break;
936		p = value + len;
937		for( ; *p != '*'; p--);
938		p++;
939
940		if (strcmp(device_id, p) == 0)
941			return 0;
942	}
943	return 1;
944}
945
946static void load_share_info(FILE *fp, char *diskname)
947{
948	/* FILE *infofp;
949	struct stat statbuf;
950	int usb_session;*/	/* `USB_SESSION` in share information file is found.  */
951	int no_shareinfo = 1; /* If `diskname` is not NULL, check if there is no share info in disk */
952	/* char *shsep = "*\n";
953	char infopath[128], buf[USB_PATH_SIZE * 2];
954	*/
955
956	struct share_info *shareinfo;
957	struct disk_partition_info *diskinfo;
958	struct list_head disk_lists, share_lists, *pos, *nxt;
959
960	INIT_LIST_HEAD(&disk_lists);
961	INIT_LIST_HEAD(&share_lists);
962
963	scan_disk_entries(&disk_lists);
964
965	USB_DEBUGP("[USB-SMB]: Loading USB share information ......\n");
966	list_for_each(pos, &disk_lists) {
967		diskinfo = list_entry(pos, struct disk_partition_info, list);
968		if (!diskinfo->mounted)
969			continue;
970		if (check_approved_disk(diskinfo)){
971			no_shareinfo = 0;
972			continue;
973		}
974		int j, i;
975		int star_count = 0;
976		char name[64], *val, oneline[1024], device_id[128], volume[128];
977		char *volumeName, *deviceName, *serial_num, *partition_id, *volume_name;
978		char fullpath[USB_PATH_SIZE], dupshare[USB_PATH_SIZE];
979		char *sep, *share_name, *folderName, *readAccess, *writeAccess;
980
981		sep = "*\n";
982		for(j=0; ;j++){
983			sprintf(name,SHARE_FILE_INFO"%d",j);
984			val = config_get(name);
985			if(*val == '\0')
986				break;
987			star_count = count_star(val);
988			i = 0;
989			volume[0] = '\0';
990
991			strcpy(oneline,val);
992
993			share_name = strtok(oneline, sep);/* share name */
994			folderName = strtok(NULL, sep);	/* folder name */
995			readAccess = strtok(NULL, sep);	/* readAccess*/
996			writeAccess = strtok(NULL, sep);	/* writeAccess */
997			if(star_count > 7){
998				star_count = star_count - 7;
999				while(i <= star_count){
1000					volume_name = strtok(NULL, sep);   /* volumeName*/
1001					sprintf(volume, "%s*%s", volume, volume_name);
1002					i++;
1003				}
1004				volumeName = volume + 1;
1005			}else{
1006				volumeName = strtok(NULL, sep);   /* volumeName*/
1007			}
1008			deviceName = strtok(NULL, sep);    /* deviceName */
1009			serial_num = strtok(NULL, sep);	/* serialNum */
1010			partition_id = strtok(NULL, sep);	/* partitionNum */
1011
1012			snprintf(device_id, sizeof(device_id), "%s*%s", serial_num, partition_id);
1013			if (share_name == NULL ||folderName == NULL ||
1014			          readAccess == NULL ||writeAccess == NULL ||
1015			          volumeName == NULL || deviceName == NULL )
1016					continue;
1017			if(strcmp(device_id,diskinfo->device_id) || strcmp(volumeName,diskinfo->vol_name) || strcmp(deviceName,diskinfo->vendor))
1018					continue;
1019
1020                        if (duplicate_share_name(share_name, &share_lists)) {
1021                                snprintf(dupshare, sizeof(dupshare), "%s(%c)", share_name, diskinfo->label);
1022                                share_name = dupshare;
1023                        }
1024
1025                        add_share_info_list(share_name, &share_lists);
1026
1027			snprintf(fullpath, sizeof(fullpath), "/mnt/%s%s", diskinfo->name, folderName);
1028
1029			readAccess = user_name(readAccess);
1030			writeAccess = user_name(writeAccess);
1031
1032			USB_DEBUGP("[USB-SMB]: SMBInfo %s Folder:%s Reader:%s Writer: %s\n",
1033							share_name, folderName, readAccess, writeAccess);
1034
1035			if(config_match("factory_mode","1" )){
1036				char cmd[128], disk[8], result[8];
1037				FILE *fp;
1038
1039				for(i = 0; i < 3; i++)
1040					disk[i] = fullpath[i+5];
1041
1042				snprintf(cmd, sizeof(cmd),
1043						"ls -l /sys/block/%s | grep usb | awk \'{print $11}\' | awk -F/ \'{print $6}\'",
1044						disk);
1045				fp = popen(cmd, "r");
1046				if (!fp) {
1047					perror("popen");
1048					return;
1049				}
1050				memset(result, 0, sizeof(result));
1051				fgets(result, sizeof(result), fp);
1052				pclose(fp);
1053				printf("result:%s\n", result);
1054				if(!strncmp(result, "dwc3.0", 6))
1055						share_name = "USB_Storage";
1056				else if(!strncmp(result, "dwc3.1", 6))
1057						share_name = "T_Drive";
1058			}
1059			add_smbd_share_info(fp, share_name, readAccess, writeAccess, fullpath, j);
1060
1061                        if (diskname != NULL && strncmp(diskinfo->name, diskname, 3) == 0)
1062                                no_shareinfo = 0;
1063		}
1064	}
1065
1066	if (no_shareinfo && diskname != NULL) {
1067		fprintf(stderr, "[USB-SMB]: Disk %s has no share information!\n", diskname);
1068		USB_DEBUGP("[USB-SMB]: Disk %s has no share information!\n", diskname);
1069		int i;
1070		//FILE *tmpfp;
1071		char value[256],name[64],*val;
1072		// char tmp_path[128], share_name[64], folder_path[64];
1073		char share_name[64], folder_path[64];
1074
1075		list_for_each(pos, &disk_lists) {
1076			diskinfo = list_entry(pos, struct disk_partition_info, list);
1077			if (!diskinfo->mounted ||strncmp(diskinfo->name, diskname, 3))
1078				continue;
1079                        if (diskinfo->label == 'U')
1080                                snprintf(share_name, sizeof(share_name), "USB_Storage");
1081                        else if (diskinfo->label == 's')
1082				snprintf(share_name, sizeof(share_name), "External_Disk");
1083                        else if (diskinfo->label == '0'){
1084				snprintf(share_name, sizeof(share_name), "SD_Card");
1085			}
1086			else if(isupper(diskinfo->label))
1087                                snprintf(share_name, sizeof(share_name),"%c_Drive", diskinfo->label);
1088			else if(isdigit(diskinfo->label))
1089				snprintf(share_name, sizeof(share_name),"SD_Card_%c", diskinfo->label);
1090			else
1091                                snprintf(share_name, sizeof(share_name),"External_Disk%d", 's' + 1 - diskinfo->label);
1092
1093			snprintf(value,sizeof(value),"%s*/*0*0*%s*%s*%s",share_name,diskinfo->vol_name,diskinfo->vendor,diskinfo->device_id);
1094
1095			for(i=0;i<100 ;i++){
1096				sprintf(name,SHARE_FILE_INFO"%d", i);
1097				val = config_get(name);
1098				if(*val == '\0')
1099					break;
1100			}
1101			config_set(name,value);
1102
1103		#ifdef USB_CONFIG_ADD
1104			snprintf(value,sizeof(value),"0*0*0*0");
1105			for(i=0;i<100 ;i++){
1106				sprintf(name,SHARE_AUTH_INFO"%d", i);
1107				val = config_get(name);
1108				if(*val == '\0')
1109					break;
1110				}
1111			config_set(name,value);
1112		#endif
1113			snprintf(folder_path, sizeof(folder_path), "/mnt/%s/", diskinfo->name);
1114			add_smbd_share_info(fp, share_name, USER_GUEST, USER_GUEST, folder_path, i);
1115		}
1116	}
1117
1118	list_for_each_safe(pos, nxt, &disk_lists) {
1119		diskinfo = list_entry(pos, struct disk_partition_info, list);
1120		list_del(pos);
1121		free(diskinfo);
1122	}
1123
1124	list_for_each_safe(pos, nxt, &share_lists) {
1125		shareinfo = list_entry(pos, struct share_info, list);
1126		list_del(pos);
1127		free(shareinfo);
1128	}
1129}
1130
1131void cleanup(int signal)
1132{
1133	printf("Try to recover from endless waiting.\n");
1134	reload_services();
1135	unlink(TMP_SAMBA_LOCK);
1136	exit(1);
1137}
1138
1139int check_samba_locked(void)
1140{
1141	return (!access(TMP_SAMBA_LOCK, F_OK));
1142}
1143
1144void check_sata_dev(void)
1145{
1146	strcpy(SATA_DEV_NAME, config_get("sata_diskname"));
1147	strcpy(SATA_DEV_SERIAL_NO, config_get("sata_serial_no"));
1148}
1149
1150void check_sd_card_dev(void)
1151{
1152	strcpy(SD_CARD_DEV_NAME, config_get("sd_card_diskname"));
1153}
1154
1155int main(int argc, char**argv)
1156{
1157	FILE *fp, *filp;
1158	char *diskname = NULL;
1159	struct timeval currenttime, newtime;
1160
1161	signal(SIGINT, cleanup);
1162	signal(SIGTERM, cleanup);
1163
1164	gettimeofday(&currenttime, NULL);
1165
1166	while(check_samba_locked()) {
1167		gettimeofday(&newtime, NULL);
1168		/* the longest waiting time is 30s, avoid endless waiting */
1169		if ((newtime.tv_sec - currenttime.tv_sec)>30)
1170			cleanup(0);
1171		sleep(1);
1172	}
1173
1174	/* create lock file */
1175	filp = fopen(TMP_SAMBA_LOCK, "w+");
1176	if (filp)
1177		fclose(filp);
1178	else {
1179		perror("error when creating samba_lock file!\n");
1180		return 1;
1181	}
1182
1183	check_sata_dev();
1184	check_sd_card_dev();
1185
1186	fp = fopen(USB_SMB_CONF, "w");
1187	if (fp == NULL)
1188		goto unlock;
1189
1190	if (argc == 2 && strlen(argv[1]) == 3 && strncmp(argv[1], "sd", 2) == 0)
1191		diskname = argv[1];	/* sd[a-z] */
1192
1193	add_smbd_global(fp);
1194	load_share_info(fp, diskname);
1195
1196	fclose(fp);
1197
1198	reload_services();
1199
1200unlock:
1201	unlink(TMP_SAMBA_LOCK);
1202	return 0;
1203}
1204
1205