[Toybox] New toys - chmod, chown and chgrp
Georgi Chorbadzhiyski
gf at unixsol.org
Wed Feb 29 06:40:27 PST 2012
Ok, these were not so hard. There is a possibility of code sharing, because
most of the code is copy and pasted between these and adding support for the
missing options in chown and chgrp will only increase code duplication.
I'll unify most of the code in these toys somewhere under lib (dirtree.c probably).
It looks like in order things to work I'll need to add one void * parameter to callback
function passed to dirtree_read() and possibly flags parameter to dirtree_read() itself
(I want to silence printed warnings for example).
How is that for a plan?
--
Georgi Chorbadzhiyski
http://georgi.unixsol.org/
-------------- next part --------------
/* vi: set sw=4 ts=4:
*
* chmod.c - Change file mode bits
*
* Copyright 2012 Georgi Chorbadzhiyski <georgi at unixsol.org>
*
* See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chmod.html
*
USE_CHMOD(NEWTOY(chmod, "<2Rfv", TOYFLAG_BIN))
config CHMOD
bool "chmod"
default y
help
usage: chmod [-R] [-f] [-v] mode file...
Change mode bits of one or more files.
-R recurse into subdirectories.
-f suppress most error messages.
-v verbose output.
*/
#include "toys.h"
#define FLAG_R 4
#define FLAG_f 2
#define FLAG_v 1
DEFINE_GLOBALS(
long mode;
)
#define TT this.chmod
static int do_chmod(const char *path) {
int ret = chmod(path, TT.mode);
if (toys.optflags & FLAG_v)
xprintf("chmod(%04o, %s)\n", TT.mode, path);
if (ret == -1 && !(toys.optflags & FLAG_f))
perror_msg("changing perms of '%s' to %04o", path, TT.mode);
toys.exitval |= ret;
return ret;
}
// Copied from toys/cp.c:cp_node()
int chmod_node(char *path, struct dirtree *node)
{
char *s = path + strlen(path);
struct dirtree *n = node;
for ( ; ; n = n->parent) {
while (s!=path) {
if (*(--s) == '/') break;
}
if (!n) break;
}
if (s != path) s++;
do_chmod(s);
return 0;
}
void chmod_main(void)
{
char **s;
TT.mode = strtoul(*toys.optargs, NULL, 8);
if (toys.optflags & FLAG_R) {
// Recurse into subdirectories
for (s=toys.optargs + 1; *s; s++) {
struct stat sb;
if (stat(*s, &sb) == -1) {
if (!(toys.optflags & FLAG_f))
perror_msg("%s", *s);
continue;
}
do_chmod(*s);
if (S_ISDIR(sb.st_mode)) {
strncpy(toybuf, *s, sizeof(toybuf) - 1);
toybuf[sizeof(toybuf) - 1] = 0;
dirtree_read(toybuf, NULL, chmod_node);
}
}
} else {
// Do not recurse
for (s=toys.optargs + 1; *s; s++) {
do_chmod(*s);
}
}
}
-------------- next part --------------
/* vi: set sw=4 ts=4:
*
* chown.c - Change ownership
*
* Copyright 2012 Georgi Chorbadzhiyski <georgi at unixsol.org>
*
* See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chown.html
*
* TODO: Add support for -h
* TODO: Add support for -H
* TODO: Add support for -L
* TODO: Add support for -P
USE_CHOWN(NEWTOY(chown, "<2Rfv", TOYFLAG_BIN))
config CHOWN
bool "chown"
default y
help
usage: chown [-R] [-f] [-v] group file...
Change ownership of one or more files.
-R recurse into subdirectories.
-f suppress most error messages.
-v verbose output.
*/
#include "toys.h"
#define FLAG_R 4
#define FLAG_f 2
#define FLAG_v 1
DEFINE_GLOBALS(
uid_t owner;
gid_t group;
char *owner_name;
char *group_name;
)
#define TT this.chown
static int do_chown(const char *path) {
int ret = chown(path, TT.owner, TT.group);
if (toys.optflags & FLAG_v)
xprintf("chown(%s:%s, %s)\n", TT.owner_name, TT.group_name, path);
if (ret == -1 && !(toys.optflags & FLAG_f))
perror_msg("changing owner of '%s' to '%s:%s'", path,
TT.owner_name, TT.group_name);
toys.exitval |= ret;
return ret;
}
// Copied from toys/cp.c:cp_node()
int chown_node(char *path, struct dirtree *node)
{
char *s = path + strlen(path);
struct dirtree *n = node;
for ( ; ; n = n->parent) {
while (s!=path) {
if (*(--s) == '/') break;
}
if (!n) break;
}
if (s != path) s++;
do_chown(s);
return 0;
}
void chown_main(void)
{
char **s;
char *owner = NULL, *group;
char *param1 = *toys.optargs;
TT.owner = -1;
TT.group = -1;
TT.owner_name = "";
TT.group_name = "";
group = strchr(param1, ':');
if (!group)
group = strchr(param1, '.');
if (group) {
group++;
struct group *g = getgrnam(group);
if (!g) {
error_msg("invalid group '%s'", group);
toys.exitval = 1;
return;
}
TT.group = g->gr_gid;
TT.group_name = group;
owner = param1;
owner[group - owner - 1] = '\0';
} else {
owner = param1;
}
if (owner && owner[0]) {
struct passwd *p = getpwnam(owner);
if (!p) {
error_msg("invalid owner '%s'", owner);
toys.exitval = 1;
return;
}
TT.owner = p->pw_uid;
TT.owner_name = owner;
}
if (toys.optflags & FLAG_R) {
// Recurse into subdirectories
for (s=toys.optargs + 1; *s; s++) {
struct stat sb;
if (stat(*s, &sb) == -1) {
if (!(toys.optflags & FLAG_f))
perror_msg("%s", *s);
continue;
}
do_chown(*s);
if (S_ISDIR(sb.st_mode)) {
strncpy(toybuf, *s, sizeof(toybuf) - 1);
toybuf[sizeof(toybuf) - 1] = 0;
dirtree_read(toybuf, NULL, chown_node);
}
}
} else {
// Do not recurse
for (s=toys.optargs + 1; *s; s++) {
do_chown(*s);
}
}
}
-------------- next part --------------
/* vi: set sw=4 ts=4:
*
* chgrp.c - Change group ownership
*
* Copyright 2012 Georgi Chorbadzhiyski <georgi at unixsol.org>
*
* See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chgrp.html
*
* TODO: Add support for -h
* TODO: Add support for -H
* TODO: Add support for -L
* TODO: Add support for -P
USE_CHGRP(NEWTOY(chgrp, "<2Rfv", TOYFLAG_BIN))
config CHGRP
bool "chgrp"
default y
help
usage: chgrp [-R] [-f] [-v] group file...
Change group ownership of one or more files.
-R recurse into subdirectories.
-f suppress most error messages.
-v verbose output.
*/
#include "toys.h"
#define FLAG_R 4
#define FLAG_f 2
#define FLAG_v 1
DEFINE_GLOBALS(
gid_t group;
char *group_name;
)
#define TT this.chgrp
static int do_chgrp(const char *path) {
int ret = chown(path, -1, TT.group);
if (toys.optflags & FLAG_v)
xprintf("chgrp(%s, %s)\n", TT.group_name, path);
if (ret == -1 && !(toys.optflags & FLAG_f))
perror_msg("changing group of '%s' to '%s'", path, TT.group_name);
toys.exitval |= ret;
return ret;
}
// Copied from toys/cp.c:cp_node()
int chgrp_node(char *path, struct dirtree *node)
{
char *s = path + strlen(path);
struct dirtree *n = node;
for ( ; ; n = n->parent) {
while (s!=path) {
if (*(--s) == '/') break;
}
if (!n) break;
}
if (s != path) s++;
do_chgrp(s);
return 0;
}
void chgrp_main(void)
{
char **s;
struct group *group;
TT.group_name = *toys.optargs;
group = getgrnam(TT.group_name);
if (!group) {
error_msg("invalid group '%s'", TT.group_name);
toys.exitval = 1;
return;
}
TT.group = group->gr_gid;
if (toys.optflags & FLAG_R) {
// Recurse into subdirectories
for (s=toys.optargs + 1; *s; s++) {
struct stat sb;
if (stat(*s, &sb) == -1) {
if (!(toys.optflags & FLAG_f))
perror_msg("stat '%s'", *s);
continue;
}
do_chgrp(*s);
if (S_ISDIR(sb.st_mode)) {
strncpy(toybuf, *s, sizeof(toybuf) - 1);
toybuf[sizeof(toybuf) - 1] = 0;
dirtree_read(toybuf, NULL, chgrp_node);
}
}
} else {
// Do not recurse
for (s=toys.optargs + 1; *s; s++) {
do_chgrp(*s);
}
}
}
More information about the Toybox
mailing list