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(¤ttime, 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