rfa 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. #!/bin/sh
  2. # Echo help information
  3. usage()
  4. {
  5. cat <<EOF
  6. Usage: $0 [options] <command> <parameters>
  7. Tool for VCS repository administration.
  8. VCS support: $possible_vcs
  9. Options:
  10. -h, --help
  11. Print help message.
  12. -c <PATH>, --config=<PATH>
  13. Specify config file (default is /etc/repoforge/rfa.conf)
  14. -s <git/svn>, --vcs=<git/svn>
  15. Choose VCS type to create new repository (default is git)
  16. --git
  17. Same as "-c git"
  18. --svn
  19. Same as "-c svn"
  20. Commands:
  21. info <repository>
  22. Get information for specified repository.
  23. add <repository1> [repository2] ...
  24. Create new repository.
  25. del <repository1> [repository2] ...
  26. Delete existing repository.
  27. fixmod <repository1> [repository2] ...
  28. Fix access rights for repository.
  29. rename <old_name> <new_name>
  30. Rename repository.
  31. useradd <repository> <r/w/rw> <user1> [user2] ...
  32. Set access rights for user(s) to repository.
  33. userdel <repository> <r/w/rw> <user1> [user2] ...
  34. Remove access rights for user(s) to repository.
  35. EOF
  36. }
  37. group_add()
  38. {
  39. groupadd -K GID_MIN=${group_gid_min} "${group_r_prefix}$1" || return 1
  40. groupadd -K GID_MIN=${group_gid_min} "${group_w_prefix}$1" || return 1
  41. }
  42. group_del()
  43. {
  44. groupdel "${group_r_prefix}$1" || return 1
  45. groupdel "${group_w_prefix}$1" || return 1
  46. }
  47. group_rename()
  48. {
  49. local old_name="$1"
  50. local new_name="$2"
  51. groupmod -n "${group_r_prefix}$new_name" "${group_r_prefix}$old_name" || return 1
  52. groupmod -n "${group_w_prefix}$new_name" "${group_w_prefix}$old_name" || return 1
  53. return 0
  54. }
  55. get_group_members()
  56. {
  57. local group="$1"
  58. grep -e "^$group:" /etc/group | sed -e "s|^.*:||" -e "s|,| |g"
  59. }
  60. create_repo_svn()
  61. {
  62. svnadmin --fs-type=fsfs create "$1" || return 1
  63. }
  64. create_repo_git()
  65. {
  66. mkdir -p "$1" || return 1
  67. # git -C "$1" init --bare --shared >/dev/null || return 1
  68. cd "$1" || return 1
  69. git init --bare --shared >/dev/null || return 1
  70. cd - >/dev/null
  71. }
  72. data_add()
  73. {
  74. local r_name="$1"
  75. local r_root="$2"
  76. local r_link="$3"
  77. local repo_r="${r_root}/${r_name}"
  78. local repo_w="${r_root}/${r_name}/${r_name}"
  79. mkdir -p "${repo_r}"
  80. local saved_umask=`umask`
  81. umask 002
  82. local create_vcs_func="create_repo_$opts_vcs"
  83. $create_vcs_func "$repo_w" || return 1
  84. umask ${saved_umask}
  85. }
  86. data_fixmod()
  87. {
  88. local r_name="$1"
  89. local r_root="$2"
  90. local r_link="$3"
  91. local repo_r="${r_root}/${r_name}"
  92. local repo_w="${r_root}/${r_name}/${r_name}"
  93. chmod 750 "${repo_r}" || return 1
  94. chgrp "${group_r_prefix}${r_name}" "${repo_r}" || return 1
  95. chgrp -R "${group_w_prefix}${r_name}" "${repo_w}" || return 1
  96. local dirs=""
  97. dirs=`find "$repo_w" -type d`
  98. local dir=""
  99. for dir in $dirs; do
  100. chmod g+s "$dir" || return 1
  101. done
  102. chmod -R g+w "${repo_w}" || return 1
  103. }
  104. data_del()
  105. {
  106. local r_name="$1"
  107. local r_root="$2"
  108. rm -Rf "$r_root/$r_name"
  109. }
  110. link_add()
  111. {
  112. local r_name="$1"
  113. local r_root="$2"
  114. local r_link="$3"
  115. ln -sf "$r_root/$r_name/$r_name" "$r_link/$r_name"
  116. }
  117. link_del()
  118. {
  119. local r_name="$1"
  120. local r_link="$2"
  121. rm -f "$r_link/$r_name"
  122. }
  123. repository_add()
  124. {
  125. local rep_name=""
  126. local repo_root
  127. local repo_link
  128. for rep_name in "$@"; do
  129. repo_root=`find_repo_root "$rep_name"`
  130. repo_link=`find_repo_link "$rep_name"`
  131. test "x$repo_root" = "x" || { echo "Error: The repository \"$rep_name\" already exists." 1>&2; exit 1; }
  132. eval repo_root="\$repository_${opts_vcs}_root"
  133. eval repo_link="\$repository_${opts_vcs}_link"
  134. test "x$repo_root" = "x" && { echo "Error: Illegal repository root \"\"" 1>&2; exit 1; }
  135. test "x$repo_link" = "x" && { echo "Error: Illegal repository link \"\"" 1>&2; exit 1; }
  136. test -d "$repo_root" || { echo "Error: Illegal repository root \"$repo_root\"" 1>&2; exit 1; }
  137. test -d "$repo_link" || { echo "Error: Illegal repository link \"$repo_link\"" 1>&2; exit 1; }
  138. group_add "$rep_name" || { echo "Error: Can't add group for repository \"$rep_name\"" 1>&2; exit 1; }
  139. data_add "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't add repository \"$rep_name\"" 1>&2; exit 1; }
  140. data_fixmod "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't fix mode for repository \"$rep_name\"" 1>&2; exit 1; }
  141. link_add "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't add link for repository \"$rep_name\"" 1>&2; exit 1; }
  142. echo "Info: The repository \"$rep_name\" was succesfully created."
  143. done
  144. }
  145. # Delete the repository
  146. repository_del()
  147. {
  148. local rep_name=""
  149. local sure=""
  150. local repo_root
  151. local repo_link
  152. for rep_name in "$@"; do
  153. repo_root=`find_repo_root "$rep_name"`
  154. repo_link=`find_repo_link "$rep_name"`
  155. test "x$repo_root" = "x" -o "x$repo_link" = "x" && { echo "Error: Can't find repository \"$rep_name\"" 1>&2; exit 1; }
  156. if test "x$opts_force" = "x"; then
  157. read -r -p "Deleting repository \"$rep_name\". Are you sure (y/n)? " sure
  158. test "x$sure" = "xy" -o "x$sure" = "xY" || { echo "Info: The repository \"$rep_name\" will be not deleted."; continue; }
  159. fi
  160. link_del "$rep_name" "$repo_link" || { echo "Error: Can't remove link for repository \"$rep_name\"" 1>&2; exit 1; }
  161. data_del "$rep_name" "$repo_root" || { echo "Error: Can't remove repository \"$rep_name\"" 1>&2; exit 1; }
  162. group_del "$rep_name" || { echo "Error: Can't remove group for repository \"$rep_name\"" 1>&2; exit 1; }
  163. echo "Info: The repository \"$rep_name\" was succesfully deleted."
  164. done
  165. }
  166. # Fix broken repository: symlink, access rights, owner.
  167. repository_fixmod()
  168. {
  169. local rep_name=""
  170. local repo_root
  171. local repo_link
  172. for rep_name in "$@"; do
  173. repo_root=`find_repo_root "$rep_name"`
  174. repo_link=`find_repo_link "$rep_name"`
  175. test "x$repo_root" = "x" -o "x$repo_link" = "x" && { echo "Error: Can't find repository \"$rep_name\"" 1>&2; exit 1; }
  176. data_fixmod "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't fix repository's \"$rep_name\" mode" 1>&2; exit 1; }
  177. link_add "$rep_name" "$repo_root" "$repo_link" || { echo "Error: Can't create link for repository \"$rep_name\"" 1>&2; exit 1; }
  178. echo "Info: The repository \"$rep_name\" was succesfully fixed."
  179. done
  180. }
  181. # Rename existing repository
  182. repository_rename()
  183. {
  184. local old_name="$1"
  185. local new_name="$2"
  186. local repo_root
  187. local repo_link
  188. # Check if target name is already exists
  189. repo_root=`find_repo_root "$new_name"`
  190. test "x$repo_root" = "x" || { echo "Error: The repository \"$new_name\" is already exist" 1>&2; return 1; }
  191. repo_root=`find_repo_root "$old_name"`
  192. repo_link=`find_repo_link "$old_name"`
  193. test "x$repo_root" != "x" -a -d "$repo_root/$old_name" || { echo "Error: Can't find repository \"$old_name\"" 1>&2; return 1; }
  194. test "x$repo_root" != "x" -a -L "$repo_link/$old_name" || { echo "Error: Can't find link of repository \"$old_name\"" 1>&2; return 1; }
  195. # Real move repository and link
  196. mv -f "$repo_root/$old_name" "$repo_root/$new_name" || { echo "Error: Can't move repository \"$old_name\"" 1>&2; return 1; }
  197. link_del "$old_name" "$repo_link" || { echo "Error: Can't remove link for repository \"$old_name\"" 1>&2; }
  198. link_add "$new_name" "$repo_root" "$repo_link" || { echo "Error: Can't create link for repository \"$new_name\"" 1>&2; }
  199. # Rename a groups
  200. group_rename "$old_name" "$new_name" || { echo "Error: Can't rename access groups for repository \"$new_name\"" 1>&2; }
  201. echo "Info: The repository \"$old_name\" was succesfully renamed to \"$new_name\""
  202. return 0
  203. }
  204. # Show repository info
  205. repository_info()
  206. {
  207. local repo="$1"
  208. local repo_root
  209. local repo_link
  210. repo_root=`find_repo_root "$repo"`
  211. repo_link=`find_repo_link "$repo"`
  212. test "x$repo_root" != "x" -a -d "$repo_root/$repo" || { echo "Error: Can't find repository \"$repo\"" 1>&2; return 1; }
  213. echo "Name: $repo"
  214. echo "VCS : "`find_repo_vcs "$repo"`
  215. echo "Path: $repo_root"
  216. echo "Link: $repo_link"
  217. echo "Write access: "`get_group_members "${group_w_prefix}$repo"`
  218. echo "Read access: "`get_group_members "${group_r_prefix}$repo"`
  219. return 0
  220. }
  221. # Add users to access groups
  222. user_add()
  223. {
  224. local w=0
  225. local r=0
  226. local repository_name="$1"
  227. local user_name=""
  228. shift
  229. case "$1" in
  230. r)
  231. r=1
  232. ;;
  233. w)
  234. w=1
  235. ;;
  236. rw|wr)
  237. r=1
  238. w=1
  239. ;;
  240. *)
  241. echo "Error: Illegal parameter \"$1\"" 1>&2
  242. exit 1
  243. ;;
  244. esac
  245. shift
  246. for user_name in "$@"; do
  247. test $r -ne 0 && adduser "${user_name}" "${group_r_prefix}${repository_name}"
  248. test $w -ne 0 && adduser "${user_name}" "${group_w_prefix}${repository_name}"
  249. done
  250. }
  251. # Remove users from access groups
  252. user_del()
  253. {
  254. local w=0
  255. local r=0
  256. local repository_name=$1
  257. local user_name=""
  258. shift
  259. case "$1" in
  260. r)
  261. r=1
  262. ;;
  263. w)
  264. w=1
  265. ;;
  266. rw|wr)
  267. r=1
  268. w=1
  269. ;;
  270. *)
  271. echo "Error: Illegal parameter \"$1\"" 1>&2
  272. exit 1
  273. ;;
  274. esac
  275. shift
  276. for user_name in "$@"; do
  277. test $r -ne 0 && deluser "${user_name}" "${group_r_prefix}${repository_name}"
  278. test $w -ne 0 && deluser "${user_name}" "${group_w_prefix}${repository_name}"
  279. done
  280. }
  281. # Find repository VCS
  282. find_repo_vcs()
  283. {
  284. local r=""
  285. local r_root=""
  286. for r in $possible_vcs; do
  287. eval r_root="\$repository_${r}_root"
  288. test "x$r_root" = "x" && continue
  289. test -d "$r_root/$1" || continue
  290. echo "$r"
  291. break
  292. done
  293. return 0
  294. }
  295. # Find repository root path by repository name
  296. find_repo_root()
  297. {
  298. local r=""
  299. local r_root=""
  300. for r in $possible_vcs; do
  301. eval r_root="\$repository_${r}_root"
  302. test "x$r_root" = "x" && continue
  303. test -d "$r_root/$1" || continue
  304. echo "$r_root"
  305. break
  306. done
  307. return 0
  308. }
  309. # Find repository link path by repository name
  310. find_repo_link()
  311. {
  312. local r=""
  313. local r_root=""
  314. local r_link=""
  315. for r in $possible_vcs; do
  316. eval r_root="\$repository_${r}_root"
  317. test "x$r_root" = "x" && continue
  318. test -d "$r_root/$1" || continue
  319. eval r_link="\$repository_${r}_link"
  320. echo "$r_link"
  321. break
  322. done
  323. return 0
  324. }
  325. #------------------ MAIN -----------------------------------------
  326. possible_vcs="svn git"
  327. # Defaults for rfa.conf
  328. group_gid_min="3000"
  329. group_w_prefix="vcs-w-"
  330. group_r_prefix="vcs-r-"
  331. repository_root=
  332. repository_link=
  333. default_vcs="git"
  334. # Parse command line options
  335. action="help"
  336. opts_force=""
  337. opts_conf="/etc/repoforge/rfa.conf"
  338. opts_vcs="$default_vcs"
  339. while test "x$1" != "x"; do
  340. option="$1"
  341. case "$option" in
  342. -h|--help)
  343. usage
  344. exit 0
  345. ;;
  346. -f|--force)
  347. opts_force=1
  348. ;;
  349. # Config file
  350. -c)
  351. shift
  352. opts_conf="$1"
  353. ;;
  354. --config=*)
  355. opts_conf=`echo "$option" | sed 's/--config=//'`
  356. ;;
  357. # Choose VCS
  358. -s)
  359. shift
  360. opts_vcs="$1"
  361. ;;
  362. --vcs=*)
  363. opts_vcs=`echo "$option" | sed 's/--vcs=//'`
  364. ;;
  365. --git)
  366. opts_vcs="git"
  367. ;;
  368. --svn)
  369. opts_vcs="svn"
  370. ;;
  371. # Default
  372. *)
  373. action="$option"
  374. shift
  375. break
  376. ;;
  377. esac
  378. shift
  379. done
  380. # Early help message
  381. test "x$action" = "xhelp" && { usage; exit 0; }
  382. # Check options
  383. bad_vcs=1
  384. for v in $possible_vcs; do
  385. test "x$opts_vcs" = "x$v" && { bad_vcs=""; break; }
  386. done
  387. test "x$bad_vcs" = "x" || { echo "Error: Illegal VCS \"$opts_vcs\"" 1>&2; exit 1; }
  388. # Include config file
  389. test -r "$opts_conf" && . $opts_conf
  390. # Compatibility (suppose SVN)
  391. test "x$repository_svn_root" = "x" && repository_svn_root="$repository_root"
  392. test "x$repository_svn_link" = "x" && repository_svn_link="$repository_link"
  393. # Action
  394. case "$action" in
  395. "info")
  396. test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
  397. repository_info "$@"
  398. ;;
  399. "add")
  400. test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
  401. repository_add "$@"
  402. ;;
  403. "del")
  404. test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
  405. repository_del "$@"
  406. ;;
  407. "fixmod")
  408. test $# -lt 1 && { echo "Error: Repository name is expected" 1>&2; exit 1; }
  409. repository_fixmod "$@"
  410. ;;
  411. "rename")
  412. test $# -lt 2 && { echo "Error: The old and new repository names are expected" 1>&2; exit 1; }
  413. repository_rename "$@" || exit 1
  414. ;;
  415. "adduser"|"useradd")
  416. test $# -lt 3 && { echo "Error: Not enough parameters" 1>&2; exit 1; }
  417. user_add "$@"
  418. ;;
  419. "deluser"|"userdel")
  420. test $# -lt 3 && { echo "Error: Not enough parameters" 1>&2; exit 1; }
  421. user_del "$@"
  422. ;;
  423. *)
  424. echo "Error: Unknown command" 1>&2
  425. exit 1
  426. ;;
  427. esac
  428. exit $?