install.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Copyright (C) 2003 by Glenn McGrath <bug1@iinet.net.au>
  4. *
  5. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  6. *
  7. * TODO: -d option, need a way of recursively making directories and changing
  8. * owner/group, will probably modify bb_make_directory(...)
  9. */
  10. #include "busybox.h"
  11. #include "libcoreutils/coreutils.h"
  12. #include <libgen.h>
  13. #include <getopt.h> /* struct option */
  14. #if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
  15. static const struct option install_long_options[] = {
  16. { "directory", 0, NULL, 'd' },
  17. { "preserve-timestamps", 0, NULL, 'p' },
  18. { "strip", 0, NULL, 's' },
  19. { "group", 0, NULL, 'g' },
  20. { "mode", 0, NULL, 'm' },
  21. { "owner", 0, NULL, 'o' },
  22. { 0, 0, 0, 0 }
  23. };
  24. #endif
  25. int install_main(int argc, char **argv)
  26. {
  27. struct stat statbuf;
  28. mode_t mode;
  29. uid_t uid;
  30. gid_t gid;
  31. const char *gid_str;
  32. const char *uid_str;
  33. const char *mode_str;
  34. int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
  35. int ret = EXIT_SUCCESS, flags, i, isdir;
  36. enum {
  37. OPT_CMD = 0x1,
  38. OPT_DIRECTORY = 0x2,
  39. OPT_PRESERVE_TIME = 0x4,
  40. OPT_STRIP = 0x8,
  41. OPT_GROUP = 0x10,
  42. OPT_MODE = 0x20,
  43. OPT_OWNER = 0x40,
  44. };
  45. #if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
  46. applet_long_options = install_long_options;
  47. #endif
  48. opt_complementary = "?:s--d:d--s";
  49. /* -c exists for backwards compatibility, its needed */
  50. flags = getopt32(argc, argv, "cdpsg:m:o:", &gid_str, &mode_str, &uid_str);
  51. /* preserve access and modification time, this is GNU behaviour, BSD only preserves modification time */
  52. if (flags & OPT_PRESERVE_TIME) {
  53. copy_flags |= FILEUTILS_PRESERVE_STATUS;
  54. }
  55. mode = 0666;
  56. if (flags & OPT_MODE) bb_parse_mode(mode_str, &mode);
  57. uid = (flags & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
  58. gid = (flags & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
  59. if (flags & (OPT_OWNER|OPT_GROUP)) umask(0);
  60. /* Create directories
  61. * don't use bb_make_directory() as it can't change uid or gid
  62. * perhaps bb_make_directory() should be improved.
  63. */
  64. if (flags & OPT_DIRECTORY) {
  65. for (argv += optind; *argv; argv++) {
  66. char *old_argv_ptr = *argv + 1;
  67. char *argv_ptr;
  68. do {
  69. argv_ptr = strchr(old_argv_ptr, '/');
  70. old_argv_ptr = argv_ptr;
  71. if (argv_ptr) {
  72. *argv_ptr = '\0';
  73. old_argv_ptr++;
  74. }
  75. if (mkdir(*argv, mode | 0111) == -1) {
  76. if (errno != EEXIST) {
  77. bb_perror_msg("cannot create %s", *argv);
  78. ret = EXIT_FAILURE;
  79. break;
  80. }
  81. }
  82. if ((flags & (OPT_OWNER|OPT_GROUP))
  83. && lchown(*argv, uid, gid) == -1
  84. ) {
  85. bb_perror_msg("cannot change ownership of %s", *argv);
  86. ret = EXIT_FAILURE;
  87. break;
  88. }
  89. if (argv_ptr) {
  90. *argv_ptr = '/';
  91. }
  92. } while (old_argv_ptr);
  93. }
  94. return ret;
  95. }
  96. isdir = lstat(argv[argc - 1], &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
  97. for (i = optind; i < argc - 1; i++) {
  98. char *dest;
  99. dest = argv[argc - 1];
  100. if (isdir)
  101. dest = concat_path_file(argv[argc - 1], basename(argv[i]));
  102. ret |= copy_file(argv[i], dest, copy_flags);
  103. /* Set the file mode */
  104. if ((flags & OPT_MODE) && chmod(dest, mode) == -1) {
  105. bb_perror_msg("cannot change permissions of %s", dest);
  106. ret = EXIT_FAILURE;
  107. }
  108. /* Set the user and group id */
  109. if ((flags & (OPT_OWNER|OPT_GROUP))
  110. && lchown(dest, uid, gid) == -1
  111. ) {
  112. bb_perror_msg("cannot change ownership of %s", dest);
  113. ret = EXIT_FAILURE;
  114. }
  115. if (flags & OPT_STRIP) {
  116. if (execlp("strip", "strip", dest, NULL) == -1) {
  117. bb_perror_msg("strip");
  118. ret = EXIT_FAILURE;
  119. }
  120. }
  121. if (ENABLE_FEATURE_CLEAN_UP && isdir) free(dest);
  122. }
  123. return ret;
  124. }