2 * dpkg-statoverride - override ownership and mode of files
4 * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
5 * Copyright © 2006-2015 Guillem Jover <guillem@debian.org>
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 #include <sys/types.h>
40 #include <dpkg/i18n.h>
41 #include <dpkg/dpkg.h>
42 #include <dpkg/dpkg-db.h>
43 #include <dpkg/path.h>
45 #include <dpkg/glob.h>
46 #include <dpkg/options.h>
51 static const char printforhelp
[] = N_(
52 "Use --help for help about overriding file stat information.");
54 static void DPKG_ATTR_NORET
55 printversion(const struct cmdinfo
*cip
, const char *value
)
57 printf(_("Debian %s version %s.\n"), dpkg_get_progname(),
61 "This is free software; see the GNU General Public License version 2 or\n"
62 "later for copying conditions. There is NO warranty.\n"));
64 m_output(stdout
, _("<standard output>"));
69 static void DPKG_ATTR_NORET
70 usage(const struct cmdinfo
*cip
, const char *value
)
73 "Usage: %s [<option> ...] <command>\n"
74 "\n"), dpkg_get_progname());
78 " --add <owner> <group> <mode> <path>\n"
79 " add a new <path> entry into the database.\n"
80 " --remove <path> remove <path> from the database.\n"
81 " --list [<glob-pattern>] list current overrides in the database.\n"
86 " --admindir <directory> set the directory with the statoverride file.\n"
87 " --update immediately update <path> permissions.\n"
88 " --force force an action even if a sanity check fails.\n"
89 " --quiet quiet operation, minimal output.\n"
90 " --help show this help message.\n"
91 " --version show the version.\n"
94 m_output(stdout
, _("<standard output>"));
99 static const char *admindir
;
101 static int opt_verbose
= 1;
102 static int opt_force
= 0;
103 static int opt_update
= 0;
106 path_cleanup(const char *path
)
108 char *new_path
= m_strdup(path
);
110 path_trim_slash_slashdot(new_path
);
111 if (opt_verbose
&& strcmp(path
, new_path
) != 0)
112 warning(_("stripping trailing /"));
117 static struct file_stat
*
118 statdb_node_new(const char *user
, const char *group
, const char *mode
)
120 struct file_stat
*filestat
;
122 filestat
= nfmalloc(sizeof(*filestat
));
124 filestat
->uid
= statdb_parse_uid(user
);
125 if (filestat
->uid
== (uid_t
)-1)
126 ohshit(_("user '%s' does not exist"), user
);
127 filestat
->uname
= NULL
;
128 filestat
->gid
= statdb_parse_gid(group
);
129 if (filestat
->gid
== (gid_t
)-1)
130 ohshit(_("group '%s' does not exist"), group
);
131 filestat
->gname
= NULL
;
132 filestat
->mode
= statdb_parse_mode(mode
);
137 static struct file_stat
**
138 statdb_node_find(const char *filename
)
140 struct filenamenode
*file
;
142 file
= findnamenode(filename
, 0);
144 return &file
->statoverride
;
148 statdb_node_remove(const char *filename
)
150 struct filenamenode
*file
;
152 file
= findnamenode(filename
, fnn_nonew
);
153 if (!file
|| (file
&& !file
->statoverride
))
156 file
->statoverride
= NULL
;
162 statdb_node_apply(const char *filename
, struct file_stat
*filestat
)
164 if (chown(filename
, filestat
->uid
, filestat
->gid
) < 0)
165 ohshite(_("error setting ownership of '%.255s'"), filename
);
166 if (chmod(filename
, filestat
->mode
& ~S_IFMT
))
167 ohshite(_("error setting permissions of '%.255s'"), filename
);
170 dpkg_selabel_set_context(filename
, filename
, filestat
->mode
);
171 dpkg_selabel_close();
175 statdb_node_print(FILE *out
, struct filenamenode
*file
)
177 struct file_stat
*filestat
= file
->statoverride
;
184 pw
= getpwuid(filestat
->uid
);
186 fprintf(out
, "%s ", pw
->pw_name
);
187 else if (filestat
->uname
)
188 fprintf(out
, "%s ", filestat
->uname
);
190 fprintf(out
, "#%d ", filestat
->uid
);
192 gr
= getgrgid(filestat
->gid
);
194 fprintf(out
, "%s ", gr
->gr_name
);
195 else if (filestat
->gname
)
196 fprintf(out
, "%s ", filestat
->gname
);
198 fprintf(out
, "#%d ", filestat
->gid
);
200 fprintf(out
, "%o %s\n", filestat
->mode
& ~S_IFMT
, file
->name
);
207 struct atomic_file
*dbfile
;
208 struct fileiterator
*iter
;
209 struct filenamenode
*file
;
211 dbname
= dpkg_db_get_path(STATOVERRIDEFILE
);
212 dbfile
= atomic_file_new(dbname
, ATOMIC_FILE_BACKUP
);
213 atomic_file_open(dbfile
);
215 iter
= files_db_iter_new();
216 while ((file
= files_db_iter_next(iter
)))
217 statdb_node_print(dbfile
->fp
, file
);
218 files_db_iter_free(iter
);
220 atomic_file_sync(dbfile
);
221 atomic_file_close(dbfile
);
222 atomic_file_commit(dbfile
);
223 atomic_file_free(dbfile
);
225 dir_sync_path(dpkg_db_get_dir());
231 statoverride_add(const char *const *argv
)
233 const char *user
= argv
[0];
234 const char *group
= argv
[1];
235 const char *mode
= argv
[2];
236 const char *path
= argv
[3];
238 struct file_stat
**filestat
;
240 if (!user
|| !group
|| !mode
|| !path
|| argv
[4])
241 badusage(_("--%s needs four arguments"), cipaction
->olong
);
243 if (strchr(path
, '\n'))
244 badusage(_("path may not contain newlines"));
246 filename
= path_cleanup(path
);
248 filestat
= statdb_node_find(filename
);
249 if (*filestat
!= NULL
) {
251 warning(_("an override for '%s' already exists, "
252 "but --force specified so will be ignored"),
255 ohshit(_("an override for '%s' already exists; "
256 "aborting"), filename
);
259 *filestat
= statdb_node_new(user
, group
, mode
);
264 if (stat(filename
, &st
) == 0) {
265 (*filestat
)->mode
|= st
.st_mode
& S_IFMT
;
266 statdb_node_apply(filename
, *filestat
);
267 } else if (opt_verbose
) {
268 warning(_("--update given but %s does not exist"),
281 statoverride_remove(const char *const *argv
)
283 const char *path
= argv
[0];
286 if (!path
|| argv
[1])
287 badusage(_("--%s needs a single argument"), "remove");
289 filename
= path_cleanup(path
);
291 if (!statdb_node_remove(filename
)) {
293 warning(_("no override present"));
300 if (opt_update
&& opt_verbose
)
301 warning(_("--update is useless for --remove"));
311 statoverride_list(const char *const *argv
)
313 struct fileiterator
*iter
;
314 struct filenamenode
*file
;
316 struct glob_node
*glob_list
= NULL
;
319 while ((thisarg
= *argv
++)) {
320 char *pattern
= path_cleanup(thisarg
);
322 glob_list_prepend(&glob_list
, pattern
);
324 if (glob_list
== NULL
)
325 glob_list_prepend(&glob_list
, m_strdup("*"));
327 iter
= files_db_iter_new();
328 while ((file
= files_db_iter_next(iter
))) {
331 for (g
= glob_list
; g
; g
= g
->next
) {
332 if (fnmatch(g
->pattern
, file
->name
, 0) == 0) {
333 statdb_node_print(stdout
, file
);
339 files_db_iter_free(iter
);
341 glob_list_free(glob_list
);
346 static const struct cmdinfo cmdinfos
[] = {
347 ACTION("add", 0, act_install
, statoverride_add
),
348 ACTION("remove", 0, act_remove
, statoverride_remove
),
349 ACTION("list", 0, act_listfiles
, statoverride_list
),
351 { "admindir", 0, 1, NULL
, &admindir
, NULL
},
352 { "quiet", 0, 0, &opt_verbose
, NULL
, NULL
, 0 },
353 { "force", 0, 0, &opt_force
, NULL
, NULL
, 1 },
354 { "update", 0, 0, &opt_update
, NULL
, NULL
, 1 },
355 { "help", '?', 0, NULL
, NULL
, usage
},
356 { "version", 0, 0, NULL
, NULL
, printversion
},
361 main(int argc
, const char *const *argv
)
365 dpkg_locales_init(PACKAGE
);
366 dpkg_program_init("dpkg-statoverride");
367 dpkg_options_parse(&argv
, cmdinfos
, printforhelp
);
369 admindir
= dpkg_db_set_dir(admindir
);
372 badusage(_("need an action option"));
375 ensure_statoverrides(STATDB_PARSE_LAX
);
377 ret
= cipaction
->action(argv
);