blob: 630d2f205b8357105d14ea40d33415f81d18909b [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2015 The ChromiumOS Authors
Christopher Wiley5ccc8292015-05-28 10:01:22 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This script installs users and groups into sysroots."""
6
Christopher Wiley5ccc8292015-05-28 10:01:22 -07007import os
8
9from chromite.lib import accounts_lib
10from chromite.lib import commandline
11from chromite.lib import cros_build_lib
12from chromite.lib import osutils
13from chromite.lib import sysroot_lib
14from chromite.lib import user_db
15
16
Alex Klein1699fab2022-09-08 08:46:06 -060017ACCOUNT_DB_FILENAME = "accounts.json"
Christopher Wiley5ccc8292015-05-28 10:01:22 -070018
Alex Klein1699fab2022-09-08 08:46:06 -060019ACTION_GET_ENTRY = "get_entry"
20ACTION_INSTALL_USER = "install_user"
21ACTION_INSTALL_GROUP = "install_group"
Christopher Wiley5ccc8292015-05-28 10:01:22 -070022
Alex Klein1699fab2022-09-08 08:46:06 -060023USER_DB = "passwd"
24GROUP_DB = "group"
Christopher Wiley5ccc8292015-05-28 10:01:22 -070025
26
27def GetOptions(argv):
Alex Klein1699fab2022-09-08 08:46:06 -060028 """Returns the parsed command line arguments in |argv|."""
29 parser = commandline.ArgumentParser(description=__doc__)
30 command_parsers = parser.add_subparsers(dest="action")
Christopher Wiley5ccc8292015-05-28 10:01:22 -070031
Alex Klein1699fab2022-09-08 08:46:06 -060032 get_ent_parser = command_parsers.add_parser(
33 ACTION_GET_ENTRY, help="Get an entry from an account database."
34 )
35 get_ent_parser.add_argument(
36 "--nolock",
37 action="store_true",
38 default=False,
39 help="Skip locking the database before reading it.",
40 )
41 get_ent_parser.add_argument(
42 "sysroot", type="path", help="Path to sysroot containing the database"
43 )
44 get_ent_parser.add_argument(
45 "database", choices=(USER_DB, GROUP_DB), help="Name of database to get"
46 )
47 get_ent_parser.add_argument("name", type=str, help="Name of account to get")
Christopher Wiley5ccc8292015-05-28 10:01:22 -070048
Alex Klein1699fab2022-09-08 08:46:06 -060049 user_parser = command_parsers.add_parser(
50 ACTION_INSTALL_USER, help="Install a user to a sysroot"
51 )
52 user_parser.add_argument("name", type=str, help="Name of user to install")
53 user_parser.add_argument("--uid", type=int, help="UID of the user")
54 user_parser.add_argument("--shell", type="path", help="Shell of user")
55 user_parser.add_argument(
56 "--home", type="path", help="Home directory of user"
57 )
58 user_parser.add_argument(
59 "--primary_group", type=str, help="Name of primary group for user"
60 )
Christopher Wiley5ccc8292015-05-28 10:01:22 -070061
Alex Klein1699fab2022-09-08 08:46:06 -060062 group_parser = command_parsers.add_parser(
63 ACTION_INSTALL_GROUP, help="Install a group to a sysroot"
64 )
65 group_parser.add_argument(
66 "name", type=str, help="Name of group to install."
67 )
68 group_parser.add_argument("--gid", type=int, help="GID of the group")
Christopher Wiley5ccc8292015-05-28 10:01:22 -070069
Alex Klein1699fab2022-09-08 08:46:06 -060070 # Both group and user parsers need to understand the target sysroot.
71 for sub_parser in (user_parser, group_parser):
72 sub_parser.add_argument(
73 "sysroot", type="path", help="The sysroot to install the user into"
74 )
Christopher Wiley5ccc8292015-05-28 10:01:22 -070075
Alex Klein1699fab2022-09-08 08:46:06 -060076 options = parser.parse_args(argv)
77 options.Freeze()
78 return options
Christopher Wiley5ccc8292015-05-28 10:01:22 -070079
80
81def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -060082 cros_build_lib.AssertInsideChroot()
83 options = GetOptions(argv)
Christopher Wiley5ccc8292015-05-28 10:01:22 -070084
Alex Klein1699fab2022-09-08 08:46:06 -060085 if options.action == ACTION_GET_ENTRY:
86 db = user_db.UserDB(options.sysroot)
87 if options.database == USER_DB:
88 print(db.GetUserEntry(options.name, skip_lock=options.nolock))
89 else:
90 print(db.GetGroupEntry(options.name, skip_lock=options.nolock))
91 return 0
92
93 overlays = (
94 sysroot_lib.Sysroot(options.sysroot)
95 .GetStandardField(sysroot_lib.STANDARD_FIELD_PORTDIR_OVERLAY)
96 .split()
97 )
98
99 # TODO(wiley) This process could be optimized to avoid reparsing these
100 # overlay databases each time.
101 account_db = accounts_lib.AccountDatabase()
102 for overlay_path in overlays:
103 database_path = os.path.join(overlay_path, ACCOUNT_DB_FILENAME)
104 if os.path.exists(database_path):
105 account_db.AddAccountsFromDatabase(database_path)
106
107 installed_users = user_db.UserDB(options.sysroot)
108
109 if options.action == ACTION_INSTALL_USER:
110 account_db.InstallUser(
111 options.name,
112 installed_users,
113 uid=options.uid,
114 shell=options.shell,
115 homedir=options.home,
116 primary_group=options.primary_group,
117 )
118
119 homedir = account_db.users[options.name].home
120 homedir_path = os.path.join(options.sysroot, homedir)
121
122 if homedir != "/dev/null" and not os.path.exists(homedir_path):
123 osutils.SafeMakedirs(homedir_path, sudo=True)
124 uid = account_db.users[options.name].uid
125 cros_build_lib.sudo_run(
126 ["chown", "%d:%d" % (uid, uid), homedir_path], print_cmd=False
127 )
128
129 elif options.action == ACTION_INSTALL_GROUP:
130 account_db.InstallGroup(options.name, installed_users, gid=options.gid)
Christopher Wiley5ccc8292015-05-28 10:01:22 -0700131 else:
Alex Klein1699fab2022-09-08 08:46:06 -0600132 cros_build_lib.Die(
133 "Unsupported account type: %s" % options.account_type
134 )