Re: [dev] Special target ".POSIX" in Makefiles
On 2021-12-30, NRK wrote: > Hmm, I was under the impression that `?=` was accepted into POSIX. But I > cannot find any mention of it in the posix manpage (man 1p make) so I > guess I was wrong. It is accepted for the upcoming POSIX issue 8: https://austingroupbugs.net/view.php?id=330
Re: [dev] tlsrp: a simple TLS reverse proxy
On 2020-07-05, Nihal Jere wrote: > I wrote a very simple TLS reverse proxy which can be used as a companion > to quark. Essentially, it just turns quark's HTTP into HTTPS. It depends > only on libtls (from LibreSSL) and libbsd (for strlcpy). Seems like a neat project. Have you considered using memccpy instead of strlcpy? I don't think it's worth adding a dependency on libbsd over such a simple function, and memccpy is POSIX (XSI) and accepted for C2x. I think it even simplifies things a bit: diff --git a/tlsrp.c b/tlsrp.c index 2766f32..c8d5d39 100644 --- a/tlsrp.c +++ b/tlsrp.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -70,13 +69,11 @@ dounixconnect(const char *sockname) int sfd; struct sockaddr_un saddr = {0}; -if (strlen(sockname) > SUN_PATH_LENGTH-1) +if (!memccpy(saddr.sun_path, sockname, '\0', SUN_PATH_LENGTH)) die("unix socket path too long"); saddr.sun_family = AF_UNIX; -strlcpy((char *) &saddr.sun_path, sockname, SUN_PATH_LENGTH); - if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) die("failed to create unix socket:"); Some other things I noticed: - You should probably use sizeof(saddr.sun_path) instead of a hard-coded assumed minimum size. - The tlsrp Makefile rule is missing a dependency on tlsrp.c and util.c. - It might be useful to have separate options for the hostname to listen on and the hostname to connect to. - I think the way to include the libtls header is #include . Some systems (including OpenBSD) don't install it in /usr/include/libressl, and the .pc file should add the appropriate include directory.
Re: [dev] [sdhcp] The problem with renewals
On 2020-03-16, Laslo Hunhold wrote: > Would you be open to work on a small patchset for it reflecting your > proposals? But before you do that, we might also just want to wait for > feedback by Michael Forney, who seems to be the current active > maintainer. I'm not the maintainer, I just sent a few patches a while back. Now that I think of it, there is still a pending patch: https://lists.suckless.org/hackers/1908/16959.html It's been a long time since I've looked at the details of DHCP. Over the past few years I have run into a few situations where sdhcp didn't work, but have not found the time to investigate them. So I can confirm that sdhcp still has some issues, just not sure if they are the same issues as Sean is reporting here.
Re: [dev] [sbase] [ed] A couple of notes
On 2020-03-22, Hiltjo Posthuma wrote: > Maybe it's an idea to just place issues in a TODO file in the repository? That's a good idea, thanks. I added a section with the issues reported by Cág, some existing items from ed.c, and a few others I have noticed.
Re: [dev] [sbase] [ed] A couple of notes
On 2020-03-21, Hiltjo Posthuma wrote: > What kind of tracker? Did you see my other reply? https://lists.suckless.org/dev/2003/33827.html >I think discussions of suckless projects should stay > on the mailinglist and/or IRC, not an external bugtracker or something. Would suckless.org consider hosting a todo.sr.ht instance? > Have you tried sending the issues to the maintainer or gently bumping it? I am the maintainer, so that wouldn't help much.
Re: [dev] [sbase] [ed] A couple of notes
On 2020-03-17, Hiltjo Posthuma wrote: > Where is the patch? I know it's contrary to the opinion of a lot of people here, but personally, I have no issue with bug reports without a patch. Sometimes people just don't have the time to investigate the issue and come up with a fix. It could even be that the fix involves more complex restructuring of the rest of the code. If the choice is between no patch, or no bug report at all, I would definitely prefer no patch. I'd like to at least be aware of places where sbase is non-conforming or buggy. I myself created https://todo.sr.ht/~mcf/sbase a while ago so I could keep track of issues that I found and have not gotten around to fixing. Of course supplying a patch should be highly encouraged, and if there is no patch the issue might not get fixed quickly, or at all, depending on its severity.
Re: [dev] [sbase] [ed] A couple of notes
On 2020-03-17, Cág wrote: > There are a couple things I've come across the > sbase's version of ed: > 1. w doesn't print the byte count. Suppose a sample > ed session (using P to distinguish my input from ed's > output): > % ed > P > *a > milk > bread > eggs > meat > veggies > bananas > apples > . > *w list > *q > % > 2. I guess using ed for huge files is not really a good > idea, however the sbase ed cannot open a 750MiB 3.5m lines > CSV file, while the GNU version can. Probably has to do > with the limits set. > > As always, I'm very pleased working with sbase and want to > thank everybody responsible for making it. Hi Cág, Thanks for the bug reports. As Hiltjo said, it would be very helpful if you could supply a patch for these issues. I think at least the first one should be pretty easy to fix. If not, feel free to use the tracker I mentioned in my other reply to make sure these issues are not forgotten.
Re: [dev] [sbase] sed 'd' command after 'r' or 'a' (POSIX interpretation question)
On 2020-01-17, Quentin Rameau wrote: >> Perhaps we should bring this up on the austin group list and get them >> to clarify the text. > > Done, let's wait and see. Thanks, Quentin! For anyone following, the clarification request is at https://www.austingroupbugs.net/view.php?id=1319
[dev] [sbase] sed 'd' command after 'r' or 'a' (POSIX interpretation question)
Hello, I recently ran into a package (dialog), which uses the following sed script to generate its dlg_config.h header: /@DEFS@/r conftest.frag /@DEFS@/d The intention is to replace @DEFS@ in the header template with the contents of a file. However, sbase sed skips writing the contents of the file since the pattern space gets deleted later on. All the other implementations I looked at *do* insert the contents of the file. Here's what POSIX says on the matter: > The a and r commands schedule text for later output. The text specified > for the a command, and the contents of the file specified for the r > command, shall be written to standard output just before the next > attempt to fetch a line of input when executing the N or n commands, or > when reaching the end of the script. If written when reaching the end > of the script, and the −n option was not specified, the text shall be > written after copying the pattern space to standard output. The > contents of the file specified for the r command shall be as of the > time the output is written, not the time the r command is applied. The > text shall be output in the order in which the a and r commands were > applied to the input. and > [2addr]d Delete the pattern space and start the next cycle. Only the cases where n or N are used or the end of the script is reached are described. So I guess the question is whether or not "start the next cycle" means "jump to the end of the script". It's not really clear to me from the POSIX description. Does anyone have any insight on this issue? I'm thinking we should probably change sbase sed to match the other implementations.
Re: [dev] [sbase] chmod -R and symbolic links
On 2019-12-23, Laslo Hunhold wrote: > On Sat, 21 Dec 2019 19:05:45 -0800 > Michael Forney wrote: > > Dear Michael, > >> I can think of two possibilities here: >> >> 1. Remove the -H, -L, and -P options from chmod, always set r.follow = >> 'H', and call chmod(3) conditional on !S_ISLINK(st->st_mode). >> 2. Keep the -H, -L, and -P options, but use fchmodat(3) instead of >> chmod(3) with AT_SYMLINK_NOFOLLOW depending on r->follow and r->depth. >> If fchmodat fails with EOPNOTSUPP, ignore that and continue. >> >> Does anyone have a strong preference for 2? I'm leaning towards 1 >> since it doesn't seem like those options are used commonly. > > I have a strong preference for 2 tbh, but it's your discretion as the > maintainer. Only because the other tools "suck" doesn't mean we should > lower our standards. Especially with the H, L and P options we found > many bugs in GNU coreutils, and keeping them in is essential if we > want to claim that we are more or less POSIX compliant. I'm only proposing removing -H, -L, and -P from chmod, not the other tools. The only POSIX option is -R, and the only use I can think of for chmod -L is if you wanted to modify the permissions of files outside the directory tree, which are pointed to by symlinks inside the tree.
Re: [dev] [sbase] wc output formatting
On 2019-11-03, Silvan Jegen wrote: > I assume it's the leading whitespace that was the problem since here[0] > the output format is given as > > "%d %d %d %s\n", , , , > > > Considering this and that [0] doesn't mention anything about alignment, > just having "%zu %zu %zu %s\n" as before seems like the right choice. Okay, that sounds good to me, and nobody else expressed an opinion, so I made this change. Thanks for your input!
[dev] [sbase] chmod -R and symbolic links
Hi, I'm looking into improving chmod(1) behavior with symbolic links. First, some background: - The mode of symbolic links is not used anywhere, and on linux, fchmodat(AT_FDCWD, path, mode, AT_SYMLINK_NOFOLLOW) on a symlink returns EOPNOTSUPP. - POSIX only specifies the -R option, and doesn't say anything about symbolic links. - coreutils and busybox chmod(1) only have a -R option. For directory traversal, they follow symlinks specified on the command-line (an error is printed if it is dangling), but don't follow symlinks encountered further down. - Most BSD chmod(1) have -H, -L, and -P options (defaulting to -P), and the filesystem *does* record the mode of a symlink, but this mode has no affect on the kernel's access checks. - sbase chmod(1) has -H, -L, and -P options (defaulting to -P), which control how recurse() traverses the directory tree. The option do *not* affect the calls to chmod(3) itself, which always follows symlinks. So currently, if sbase chmod -R encounters a dangling symlink, it always fails. I can think of two possibilities here: 1. Remove the -H, -L, and -P options from chmod, always set r.follow = 'H', and call chmod(3) conditional on !S_ISLINK(st->st_mode). 2. Keep the -H, -L, and -P options, but use fchmodat(3) instead of chmod(3) with AT_SYMLINK_NOFOLLOW depending on r->follow and r->depth. If fchmodat fails with EOPNOTSUPP, ignore that and continue. Does anyone have a strong preference for 2? I'm leaning towards 1 since it doesn't seem like those options are used commonly. -Michael
[dev] [sbase] wc output formatting
Hi, I was looking through wc.c in sbase and noticed a couple curious things about the output formatting. POSIX says the tool should write "%d %d %d %s\n", , , , When the tool was first written, it used fixed field widths, presumably to maintain alignment when multiple files were specified. " %5zu %5zu %5zu %s", , , , This seems to match what several other implementations do. In 39802832[0], this was changed to "%*.zu%*.zu%*.zu %s", 0, , 7, , 7, , with the intention of making the output POSIX compliant. '%*.zu' has a field width specifier of '*' (meaning it is passed as an argument), and a precision of '.' (equivalent to '.0', which means the value 0 produces no characters). I'm not sure exactly what the problem was, or how this was meant to fix it, but there are a few issues with this: 1. Now that the first field has no minimum width, the width depends on the number of newlines in the file, so the remaining fields are not aligned, even though that have fixed minimum widths. If we don't care about alignment, we may as well just use "%zu %zu %zu %s\n". 2. With a precision of 0, any counts with value 0 get skipped. I'm guessing this was just a mistake, and there wasn't meant to be a precision specifier at all ('%*zu'). 3. Since the field may consume the full width, we might end up with no separating whitespace between the fields. Issue 2 was fixed in bbd2b4d2[1], by changing the precision specifier to 1 "%*.1zu%*.1zu%*.1zu %s", 0, , 7, , 7, , But, 1 is the default precision for 'u' conversions, so I think a better change would be "%*zu%*zu%*zu %s", 0, , 7, , 7, , Issue 3 was fixed in 79e8e330[2], by reducing the field width to 6, and adding a leading space "%*.1zu %*.1zu %*.1zu %s", 0, , 6, , 6, , This leaves issue 1, which makes me wonder about the point of the field widths if they aren't for alignment of the output. If we don't care about alignment, I think we should just use "%zu %zu %zu %s\n". If we do care about the alignment, we should use fixed widths similar to the original code, like "%6zu %6zu %6zu %s\n". But now we've come full circle, which makes me wonder what POSIX compliance issue commit 39802832 was meant to fix. Is the leading whitespace for the first field a problem? If so, I don't think trying for alignment makes sense since we'd have to left-justify the first column, which breaks the digit alignment. Anyone have any thoughts on this? [0] https://git.suckless.org/sbase/commit/39802832af40f1a24aa362ca73e369a0cd26ecf2.html [1] https://git.suckless.org/sbase/commit/bbd2b4d2439e13d44ec7d1f55bbc84f23d256401.html [2] https://git.suckless.org/sbase/commit/79e8e330cbfbce4cbabae7c2a31846a89afdc095.html
[dev] Re: [sbase] sys/sysmacros.h and major/minor
On 2019-06-25, Michael Forney wrote: > 1. Invert the ifdef by conditionally *omitting* the sysmacros.h > include on systems that don't have it rather than including it only on > glibc. I know this includes at least OpenBSD. Does anyone know of any > others? I think this includes most BSD operating systems, so this option probably isn't a good idea.
[dev] [sbase] sys/sysmacros.h and major/minor
Since glibc 2.28, sys/types.h no longer includes sys/sysmacros.h which defines the major and minor macros. Some BSDs don't have sys/sysmacros.h, so sbase has been conditionally including sys/sysmacros.h on glibc since 99c78763[0]. However, in the upcoming musl release, it too will remove the sys/sysmacros.h include from sys/types.h[1]. To continue building with musl, glibc, and on other operating systems, we have a few options: 1. Invert the ifdef by conditionally *omitting* the sysmacros.h include on systems that don't have it rather than including it only on glibc. I know this includes at least OpenBSD. Does anyone know of any others? 2. Add a make variable to control whether sysmacros.h is included. Users on systems without sysmacros.h will have to modify this variable in config.mk or the make command-line. 3. Add a configure test to check the availability of sysmacros.h. This would be the first such configure test in sbase, and I'm sure some of you would disapprove. Personally, I wouldn't be happy with this option either, but it does seem to be the only reliable way to automatically determine whether sysmacros.h needs to be included. Unfortunately there no longer seems to be any way to write a program using major/minor that doesn't involve conditional inclusion and/or configure tests. Right now I'm leaning towards option 2 by adding -D HAVE_SYSMACROS_H to CFLAGS in config.mk, and guarding the sysmacros.h include by ifdefs. If anybody has a nice solution to this problem, please let me know. [0] https://git.suckless.org/sbase/commit/99c787631013bacf71c27dcac16d5a55b82be1c2.html [1] http://git.musl-libc.org/cgit/musl/commit/?id=a31a30a0076c284133c0f4dfa32b8b37883ac930
[dev] [ubase] Fixing passwd crash
I noticed that when passwd in ubase is changing a password, it will try to dereference a NULL pointer when /etc/shadow exists, but the user's password is not stored in /etc/shadow (i.e. marked with "x" in /etc/passwd). It will try to save the spw entry if /etc/shadow exists, even if the shadow entry wasn't used (in which case spw is NULL). I can think of a couple solutions, but I'm not sure what the right behavior is. 1. Always store the password in /etc/shadow (or tcb shadow) if it exists, so if a password in /etc/passwd is updated, it is moved to shadow and the passwd entry is replaced with "x". 2. Always store the password in the location the previous one was stored in. I'm thinking (1) might be the best option. Does anyone know what other implementations do?
Re: [dev] dwm alpha patch: const isn't a const??
On 2019-05-26, Paul Swanson wrote: > Hello, > > I've a fresh clone of dwm and the dwm alpha patch (20180613-b69c870) and > it's generating > the following error: > > dwm.c > In file included from dwm.c:280:0: > config.h:24:27: error: initializer element is not constant > [SchemeNorm] = { OPAQUE, baralpha, borderalpha }, >^~~~ > config.h:24:27: note: (near initialization for ‘alphas[0][1]’) > config.h:24:37: error: initializer element is not constant > > What I can't understand, is the fact that 'baralpha', and all the other > variables > accused of not being constants are in fact declared as "static const > unsigned int": > > static const unsigned int baralpha = 0xd0; > static const unsigned int borderalpha = OPAQUE; > > If I substitute the initialising variables for a numeric literal (ie. 1) it > compiles. > But if I leave the constants from the patch or make my own, it fails. > > How can a const, not be a const? > > Any help would be greatly appreciated. I'm not familiar with the alpha patch, but in standard C, initializer elements need to be constant expressions, which is different from an identifier for a const-qualified object. See http://port70.net/~nsz/c/c99/n1256.html#6.6p7 for what is allowed in initializers for static objects. Perhaps the author of the patch was using a compiler that allows these initializers (it looks like gcc-8 does, but gcc-7 does not). If you want a portable way to use an identifier in an initializer for a global, you have to use a preprocessor define like `#define baralpha 0xd0`, or enum constant like `enum { baralpha = 0xd0 };`.
Re: [dev] Yet another C compiler
On 2019-05-20, sylvain.bertr...@gmail.com wrote: > Sadly, gcc-4.7 does not have an aarch64 backend and it's a pain to > configure > without breaking anything. I wonder what the state of ARM/aarch64-4.7-branch is: https://gcc.gnu.org/viewcvs/gcc/branches/ARM/aarch64-4.7-branch/ It doesn't look like this branch is exported in the git mirror, but maybe if I can figure out git-svn, I can merge it into my branch. > Last time I tried to bootstrap, gcc 8 was not compiling with gcc 4.7 on > x86_64, > did you test it with gcc 9? Yes, I tested building gcc-9.1 with gcc-4.7.4 built by my compiler. I have not tried gcc-8. > What you say is good news, I may be able to add again a "gnu C" bootstrap to > my > custom distro (may burn some sh scripts to kill the GNU autotools in gcc > 4.7 > then). At least gcc tracks the autotools-generated files in the repository, so you don't actually need them installed to build. > You can replace inline asm: > - machine code from an independant assembler, for big asm chunks. > - with many extension keywords ("intrinsics"). A good idea is to make > addition of a keyword with their "machine code conversion" kind of > pluggable: I know it would have many limitations (llvm is literally > brain diarhea on this) but it can circumvent many inline asm snippets > this way. linux would be the primary target for this. > - to a certain extend, you could patch the target source code if > its authors are fine with it, (asm->plain and simple C, or > C11->simpler C). The issue is for lower level code that can't be written in C, for example making system calls. I don't think inline asm will be too difficult to implement in QBE. For the most part I think it can be treated similarly to a function call, but with a special calling convention. > I really need to check Quentin's QBE again. Yes, it has improved a lot in the past few months. > What you do is great work, keep going while real life let you. Thanks!
[dev] Yet another C compiler
Hi all, I know there are a number of small C compilers out there in various states of completion, but recently I've been working on another to add to the mix: https://git.sr.ht/~mcf/cc It is a C11 compiler based on QBE. The name is not yet chosen. I hope to differentiate it from the others by focusing on compiling lots of real world software in various environments. In particular, most suckless software builds and works with an occasional tweak or two (dwm, dmenu, st, sbase, ...). I've also been able to build some other toolchain components including binutils and gcc-4.7 (which can then be used to bootstrap to gcc-9). It is not yet able to build musl libc due to lack of inline asm, volatile, and long double support, but I hope to add those features if QBE gains support for them. My ultimate goal is to use it as the system compiler for oasis (https://github.com/michaelforney/oasis). Currently, the following targets are supported: - x86_64-linux-musl - x86_64-linux-gnu - x86_64-freebsd - aarch64-linux-musl - aarch64-linux-gnu If you're interested in helping, probably the best way is to try to build your favorite software and report any issues to the bug tracker at https://todo.sr.ht/~mcf/cc-issues (checking for existing issues first, of course).
Re: [dev] key-value config reader
On 2019-05-12, Markus Wichmann wrote: > On Sat, May 11, 2019 at 08:52:32PM +0100, Piotr Oleskiewicz wrote: >> I would prefer to >> write >> >> X(int, i, 1) >> >> rather than >> >> X(int, i, atoi, "%d", 1) >> >> Many thanks, >> Piotr >> > > That is going to be tough, as in C in a macro, there is no way to really > determine what type name you were given. The only thing standard C has > to offer to help is "sizeof", but that doesn't help you, obviously. > (sizeof(float) == sizeof(int)). What about _Generic in C11? This allows you to choose an expression based on the type of another expression. So I think something like the following should work: diff --git a/kv.h b/kv.h index 4a0be52..57facce 100644 --- a/kv.h +++ b/kv.h @@ -23,7 +23,7 @@ atoc(char *str) { return strlen(str) > 0 ? str[0] : '\0'; } -#define X(type, name, parse, format, init) \ +#define X(type, name, init) \ type name; typedef struct { KV @@ -33,7 +33,7 @@ typedef struct { kv kv_init() { kv c; -#define X(type, name, parse, format, init) \ +#define X(type, name, init) \ c.name = init; KV #undef X @@ -42,8 +42,13 @@ kv_init() { void kv_print(FILE *f, kv c) { -#define X(type, name, parse, format, init) \ - fprintf(f, "%s = "format"\n", #name, c.name); +#define X(type, name, init) \ + fprintf(f, _Generic((type){0}, \ + char *: "%s = %s\n", \ + double: "%s = %f\n", \ + int: "%s = %d\n", \ + bool: "%s = %d\n" \ + ), #name, c.name); KV #undef X } @@ -51,9 +56,14 @@ kv_print(FILE *f, kv c) { void kv_read(FILE *f, kv *c) { char k[MAXLEN], v[MAXLEN]; -#define X(type, name, parse, format, init) \ +#define X(type, name, init) \ if(strncmp(k, #name, MAX(strlen(k), strlen(#name))) == 0) \ - c->name = parse(v); + c->name = _Generic((type){0}, \ + char *: strdup, \ + double: atof, \ + int: atoi, \ + bool: atob \ + )(v); while(fscanf(f, "%s = %s\n", k, v) == 2) { KV }
Re: [dev] miniyacc
On 2019-05-08, Daniel Cegiełka wrote: > • lack of {% and %} which is quite common (license): > https://github.com/openbsd/src/blob/master/usr.bin/awk/awkgram.y > • I don't even know what else: > https://github.com/9fans/plan9port/blob/master/src/cmd/hoc/hoc.y#L32 I think these are both the same problem, lack of comment support in the tokenizer. The '{%' and '%}' are present, just after the license comment. It should be a pretty easy fix, and I'm sure mpu would appreciate a patch.
Re: [dev] miniyacc
On 2019-05-07, Daniel Cegiełka wrote: > Hi, > > I'm going to use Quentin's miniyacc with (for example) bc.y from Plan 9: > https://github.com/9fans/plan9port/blob/master/src/cmd/bc.y > > Of course, I had to modify the code (a bit), but unfortunately I still > get an error when using miniyacc - works correctly with yacc from > OpenBSD and Plan 9. > > I'm getting a message from this place ("production rule too long"): > https://c9x.me/git/miniyacc.git/tree/yacc.c#n1110 > > I tried to increase the value of IdntSz and MaxRhs, but it didn't help > in any way. It looks like this error is caused when miniyacc encounters a character that it doesn't recognize as a token. nexttk() returns a zero-length TIdnt token, causing an infinite loop, filling up r->rhs. Try the attached patch, which makes it fail on invalid tokens. In the example bc.y you linked, I think the '={' is causing problems, and is from an obsolete yacc syntax: Some implementations recognize "={" as equivalent to '{' because it appears in historical documentation. This construction was recognized and documented as obsolete as long ago as 1978, in the referenced Yacc: Yet Another Compiler-Compiler. This volume of POSIX.1-2017 chose to leave it as obsolete and omit it. I also ran into this problem on some other grammar files containing comments. One other issue I noticed is miniyacc doesn't seem to handle escape sequences in literals (i.e. '\n'). After working around those issues, I get a different error $n has no type (on line 171) I think this is due to the usage of $2 referring to a token (EQOP in this case) rather than a non-terminal. I haven't investigated this further. From 2c333b66bcbf4278bd5d080a6722aad704160905 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Wed, 8 May 2019 01:14:57 -0700 Subject: [PATCH] Fail on invalid token Reading a zero-length TIdnt token causes infinite loops or other failures. --- yacc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yacc.c b/yacc.c index 01f054e..8ea5137 100644 --- a/yacc.c +++ b/yacc.c @@ -837,6 +837,8 @@ nexttk() die("identifier too long"); c = fgetc(fin); } + if (p == idnt) + die("unknown token"); *p = 0; if (strcmp(idnt, "%")==0) if (c=='{') -- 2.20.1
Re: [dev][sdhcp] more updates
On 2019-02-02, Sean MacLennan wrote: > First a question: how portable do we want things? The current sdhcp > works only on Linux. I think that depends on how feasible it is to make it portable without relying on a bunch of ifdefs to support different platforms. In terms of timerfd, I think it should be okay to use POSIX timers and a self-pipe (like that patch I sent you a while back), but it is kind of ugly to have to recreate the timers after the fork. Personally, I don't see much value in having sdhcp fork; I always run it with a service supervisor. CLOCK_BOOTTIME is pretty important for being able to resume from suspend, but I'm not sure how portable this is. It looks like OpenBSD has it, but not FreeBSD. Maybe this could be an option in a config.h? > * calctimeout() was dividing the timeout by 2. Not sure why so I > removed it. Also, the check for less than 60 seconds would only > work if you went back in time to Jan 1, 1970 for the first minute > after midnight. Check the comment for the calctimeout() function. It sets the itimerspec passed by the caller to half-way until the expiration of the specified timer. The struct itimerspec here specifies a time *duration*, not a time instant, so I don't think 1970 has anything to do with it. The function uses timerfd_gettime to determine the duration of time left until timer `n` expires, then sets `ts` to half of that duration, down to a minimum of 60 seconds. This is what RFC 2131 says to do: In both RENEWING and REBINDING states, if the client receives no response to its DHCPREQUEST message, the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state) and one-half of the remaining lease time (in REBINDING state), down to a minimum of 60 seconds, before retransmitting the DHCPREQUEST message.
Re: [dev] using vis (libtermkey) and netbsd-curses (was: oasis: small linux system inspired by stali)
Hi Daniel, On 2018-11-24, Daniel Cegiełka wrote: > Hi, > > https://lists.suckless.org/dev/1811/33025.html > > I prepared a more detailed description of how to compile vis + > netbsd-curses. > > 1) copy from ncurses/ncurses/names.c strnames & strfnames: > > DCL(strnames) = { > "cbt", > "bel", > (...) > "box1", > (NCURSES_CONST char *)0, > }; > > DCL(strfnames) = { > "back_tab", > "bell", > (...) > "box_chars_1", > (NCURSES_CONST char *)0, > }; > > > 2) replace ncurses macros (DCL etc.) with C declarations: > > const char *strnames[] = { > "cbt", > "bel", > (...) > "box1", > NULL, > }; > > const char *strfnames[] = { > "back_tab", > "bell", > (...) > "box_chars_1", > NULL, > }; When I looked into this, I went with a slightly different approach. Instead of copying from ncurses, I generated the arrays from term.h and an awk script. awk ' /TICODE_[a-z]+,/ { names[++numnames] = substr($1, 8, length($1) - 8) } /^#define t_[a-z_]+(t)/ { fnames[++numfnames] = substr($2, 3, length($2) - 5) } END { print "const char *const strnames[] = {" for (i = 1; i <= numnames; ++i) print("\t\"" names[i] "\",") print "\t(void *)0" print "};" print "const char *const strfnames[] = {" for (i = 1; i <= numfnames; ++i) print("\t\"" fnames[i] "\",") print "\t(void *)0" print "};" } ' libterminfo/term.h > libterminfo/names.c > > 3) edit driver-ti.c (libtermkey) and include names.c: > > #ifdef HAVE_UNIBILIUM > # include > #else > # include > # include > > /* strnames and strfnames */ > #include "names.c" > > /* curses.h has just poluted our namespace. We want this back */ > # undef buttons > #endif You don't need to include the whole names.c in term.h, just declare the arrays: diff --git a/libterminfo/term.h b/libterminfo/term.h index 884cfe9..8345a7f 100644 --- a/libterminfo/term.h +++ b/libterminfo/term.h @@ -1944,6 +1944,8 @@ extern "C" { #endif extern TERMINAL *cur_term; +extern const char *const strfnames[]; +extern const char *const strnames[]; /* setup functions */ intsetupterm(const char *, int, int *); > vis works fine, however, there is a problem when I use ':!' or ':e *'. > I think that the terminal settings are not restored. Does anyone have > an idea here how it can be solved? I can confirm the issue here. No idea about how to solve it though. Compared to ncurses, I also notice a bit of flickering when scrolling fast (status bar occasionally blinks). I remember this problem being more severe back when I looked into this, so I had decided to stick with ncurses for oasis for the time being.
Re: [dev] [sdhcp] Part 1/3 Bugs
On 2018-11-12, Sean MacLennan wrote: > I am surprised you are getting away with binding the socket to the > broadcast address. I found in ip(7): INADDR_BROADCAST (255.255.255.255) means any host and has the same effect on bind as INADDR_ANY for historical reasons. So that explains why it worked. BTW, is there going to be a part 3/3?
Re: [dev] GPL free Linux
On 2018-11-13, Markus Wichmann wrote: > On Mon, Nov 12, 2018 at 01:14:38PM -0800, Michael Forney wrote: >> Usually how it works is either the display server itself needs to be >> setuid to open those input devices, or some other program (commonly >> systemd-logind) needs to open it on its behalf. I believe Xorg with >> systemd disabled will need to be setuid because of this. >> > > I lack the words to describe how broken I think it is, to make an > application setuid because you couldn't be arsed to set file permissions > properly. Or at least, the words to do so in a civilised manner. Well, you usually don't want just any process to be able to open your keyboard device and read events from it; just the display server and only when the VT it is running on is active. This is especially true on a multi-user system. So, you want opening input devices to be privileged or federated in some way. There is also a problem with DRM, since while you can become master (required for modesetting) implicitly if no other process is master, you need CAP_SYS_ADMIN to be able to issue the ioctls to drop/regain master. This makes it impossible to do VT switching properly as non-root (see https://github.com/mpv-player/mpv/issues/6184 for example).
Re: [dev] GPL free Linux
On 2018-11-12, Alessandro Pistocchi wrote: > What is swc? My wayland compositor library: https://github.com/michaelforney/swc > Where can I find oasis? Would you be interested in helping a bit if I needed > help starting from oasis and removing gpl/lgpl stuff? I am ok with gpl apps > but not with libs... https://github.com/michaelforney/oasis I won't be removing GPL/LGPL packages just because of the license, but you don't have to install them if you don't want them. You can also just comment out what you don't want in pkg/gen.lua to make sure they don't get pulled in by something. The core set of packages (required for bootstrap and basic system operation) doesn't use any GPL/LGPL libraries, but does include some GPL applications (bc, e2fsprogs, git, iproute2, kbd, util-linux) and plan9port (Lucent Public License 1.02). Going through the package list, the libraries will likely have problems with are: - libelf from elfutils (LGPLv3), required to build linux - efivar (LGPLv2.1), required by efibootmgr (GPLv2) - libfuse (LGPLv2.1), required by sshfs (GPLv2) - libnl (LGPLv2.1), required by wpa_supplicant (BSD-3, but libnl is linked statically, so also LGPLv2.1) - jbig2dec (AGPLv3), required by mupdf (AGPLv3) - ffmpeg (LGPLv2.1 or GPLv2, depending on what's enabled), required by mpv (also GPLv2 or LGPLv2.1 depending on what's enabled). - alsa-lib (LGPLv2.1), required by alsa-utils (GPLv2) and mpv (licenses were determined by looking briefly at https://repology.org/)
Re: [dev] GPL free Linux
On 2018-11-12, Markus Wichmann wrote: > On Mon, Nov 12, 2018 at 11:17:49AM +, Alessandro Pistocchi wrote: >> I would use some help to make it work with X ( does it work with >> Wayland? ). There are not many docs I found about it... > > Ah, that old chestnut. As far as I know, the X input driver "evdev" > depends on the paths of the event devices being in /dev/input, and on > you having read access to them. I don't know if smdev puts them there by > default, nor how it sets the permissions on those files. Also, there's a > dependency on libudev in there somewhere. I don't know if that can pick > up files from smdev. I don't know about smdev, but if your /dev is a devtmpfs, the kernel will create those devices automatically with permissions 600 root:root. I run a system without any hotplug daemon, just CONFIG_DEVTMPFS and CONFIG_DEVTMPFS_MOUNT, and a script that runs at startup to set /dev/dri/* to 660 root:video and /dev/snd/* to 660 root:audio. > The files should be named according to the links in /sys/class/input. > You should also be able to see the error messages in X11's log file. > That should tell you what's wrong. And if all else fails: strace. > > I have no experience with Wayland but I suppose it requires a similar > setup. Not having read permission on a device file is a showstopper no > matter the codebase. Usually how it works is either the display server itself needs to be setuid to open those input devices, or some other program (commonly systemd-logind) needs to open it on its behalf. I believe Xorg with systemd disabled will need to be setuid because of this. Wayland compositors work the same way. They either run setuid so they can open devices themselves, communicate with systemd-logind to get device FDs, or with some parent setuid "launcher" program which opens the devices for them. For swc, I went with the third approach. Regarding hotplugging and libudev, most wayland compositors use libinput to handle input devices, which uses libudev to detect when devices are added or removed. I believe libudev *does* work without udevd running (not completely sure). However, you can also just listen to netlink uevents to do the same thing. I maintain a branch of libinput that does exactly this: https://github.com/michaelforney/libinput/blob/master/src/netlink-seat.c Xorg seems to work similarly, and you might be able to avoid libudev and retain hotplug support by writing a "netlink" config backend here: https://cgit.freedesktop.org/xorg/xserver/tree/config >> I want to have a windowing system, compilers and libraries mainly. >> Also I need make and I would like to have flex and bison. Maybe a web >> browser and a graphical IDE for source code editing but I am not even >> sure about that. > > I was going to ask "Why not just use sta.li?" but that project > apparently doesn't exist anymore. > > And that is pretty much exactly what I want from a distribution as well, > and I just use Debian (you know you can just remove systemd from Debian, > right?) My own oasis project has all of those components and was inspired by sta.li, though avoiding GPL has not been a primary goal. It has some main components that are GPL including gcc, e2fsprogs, git, iproute2, kbd, fuse, and netsurf.
Re: [dev] Some questions about sdhcp
On 2018-10-11, Markus Wichmann wrote: > Hi all, > > I recently read the source code of sdhcp, and it does seem to be a nice > tool, but I couldn't help but notice a few things. Now, maybe I'm dense, > and none of the things I'm about to bring up matter for some reason, and > if so, that would be really cool. But some of these really do seem like > major issues, so here goes: Hey Markus, I have a branch of sdhcp[0] I'm using for oasis that fixes some of these issues. I didn't send them to the ML though since they were linux-specific (timerfd, CLOCK_BOOTTIME, ...), and I wasn't sure if sdhcp was meant to work on other systems as well. It's been a while since I looked at it, but sdhcp has mostly been working fine for me since then. Though, there have been a couple of occasions where I wasn't able to connect for whatever reason, so I keep a build of ISC dhclient as a backup. It'd be nice to get any remaining issues resolved. [0] https://github.com/michaelforney/sdhcp > 1. Timeout based on alarm() > --- > > That is, in principle, not a bad way to do it, but unsuitable for a > laptop application, which might see extended time spent in a sleep > state. This is mostly an issue during the Bound state, as I have no idea > if the alarms get adjusted for the time slept, and what happens if the > alarm times out during sleep. > > That said, I also have no idea what happens to monotonic clocks, so what > the heck. > 2. Signal handlers established with signal() > > > Unfortunately, the BSD-v-SysV war has destroyed that interface beyond > usability. On Linux, it depends on the libc, and for glibc also on the > compiler flags, whether you get oneshot behavior or persistent behavior. > So now we have to use sigaction() to establish signal handlers, or > always re-establish the handlers from within, just in case. > > musl gives the BSD behavior always, BTW. > > 3. Broken timing model > -- > > The code reads the value from the Lease Time option into a variable > called "t1", and proceeds to use that variable as T1 (i.e. the time > after which the lease should be renewed). That is not what the lease > time is! > > The RFC states that after the lease time has elapsed, the client must no > longer use the address granted to it, and failing to do so was the > reason why many Apple devices where banned from some Ivy League campus > network or other, some years back; which was a great source of humour > for me and others. Yet here we are, doing the same thing wrong. > > The RFC states that T1 is specified in option 58, and T2 in option 59. > Failing these, T1 is 1/2 lease time, and T2 is 7/8 lease time. Apropos > failing: > > 4. Christian search routines > > > The Bible states "Seek and you will find" but it might not be a > great idea to implement this in a computer program. Unfortunately, > optget() has absolutely no way of communicating failure to find a given > option, and its callers don't seem to care much, either way. "Be lenient > in what you accept" is all well and good, but not when the most > important pieces of data are missing. > > 5. Absolutely no timeout in Renewing and Rebinding states > - > > I couldn't find info on what happens after an alarm fires, but the only > behaviors that make any sense are (a) alarm() is oneshot, and (b) > alarm() is cyclical. Once sdhcp has made it into Bound state, an alarm() > for the lease time is registered. When that fires, no further alarm is > registered as sdhcp sends out a single request for renewal. If that > packet, or the acknowledgment of it, drops for any reason, we're stuck > in Renewing with either no timeout, if (a) is true, or one lease time > (typically something like 1 day) as timeout, if (b) is true. > > The RFC states that the client should set the packet timeout in these > states to half the remaining time (until T2 or lease time), down to one > minute. > > 6. No XID reroll or comparison > -- > > The XID is rolled once, at the start of the process, and never rolled > again. Shouldn't a different XID be used for each separate transaction? > That might be down to taste, but this one is not: XID is never compared > to the XID of a received packet. And neither is the CID. Thus, sdhcp > ends up stealing people's leases! I mean, the whole protocol is > broadcast, we're bound to see a packet that wasn't meant for us. > > 7. Use of the realtime clock for time measurement > - > > For some reason I don't quite get, DHCP clients are required to send the > time they spent working in the packet header. Well, not required; we > could just null the field. But since we do send something, we might as > well do it right. Currently, the time is measured by way of the time() > function, which returns the current realtime clock value.
Re: [dev] [bc]
On 2018-03-13, Laslo Hunhold wrote: > On Tue, 13 Mar 2018 13:44:08 -0600 > Gavin Howard wrote: >> About GNU extensions: this was originally implemented for toybox >> (http://landley.net/toybox/), and the maintainer specifically asked >> that my bc be able to run >> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/time/timeconst.bc >> which has basically every GNU extension. Thus, my bc will probably not >> fit the suckless philosophy because the GNU extensions need to stay. >> Thanks, though. > > Toybox is a one-man operation and it shows in the code. I'd rather > recommend busybox to anyone, and I hate busybox! > You as a developer need to decide how you want to write your code. It's > a mistery to me why you presented it here when you are not planning to > even remove some of the insane GNU-extensions. I know next to nothing about bc and what GNU extensions are used by timeconst.bc, but being able to build a linux kernel sounds like a good goal to me. However, if timeconst.bc can be changed to use only portable features of bc (in a way that is acceptable to upstream), I think that would be better than implementing the GNU extensions. Currently sbase (and GNU make/bc) is almost sufficient for building linux, except for - Usage `-n` flag in ln(1), which I think we should add. - Usage of `\t` in sed bracket expressions. I sent a patch and it was accepted, so this should be fixed in a future linux version (maybe 4.17?). - Usage of `stat -c "%s"` to determine file size. I sent a patch to use `ls -dn`, but still need to respond to some comments.
Re: [dev] securiy guidance
On 2018-03-07, pet...@riseup.net wrote: > Looking at the chacha API one needs to use a nonce, in the monocypher > implementation it is 24 bits wide, which would give the option of almost > 17M runs with a single key. IIUC adding a salt would further randomize > the output and possibly prevent some other forms of attacks but won't > replace the nonce as the salt cannot be secret either. It is actually 24 *bytes*, so 192 bits. My understanding is that the difference between ChaCha20 and XChaCha20 is the extended nonce size (ChaCha20 uses a 64-bit nonce). This is big enough to select at random and be confident there won't be a collision. See the nonce description in https://monocypher.org/manual/crypto_chacha20_init.html#DESCRIPTION
Re: [dev] securiy guidance
On 2018-03-07, pet...@riseup.net wrote: > On 2018-03-07 00:23, Michael Forney wrote: >> Another related project I've been following is https://monocypher.org/ >> >> It has a quite permissive license and encourages inlining the source >> like you want. > > Hi Michael, > > thanks, this looks really nice and small. I'm doing my homework reading > crypto 101 and getting to know what do I actually need for proper > encryption. It would seem that I'll be fine with a symmetric-key algo > and I'll have to encrypt the secret key using a master password. I see > xchacha20 in monocypher but I have to yet read up if it is safe to use > with a single key, i.e. encrypting n passwords with the same secret key. I'm no expert either (so follow this at your own risk), but I also did some investigation, and I think either of the following schemes would work: (1) Setup: - Generate a random salt and store somewhere safe. Encryption: - Read the salt from its location and the master password from the console. Use those to generate a key with crypto_argon2i. - Read password from the console (or generate randomly) and encrypt it with the key and a randomly generated nonce using crypto_lock. - Write the mac, nonce, and encrypted password to a file. Decryption: - Read the salt from its location and the master password from the console. Use those to generate a key with crypto_argon2i. - Read the mac, nonce, and encrypted password from the file. - Decrypt the password using the mac, nonce, and key using crypto_unlock. It's not clear to me if it's okay to use the plain crypto_argon2i with just a fixed secret salt. A related scheme might be to use crypto_argon2i_general with a salt generated for each encryption and a single saved key. Then, the salts could be stored as plain text the output file (and probably authenticated with crypto_lock_aead). Perhaps one benefit is if someone somehow figured out the encryption key for one password, they still wouldn't be able to decrypt the others. (2) Setup: - Generate a random salt. - Read a master password from the console and generate a master key from it and the salt using crypto_argon2i. - Use crypto_key_exchange_public_key to compute the master public key from the secret key. - Save the salt and the master public key somewhere safe. Encryption: - Read the master public key from its location. - Randomly generate a single-use key, and compute a shared key from it and the master public key using crypto_key_exchange. - Compute the single-use public key using crypto_key_exchange_public_key. - Read password from the console (or generate randomly) and encrypt it with this shared key, a randomly generated nonce, and the single-use public key as additional data using crypto_lock_aead. - Write the mac, nonce, single-use public key, and encrypted password to a file. Decryption: - Read the salt from its location. - Read a master password from the console and compute the master key from it and the salt using crypto_argon2i. - Read the mac, nonce, single-use public key, and encrypted password from the file. - Compute the shared key from the single-use public key and the master key. - Decrypt the password using the mac, nonce, single-use public key, and shared key using crypto_unlock_aead. For (2) I'm not sure if the nonce is necessary or not, since passwords are encrypted with randomly generated single-use keys (so maybe a fixed value is sufficient; it is still only used once per key). The main differences are that (1) requires the master password for every encryption, but not setup, and (2) requires the master password only for setup. I think (2) is more similar to how gpg works. Perhaps somebody who knows more about these crypto primitives could point out any flaws with these schemes.
Re: [dev] securiy guidance
On 2018-03-06, pet...@riseup.net wrote: > On 2018-03-06 10:01, Truls Becken wrote: >> Some libraries to look at are; libressl, libtomcrypt, nacl.cr.yp.to, >> libsodium, nettle, libgcrypt and libmcrypt. > > Hello Truls, > > thank you for this list. I was hoping there would be a publicly > available algo that could be inlined in the source since I really only > need 1 algorithm, not a whole suite. > > If sticking to libraries, is there any one you recommend most? > Preferably non-GPL. Another related project I've been following is https://monocypher.org/ It has a quite permissive license and encourages inlining the source like you want.
Re: [dev] Some suckless hackathon 2017 preparation
On 2017-09-01, Silvan Jegen wrote: > On Fri, Sep 01, 2017 at 08:40:34AM -0400, Carlos Torres wrote: >> > On Aug 30, 2017, at 2:07 PM, Silvan Jegen wrote: >> > >> > * Wayland dwm prototype? >> > * Suckless Wayland client library prototype? >> >> I think Michael Forney has already addressed these issues. > > Yes, I am aware of those. > > I assume we will have another look at those to see if suckless is > interested in the apporach taken within them or not. The wl-st Michael > wrote has diverged quite a bit from upstream so one goal could be to > merge them back? Not sure. Just to give an update on this: It's not that my st branch has diverged from upstream (in fact, I've tried hard to make the differences as small as possible). It was quite difficult to keep up with changes to master because st was just a single >4k line file with X11 calls mixed in throughout. Every change was a tricky merge conflict. I attempted to separate the X11-specific stuff into x.c, but have not had a chance to rebase my changes after this split. If anyone plans to work on this, I suggest rendering with pixman and freetype rather than wld, which has quite limited font support (I have plans to replace it with something else in the future). I hope the wayland-related work at the hackathon won't just be duplicates of my efforts.
Re: [dev] [ANN] samurai: ninja-compatible build tool
On 7/26/17, Anselm R Garbe wrote: > On 26 July 2017 at 09:05, Silvan Jegen wrote: >> That's what I suspected. Not sure it's desirable to ever work on a >> codebase big enough to require a build system which uses ninja under >> the hood. If I find myself in such a position I will turn to samurai >> first. > > Out of curiosity, what is the point of a build system like ninja, if > the codebase requires to be complex? ninja doesn't require the codebase to be complex, but does tolerate it. Anyway, I'm a little suprised about the distaste for ninja since it's features are pretty much the same as POSIX make (variable assignments and rule definitions). The main differences being - In make, variable assignments are evaluated only when used. In ninja, they are evaluated at the assignment. - In make, inference rules are used to run the same command template for many different targets. In ninja, rules specify the command-template and build lines invoke the rule. - In make, a new scope (to change CFLAGS/LDFLAGS for instance) can effectively be introduced with a recursive call to make. In ninja, you can include another ninja file with a new scope using `subninja`. - make is standardized and ninja is not. In oasis I'm using ninja like you're use stali.mk in stali. The advantage is that dependencies are tracked throughout all packages (not only within a package and between packages), so I can edit a file in some library (libcurl for instance), and git, mupdf, and netsurf all get rebuilt automatically. The disadvantage of course is it's not a standard UNIX tool. > Isn't the issue to be tackled the > codebase complexity then? Yes ideally projects like llvm and chromium would instead focus on codebase complexity. But the argument that ninja is bad because bad projects use it does not make sense to me.
Re: [dev] [ANN] samurai: ninja-compatible build tool
On 7/25/17, Silvan Jegen wrote: > Hi > > On Wed, Jul 26, 2017 at 7:32 AM, Michael Forney > wrote: >> Over the past couple weeks, I implemented a ninja-compatible build >> tool in C. It is much simpler and smaller than ninja and seems to >> perform at least as well. >> >> https://github.com/michaelforney/samurai >> >> It has all the features I care about, apart from gcc -MD header >> dependency parsing which is planned. I replaced ninja with samurai in >> oasis to remove the C++ dependency. > > https://ninja-build.org/manual.html#ref_headers > > I assume it's this functionality that is still missing, correct? Correct. >> Even if you don't care for ninja, it does seem to be gaining >> popularity, and I've noticed several projects start switching from >> autotools to meson (which outputs ninja), so I thought it would be >> good to have a small C implementation. It was also a fun project. > > I have seen that some of the Wayland projects I care about are working > on switching to meson but I did not know that it uses ninja under the > hood. > > Since you seem to have plenty of experience with ninja, do you think > it has any advantages over using a Makefile containing 20-50 lines of > code? No, not at all. Definitely use a Makefile for that case.
[dev] [ANN] samurai: ninja-compatible build tool
Hi all, Over the past couple weeks, I implemented a ninja-compatible build tool in C. It is much simpler and smaller than ninja and seems to perform at least as well. https://github.com/michaelforney/samurai It has all the features I care about, apart from gcc -MD header dependency parsing which is planned. I replaced ninja with samurai in oasis to remove the C++ dependency. Even if you don't care for ninja, it does seem to be gaining popularity, and I've noticed several projects start switching from autotools to meson (which outputs ninja), so I thought it would be good to have a small C implementation. It was also a fun project.
[dev] git://git.suckless.org not accepting connections
Hi, I noticed that git.suckless.org is no longer accepting connections with the git protocol. HTTP still works though. Just pointing that out in case it wasn't a deliberate change. -Michael
Re: [dev] [sbase] Changing BUFSIZ
On 6/13/17, Mattias Andrée wrote: > On Linux, the performance of cat(1) can be doubled > when cat(1):ing from one pipe to another, by compiling > with -DBUFSIZ=(1<<16) (the default pipe capacity). > This is close to optimial for a read(3)/write(3) > implementation. Agreed. On my sbase branch, I bumped it up to 8192 (from 1024 on musl) and noticed significant performance improvements. Speaking of a read(3)/write(3) implementation, I should ping my IO improvement patch series thread...
Re: [dev] oasis: small linux system inspired by stali
On Tue, Mar 28, 2017 at 3:34 AM, Kamil Cholewiński wrote: >> I think it might have been possible to use some other build tool to >> achieve something similar, but I don't think it would have worked out >> as well. > > http://gittup.org/tup/ ? I think tup could have worked too, but I still prefer ninja for a few reasons: - tup uses fancy trickery to calculate dependencies of commands using a fuse filesystem. This requires setuid or user namespaces to work correctly, or else runs in a "degraded" mode (though, not quite sure how this works). - tup has more dependencies (sqlite, libfuse, lua), and as a result, larger binary size (1.4M vs 908K for static stripped binary built with -O2). - tup has a more complicated language because it is intended to be written directly instead of generated by something else. I'd have to do some experimentation to see if it could replace the rc scripts, or if I'd have to use the lua API.
Re: [dev] oasis: small linux system inspired by stali
On Mon, Mar 27, 2017 at 2:44 PM, Marc André Tanner wrote: > Hi Michael, > > Overall I like your package selection, but I also have a few questions: > > * Did you consider using netbsd-curses[1] instead of ncurses? > >This probably won't work as is, because libtermkey as required by >vis depends on the ncurses terminfo library. It might be worth >investigating how much work it would be to either port libtermkey >or provide the necessary terminfo symbols in netbsd-curses. I have not. I actually was originally very hesitant to include any curses library at all, since it seems to me like the wrong layer to implement a graphical UI (instead going the route of acme + 9term). If you find a way to use netbsd-curses (or maybe no curses at all; I saw you added a vt100 UI to vis), I'd be interested. > * What is the justification for using ninja (I'm not really familiar >with it). It seems like the only (non-toolchain) package requiring >C++. Furthermore, you mentioned that you might write a compatible >C replacement at some point, hence it must obviously be better than >other existing alternatives. I am actually quite happy with how the rc/ninja based build system worked out. In my experience, ninja is quite good as a low level build tool. The language itself is extremely simple, and the tool handles projects with several thousand build actions with ease (since it was designed for chromium). This makes it really easy to hack on some package a bit, and build incrementally. Since dependencies (including C header dependencies) are tracked across the entire system, relinking due to a static library change is easy and automatic, and everything is always up to date. I think it might have been possible to use some other build tool to achieve something similar, but I don't think it would have worked out as well. > * Did you try how much of the system can be built using a C only >toolchain like cparser+libfirm? I did try cparser/libfirm at one point in the project's infancy and I was surprised at the amount of stuff that built no problem. I have since added more packages though, so can't give you a recent answer. I also spent a week or so a while ago fixing some bugs in scc to try to get it to build sbase. I think it would be really cool to be able to build the core system (or more!) with a lighter toolchain. > * Why did you settle for perp instead of s6[2]? Again I'm not really >familiar with either of them (besides reading their respective >websites etc.). Just curious, it would be interesting to get your >reasoning behind the package selection process. I tried both a couple of years ago, and liked perp more. It seemed simpler and smaller in scope than s6. s6 has its own scripting language and quite a lot of extra tools. Although, I have to admit, one contributing factor is that the s6 tool names are just a pain to type. Though s6 is definitely more actively maintained and more popular, so I may take another look at some point. I would not object if someone wanted to package it as an alternative. > * Will you consider using BearSSL in the future, once it gets a bit >more mature? Of course, although there are a number of packages that depend on the OpenSSL/LibreSSL API (curl, wpa_supplicant, msmtp, netsurf, openssh, python, transmission), so it might involve a lot of porting effort. > Thanks for your work! Thanks for taking a look!
[dev] oasis: small linux system inspired by stali
For a while now, I've been working on putting together a linux system based on suckless core tools, as well as various other projects. There are still a number of things left to do, but I'm now at a point where it is quite usable for me, and maybe for others as well. https://github.com/michaelforney/oasis/wiki https://github.com/michaelforney/oasis/releases # stali similarities - Uses musl libc and suckless core tools. - Everything is statically linked. - Everything is built from a single repository. - Root filesystem is managed with git. - Package build systems are ignored in favor of uniform custom build scripts. # stali differences - Package sources are not checked into the source repository, but fetched on demand depending on which packages you have selected in config.rc[0]. - Though stali has given up on being a general purpose desktop system, I have not, so oasis includes my wayland display server (velox), wayland ports of dmenu and st, and a wayland implementation of the framebuffer backend for the netsurf browser. - Only x86_64 is supported at the moment. - Self-bootstrappable. Nearly all packages are buildable with only the core packages[1] and a toolchain targeting musl (some need special handling to first build some tool and add to PATH). A new toolchain can be built with the above and GNU make (using musl-cross-make). A new kernel can be built with the above and python (after applying a couple patches[2]). - Instead of makefiles, oasis uses rc scripts to generate ninja build files (maybe in the future I will work on a ninja-compatible build tool in C to avoid the C++ dependency). - Binaries are not distributed, users are expected to build their own (though, you can do so on a separate system and pull from it). # Trying it out ## Real hardware I wrote up some installation instructions[3] on the github wiki. I've tested the build and install with the xubuntu 16.10 live environment[4]. If you try this and run into any problems, please let me know so that I can fix/clarify things. ## qemu I built a qemu image[5] containing all the core, extra, and desktop packages as well as a toolchain. It is probably the best way to play around with oasis. The installed kernel is pretty minimal, and only has support for virtio drivers. The root password is `oasis`. qemu-system-x86_64 \ -enable-kvm -cpu host -m 2048 \ -device virtio-balloon \ -device virtio-keyboard \ -device virtio-tablet \ -device virtio-net,netdev=net \ -device virtio-scsi \ -device virtio-serial \ -device virtio-vga \ -chardev stdio,id=cons \ -mon chardev=cons \ -drive if=none,id=hd,file=oasis-20170211.qcow2 \ -device scsi-hd,drive=hd \ -netdev user,id=net To enable ssh login, `ssh-keygen -A && perpctl A sshd` (you will probably want to set up a bridge and change `user` to `bridge` in the netdev option to access from the host system). To start velox, `swc-launch velox`. To run without graphics mode, add `mux=on,signal=off` to the chardev option, and add `-device virtconsole,chardev=cons -display none`. To reboot/shutdown cleanly, `kill -s INT 1`/`kill -s USR1 1` respectively. ## chroot I also uploaded a tar archive[6] created with `git archive` on the root repository. It might be useful for poking around with chroot. Note that the tar does not contain any empty directories and some files are missing special permissions. After extracting, run `./libexec/oasis/applyperms -d . && ./libexec/oasis/applyperms -d etc` to fix this. Also, be aware that there is no common parent directory, so make sure to extract somewhere you can easily clean up (such as a new directory). I've added various bits of documentation to the github wiki[7] if you want to read more (or clone https://github.com/michaelforney/oasis.wiki). [0] https://github.com/michaelforney/oasis/blob/master/config.def.rc [1] https://github.com/michaelforney/oasis/blob/master/sets.rc#L1 [2] https://github.com/torvalds/linux/compare/master...michaelforney:oasis [3] https://github.com/michaelforney/oasis/wiki/Install [4] http://cdimages.ubuntu.com/xubuntu/releases/16.10/release/xubuntu-16.10-desktop-amd64.iso [5] https://github.com/michaelforney/oasis/releases/download/20170211/oasis-20170211.qcow2 [6] https://github.com/michaelforney/oasis/releases/download/20170211/oasis-20170211.tar.xz [7] https://github.com/michaelforney/oasis/wiki
Re: [dev] a
On 2/2/17, willy wrote: > At this point, I'm not sure where to look at, or even if the bug > really lies in tar and not in bzip2. > I checked the size (both octal and converted) and the value is good. So > I'm not sure why the headers are not well read. > In the case of the archive above, the error occurs on the last entry, > but depending on the archives, it can occur on the second entry or in > the middle, there's no rule. > > I hope my example are clear to define what the issue is. Would anyone > have an idea? It's a tar bug. See http://lists.suckless.org/dev/1612/30865.html.
Re: [dev] [sbase] [tar] some errors
On 12/24/16, Cág wrote: > Markus Wichmann wrote: > >> Well, that looks like it might be problematic, doesn't it? Especially >> when you find out, that the size of h->name there is 100 bytes. path >> contains, of course, the entire file path relative to the starting >> directory. In short, you will get this error message whenever trying to >> package files with a total relative path length of more than 100 >> characters. > > Indeed, I've just tried to compress an extracted Linux kernel > (that doesn't have .git folder), it went without errors. Thanks for > pointing out. > > But when I tried to extract it, it still said "malformed tar archive". > Here's the part with it: http://git.suckless.org/sbase/tree/tar.c#n404 Fixing up tar bugs in sbase has been on my TODO list for a while. It's the one tool I'm not using from sbase. One thing that might be related is that in various places, it uses eread(..., BLKSIZE), expecting that exactly BLKSIZE bytes are written (skipblk, xt, unarchive). But, if you are extracting from a pipe hooked up to a decompression program, it may be less than that. When this happens, it calls chktar on a random piece of data from the archive, which fails the checksum check. I think we should add a readall function to libutil, similar to the writeall function I sent in a patch set a few weeks ago. I think I have a pending patch to make the "malformed tar archive" errors more specific, but it's on a different computer and I am visiting family for the holidays. If you want to try and debug the error, I'd start with trying to figure out why it thinks it is malformed. I suspect it is due to a bad checksum.
[dev] [sbase] Allow \t escape in sed?
I recently came across an issue running `make headers_install` for installing kernel headers. The headers_install.sh script runs sed -r \ -e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \ -e 's/__attribute_const__([ \t]|$)/\1/g' \ -e 's@^#include @@' \ -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \ -e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \ -e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \ "$SRCDIR/$i" > "$OUTDIR/$FILE.sed" || exit 1 which doesn't work correctly with sbase sed because it doesn't support escaped tabs. There is a comment at the top of sed.c wondering about allowing this. POSIX says "For each other encountered, the following character shall lose its special meaning (if any)", so for strict compliance, '\t' should be treated as just 't', as in the current version of sed. How should we resolve this? Replace '\t' with a literal tab character in the headers_install.sh script, or add '\t' to the list of characters handled by escapes() in sed.c? Other sed implementations I looked at do not support escaped tabs, but I'm not sure how willing the kernel people would be to removing the tab escapes. What do others think? I'm leaning towards just trying to fix this by patching the headers_install.sh locally and hoping it gets accepted.
Re: [dev] [stali] Root CA certificates
On 10/23/16, Bruno Vetter wrote: >> I suggest just grabbing cert.pem from libressl. > > Thanks for the quick reply. Do you know if there is a designated default > path for certs in stali? It looks like the stali curl_config.h sets CURL_CA_BUNDLE to /etc/ssl/certs/ca-certificates.crt[0]. I suspect that this is the detected location for the cert bundle on the system used to run curl's configure script. > From what I see, stali's curl is not built with any certs default path or > default bundle file. See above. > I don't know if it falls back to some libressl settings > in that case (I have no openssl.cnf yet). Same question for other > applications using certs like git. I believe git uses libcurl, so probably just uses the path specified in curl. It looks like the default path in libressl is to use OPENSSLDIR "/cert.pem", and stali is using the default value of OPENSSLDIR, /etc/ssl. So, other applications that use libressl directly and have no default are probably looking for it in /etc/ssl/cert.pem. > I just want to understand how it's meant to work. I don't know how it's meant to work on stali, but on my system, I install cert.pem to /share/libressl/cert.pem, and create a symlink /etc/ssl/cert.pem -> ../share/libressl/cert.pem, and set CURL_CA_BUNDLE to /etc/ssl/cert.pem.
Re: [dev] [stali] Root CA certificates
On Sun, Oct 23, 2016 at 8:47 AM, Bruno Vetter wrote: > what is the recommended way to obtain a decent bundle of CA certificates for > stali? Like the ones I find in /etc/ssl/certs in my current distro. I suggest just grabbing cert.pem from libressl.
Re: [dev] [stali] How to view manpages?
On Mon, Oct 17, 2016 at 6:53 PM, Evan Gates wrote: > The plan for now is to use 9 base troff and a pager which has not yet > been picked. Currently 9 base troff has been added to the src repo, > but the mdoc macros still need to be included (the ones from heirloom > troff worked). As such you should be able to manually view pages using > the man macros but not the mdoc macros (e.g. sbase man pages won't > work). I don't think there is a plan yet on how to handle the > search/troff/pager setup, whether a man script like plan 9's or > something else entirely. A minor point, the man macros included with 9 > base troff seem to add page breaks. I started to learn troff to remove > them but I got side tracked by other projects. > > If you come up with a good solution start a discussion. Why not mdocml[0]? It supports man and mdoc macros, and also has can find and display man pages when invoked as 'man'. [0] http://mdocml.bsd.lv/
Re: AW: [dev] [stali] Need musl based toolchain on stali installation
On Oct 7, 2016 7:24 AM, "Bruno Vetter" wrote: > yes, it's tedious and I understand that it's not crucial to have the > toolchain statically linked. Trying to do so also brings up a lot of > questions that I cannot answer easily. For example a statically linked linker > apparently does not support an lto plugin. I have no idea if that would be > acceptable for a toolchain. > > I might just go on with the existing toolchain as you describe. Thanks much > for your help. What "header file not found" issue did you hit with musl-cross-make? I've used it successfully to build a native statically-linked toolchain, although I ran into and worked around a couple of issues. If you like, I have uploaded a pre-built toolchain[0] for my own project. Yes, I believe LTO doesn't work with a statically-linked gcc/binutils. [0] https://github.com/michaelforney/oasis-toolchain
Re: [dev] sbase installed first impressions
On Mon, Oct 3, 2016 at 5:02 PM, stephen Turner wrote: > Thanks for the links i will check it out! Also i wasn't aware of the > -F function, playing with it now and that is a big help with working > around the whole color bit. Clearly the / is for directories. How are > the rest used? Surprisingly even google doesn't know. From what i > could see they didn't label links and such so not very helpful in that > respect but at least i wont try to vi a directory or cd to a file. It is documented in POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html#tag_20_73_04
Re: [dev] Wayland vs X11
On Tue, Aug 2, 2016 at 1:08 PM, Silvan Jegen wrote: > On Tue, Aug 02, 2016 at 08:41:57PM +0200, FRIGN wrote: > > On Tue, 2 Aug 2016 20:33:39 +0200 > > Silvan Jegen wrote: > > > > Hey Silvan, > > > > > One can argue that having a simple protocol *is* the suckless part of > > > Wayland (dont forget Xprint[0] :P). The Wayland protocol also does not > > > allow for communication between clients directly[1] but only through > > > the Wayland compositor. > > > > yeah, but omitting the rest is not suckless, it just turns everything > > into a big mess. You might say anything about X.org, but at least you > > can more or less rely on a set of features available to you, even if > > they are "default" XFree86 extensions. You are comparing a specific implementation of X11 (Xorg) with a protocol (wayland). If you chose to implement your own suckless X11 server, you'd still have all the problems you are describing (rendering, buffer management, input handling, joysticks, etc), and probably a lot more because of legacy X11 baggage. > > > I see two main issues that stem from switching to Wayland. > > > 1. With Wayland there will be no non-compositing desktop. > > > > I don't see this aspect too critically. See how Wayland performs vs. > > X in limited environments[0]. > > I always assumed that having a compositing window manager has negative > performance impact but at least according to > > https://blog.martin-graesslin.com/blog/2013/05/compositing-and-lightweight-desktops/ Xorg is a compositor too... At the end of the day, *something* has to combine all your windows into a single frame to display them on your monitor. I didn't read the article, but presumably the slowness is due to Xcomposite redirecting to some compositing windowing manager. If the display server does the compositing (as in normal Xorg, or a typical wayland server), there is no such problem. > > > 2. Since rendering is done client-side and there is no Xlib, it may be > > >harder to get pixel on your screen if you don't want to use one of > > > the big GUI libraries like Qt or GTK2/3/++/whatev. > > > > Yeah, very good point. Also, clients cannot rely on compositor > > features, because each compositor can do things differently. There > > really is no simple way to write software and making it deliberately > > hard almost makes you believe its a GTK/Qt conspiracy of some sort. > > > > As a non-expert in this space I am not sure the Wayland future is > > > looking that bleak though. > > > Velox[2] does not look bloated to me and wayland-enabled st[3] is only > > > barely larger than the current X11 version's git tip (though the > > > wayland version depends on wld[4]). > > > > How can you compare the two? You need a third-party library (wld) to > > get shit done. Just wait down the line how much of a fucking mess we > > are going to have! With X11 and Xlib, you need an X server that implements every drawing routine you might want to call. But maybe you are arguing for server-side rendering over the display server connection. I think it's simpler to just have the client do the rendering, which it can do however it pleases. -- Michael Forney
[dev] [sbase] [PATCH 1/3] grep: Reverse some if-else logic
This way, people don't have to do double negatives in their head. --- grep.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/grep.c b/grep.c index 64ffbe2..ae23967 100644 --- a/grep.c +++ b/grep.c @@ -114,23 +114,23 @@ grep(FILE *fp, const char *str) if (len && buf[len - 1] == '\n') buf[len - 1] = '\0'; SLIST_FOREACH(pnode, &phead, entry) { - if (!Fflag) { - if (regexec(&pnode->preg, buf, 0, NULL, 0) ^ vflag) - continue; - } else { - if (!xflag) { - if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) + if (Fflag) { + if (xflag) { + if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) match = Match; else match = NoMatch; } else { - if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) + if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) match = Match; else match = NoMatch; } if (match ^ vflag) continue; + } else { + if (regexec(&pnode->preg, buf, 0, NULL, 0) ^ vflag) + continue; } switch (mode) { case 'c': -- 2.6.2
[dev] [sbase] [PATCH 3/3] grep: Fix -v output and exit status
Previously, it printed lines that didn't match some pattern. Instead, it should print lines that don't match *any* pattern. Test case: out=$(echo foo | ./grep -v -e foo -e bar) if [ "$?" = 1 ] && [ -z "$out" ] ; then echo pass else echo fail fi --- grep.c | 28 +++- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/grep.c b/grep.c index fb911ff..c322a32 100644 --- a/grep.c +++ b/grep.c @@ -113,25 +113,28 @@ grep(FILE *fp, const char *str) /* Remove the trailing newline if one is present. */ if (len && buf[len - 1] == '\n') buf[len - 1] = '\0'; + match = 0; SLIST_FOREACH(pnode, &phead, entry) { if (Fflag) { if (xflag) { - if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) - match = Match; - else - match = NoMatch; + if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) { + match = 1; + break; + } } else { - if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) - match = Match; - else - match = NoMatch; + if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) { + match = 1; + break; + } } - if (match ^ vflag) - continue; } else { - if (regexec(&pnode->preg, buf, 0, NULL, 0) ^ vflag) - continue; + if (regexec(&pnode->preg, buf, 0, NULL, 0) == 0) { + match = 1; + break; + } } + } + if (match != vflag) { switch (mode) { case 'c': c++; @@ -150,7 +153,6 @@ grep(FILE *fp, const char *str) break; } result = Match; - break; } } if (mode == 'c') -- 2.6.2
[dev] [sbase] [PATCH 2/3] grep: Fix exit status with -F when last line doesn't match
Test case: if printf '%s\n' foo bar | ./grep -F foo >/dev/null ; then echo pass else echo fail fi --- grep.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grep.c b/grep.c index ae23967..fb911ff 100644 --- a/grep.c +++ b/grep.c @@ -107,7 +107,7 @@ grep(FILE *fp, const char *str) ssize_t len = 0; long c = 0, n; struct pattern *pnode; - int match = NoMatch; + int match, result = NoMatch; for (n = 1; (len = getline(&buf, &size, fp)) > 0; n++) { /* Remove the trailing newline if one is present. */ @@ -149,7 +149,7 @@ grep(FILE *fp, const char *str) puts(buf); break; } - match = Match; + result = Match; break; } } @@ -158,9 +158,9 @@ grep(FILE *fp, const char *str) end: if (ferror(fp)) { weprintf("%s: read error:", str); - match = Error; + result = Error; } - return match; + return result; } static void -- 2.6.2
[dev] Re: [sbase] [PATCH] sort: Fix -u option
On Sat, Mar 12, 2016 at 11:46:31AM -0800, Michael Forney wrote: > In eb9bda878736344d1bef06d42e57e96de542a663, a bug was introduced in the > handling of -1 return values from getline. Since the type of the len > field in struct line is unsigned, the break condition was never true. > This caused sort -u to never succeed. This should be "sort -c" (here and in subject). Please amend before committing. > --- > sort.c | 11 --- > 1 file changed, 8 insertions(+), 3 deletions(-) > > diff --git a/sort.c b/sort.c > index 5cfe801..90ee911 100644 > --- a/sort.c > +++ b/sort.c > @@ -210,10 +210,15 @@ check(FILE *fp, const char *fname) > { > static struct line prev, cur, tmp; > static size_t prevsize, cursize, tmpsize; > + ssize_t len; > > - if (!prev.data && (prev.len = getline(&prev.data, &prevsize, fp)) < 0) > - eprintf("getline:"); > - while ((cur.len = getline(&cur.data, &cursize, fp)) > 0) { > + if (!prev.data) { > + if ((len = getline(&prev.data, &prevsize, fp)) < 0) > + eprintf("getline:"); > + prev.len = len; > + } > + while ((len = getline(&cur.data, &cursize, fp)) > 0) { > + cur.len = len; > if (uflag > slinecmp(&cur, &prev)) { > if (!Cflag) { > weprintf("disorder %s: ", fname); > -- > 1.8.5.1 >
[dev] [sbase] [PATCH] sort: Fix -u option
In eb9bda878736344d1bef06d42e57e96de542a663, a bug was introduced in the handling of -1 return values from getline. Since the type of the len field in struct line is unsigned, the break condition was never true. This caused sort -u to never succeed. --- sort.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sort.c b/sort.c index 5cfe801..90ee911 100644 --- a/sort.c +++ b/sort.c @@ -210,10 +210,15 @@ check(FILE *fp, const char *fname) { static struct line prev, cur, tmp; static size_t prevsize, cursize, tmpsize; + ssize_t len; - if (!prev.data && (prev.len = getline(&prev.data, &prevsize, fp)) < 0) - eprintf("getline:"); - while ((cur.len = getline(&cur.data, &cursize, fp)) > 0) { + if (!prev.data) { + if ((len = getline(&prev.data, &prevsize, fp)) < 0) + eprintf("getline:"); + prev.len = len; + } + while ((len = getline(&cur.data, &cursize, fp)) > 0) { + cur.len = len; if (uflag > slinecmp(&cur, &prev)) { if (!Cflag) { weprintf("disorder %s: ", fname); -- 1.8.5.1
Re: [dev] Re: Stali RC
On Fri, Oct 02, 2015 at 05:25:55PM +0200, Jens Staal wrote: > On Friday 02 October 2015 16.59.57 Christian Neukirchen wrote: > > (Statically linking X11 apps results in massively bloated binaries, > > I can't recommend it.) > > Anyone tried a static wayland dwm-like client like velox and its wayland- > ported variants of st and dmenu? FWIW, I've used a statically-linked velox, st, and dmenu on a custom-built musl/sbase/ubase system, and it works fine. Perhaps the biggest issue is lack of touchpad support and input hotplugging (libinput requires udev), and a browser that works well with wayland and musl.
[dev] [sbase] [PATCH 3/3] touch: Use both atime and mtime of reference file
--- touch.c | 22 +- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/touch.c b/touch.c index 2789716..fb04142 100644 --- a/touch.c +++ b/touch.c @@ -14,14 +14,13 @@ static int aflag; static int cflag; static int mflag; -static struct timespec t; +static struct timespec times[2]; static void touch(const char *file) { int fd; struct stat st; - struct timespec times[2]; int r; if ((r = stat(file, &st)) < 0) { @@ -30,8 +29,10 @@ touch(const char *file) if (cflag) return; } else if (!r) { - times[0] = aflag ? t : st.st_atim; - times[1] = mflag ? t : st.st_mtim; + if (!aflag) + times[0] = st.st_atim; + if (!mflag) + times[1] = st.st_mtim; if (utimensat(AT_FDCWD, file, times, 0) < 0) eprintf("utimensat %s:", file); return; @@ -117,8 +118,8 @@ int main(int argc, char *argv[]) { struct stat st; - char *ref; - clock_gettime(CLOCK_REALTIME, &t); + char *ref = NULL; + clock_gettime(CLOCK_REALTIME, ×[0]); ARGBEGIN { case 'a': @@ -129,7 +130,7 @@ main(int argc, char *argv[]) break; case 'd': case 't': - t.tv_sec = parsetime(EARGF(usage()), t.tv_sec); + times[0].tv_sec = parsetime(EARGF(usage()), times[0].tv_sec); break; case 'm': mflag = 1; @@ -138,10 +139,11 @@ main(int argc, char *argv[]) ref = EARGF(usage()); if (stat(ref, &st) < 0) eprintf("stat '%s':", ref); - t = st.st_mtim; + times[0] = st.st_atim; + times[1] = st.st_mtim; break; case 'T': - t.tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX); + times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX); break; default: usage(); @@ -151,6 +153,8 @@ main(int argc, char *argv[]) usage(); if (!aflag && !mflag) aflag = mflag = 1; + if (!ref) + times[1] = times[0]; for (; *argv; argc--, argv++) touch(*argv); -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 2/3] touch: Handle nanosecond timestamps
--- touch.c | 24 +++- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/touch.c b/touch.c index 563f919..2789716 100644 --- a/touch.c +++ b/touch.c @@ -14,14 +14,14 @@ static int aflag; static int cflag; static int mflag; -static time_t t; +static struct timespec t; static void touch(const char *file) { int fd; struct stat st; - struct utimbuf ut; + struct timespec times[2]; int r; if ((r = stat(file, &st)) < 0) { @@ -30,10 +30,10 @@ touch(const char *file) if (cflag) return; } else if (!r) { - ut.actime = aflag ? t : st.st_atime; - ut.modtime = mflag ? t : st.st_mtime; - if (utime(file, &ut) < 0) - eprintf("utime %s:", file); + times[0] = aflag ? t : st.st_atim; + times[1] = mflag ? t : st.st_mtim; + if (utimensat(AT_FDCWD, file, times, 0) < 0) + eprintf("utimensat %s:", file); return; } @@ -118,7 +118,7 @@ main(int argc, char *argv[]) { struct stat st; char *ref; - t = time(NULL); + clock_gettime(CLOCK_REALTIME, &t); ARGBEGIN { case 'a': @@ -128,7 +128,8 @@ main(int argc, char *argv[]) cflag = 1; break; case 'd': - t = parsetime(EARGF(usage()), t); + case 't': + t.tv_sec = parsetime(EARGF(usage()), t.tv_sec); break; case 'm': mflag = 1; @@ -137,13 +138,10 @@ main(int argc, char *argv[]) ref = EARGF(usage()); if (stat(ref, &st) < 0) eprintf("stat '%s':", ref); - t = st.st_mtime; + t = st.st_mtim; break; case 'T': - t = estrtonum(EARGF(usage()), 0, LLONG_MAX); - break; - case 't': - t = parsetime(EARGF(usage()), t); + t.tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX); break; default: usage(); -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 1/3] mv, cp: Preserve nanosecond timestamps
Otherwise, we run into problems in a typical autoconf-based build system: - config.status is created at some point between two seconds. - config.status is run, generating Makefile by first writing to a file in /tmp, and then mv-ing it to Makefile. - If this mv happens before the beginning of the next second, Makefile will be created with the same tv_sec as config.status, but with tv_nsec = 0. - When make runs, it sees that Makefile is older than config.status, and re-runs config.status to generate Makefile. --- libutil/cp.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libutil/cp.c b/libutil/cp.c index 32e0dc6..0f098d3 100644 --- a/libutil/cp.c +++ b/libutil/cp.c @@ -30,7 +30,7 @@ cp(const char *s1, const char *s2, int depth) FILE *f1, *f2; struct dirent *d; struct stat st; - struct utimbuf ut; + struct timespec times[2]; ssize_t r; int (*statf)(const char *, struct stat *); char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX], *statf_name; @@ -154,9 +154,9 @@ cp(const char *s1, const char *s2, int depth) if (cp_aflag || cp_pflag) { /* timestamp and owner*/ if (!S_ISLNK(st.st_mode)) { - ut.actime = st.st_atime; - ut.modtime = st.st_mtime; - utime(s2, &ut); + times[0] = st.st_atim; + times[1] = st.st_mtim; + utimensat(AT_FDCWD, s2, times, 0); if (chown(s2, st.st_uid, st.st_gid) < 0) { weprintf("chown %s:", s2); -- 2.1.3.1.g339ec9c
[dev] Miscellaneous sbase issues
Hi suckless, I came across some issues in sbase whose solution wasn't immediately apparent: printf -- Ignores flag characters '#', '0', '-', ' ', and '+', but is labeled as POSIX compliant and complete, so this is presumably unintentional. "git am" breaks without this functionality. tar --- Since fb1595a69c091a6f6a9303b1fab19360b876d114, tar calls remove(3) on directories before extracting them. I'm not sure that it is reasonable for tar to do this because users may want to re-extract archives, or extract archives on top a directory structure that already exists. Additionally, it is fairly common to find tar archives containing the "." directory (possibly with a trailing '/'), which were constructed using "tar -cf foo.tar .". cat, tee These utilities read from stdin using fread(3) into a buffer of size BUFSIZ. However, fread will read until it fills up the entire buffer (or hits EOF) before returning, causing noticeable delay when the input comes from other programs or scripts. To demonstrate this problem, compare the output of these commands: for i in $(seq 500) ; do printf 0123456789abcdef ; sleep 0.005 ; done for i in $(seq 500) ; do printf 0123456789abcdef ; sleep 0.005 ; done | cat for i in $(seq 500) ; do printf 0123456789abcdef ; sleep 0.005 ; done | tee I considered fixing this by making the concat function take an fd instead and make a single call to read(2), but this causes problems for sponge, which uses a FILE * obtained from tmpfile(3) as both output and input for concat. We could also use mkstemp(3) to return a file descriptor, and use a FILE * from fdopen for writing, and the file descriptor for reading, but this seems unclean to me. Another option would be to use fgetc and fputc for the concat implementation, and let libc take care of the buffering. I'm not sure if this has any performance implications. Thanks everyone for their work on sbase! It really has come a long way in the last 6 months. pgpDBGzDW2cHX.pgp Description: PGP signature
[dev] [sdhcp] [PATCH 1/2] Only fork once
--- sdhcp.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sdhcp.c b/sdhcp.c index aa3cef2..9ff9baf 100644 --- a/sdhcp.c +++ b/sdhcp.c @@ -339,6 +339,8 @@ acceptlease(void) static void run(void) { + int forked = 0; + #if 0 InitReboot: /* send DHCPrequest to old server */ @@ -390,8 +392,11 @@ Requesting: } Bound: fputs("Congrats! You should be on the 'net.\n", stdout); - if(fork()) - exit(EXIT_SUCCESS); + if(!forked) { + if(fork()) + exit(EXIT_SUCCESS); + forked = 1; + } switch (dhcprecv()) { case DHCPoffer: case DHCPack: -- 2.1.3.1.g339ec9c
[dev] [sdhcp] [PATCH 2/2] Add flag to run in foreground
--- sdhcp.1 | 3 +++ sdhcp.c | 8 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sdhcp.1 b/sdhcp.1 index ef22689..d037624 100644 --- a/sdhcp.1 +++ b/sdhcp.1 @@ -28,6 +28,9 @@ don't change interface information such as an IP address. .TP .B "\-e program" run program. Variables will be set, see VARIABLES. +.TP +.B \-f +run in foreground. .SH VARIABLES .LP The following variables are set: diff --git a/sdhcp.c b/sdhcp.c index 9ff9baf..01f0d23 100644 --- a/sdhcp.c +++ b/sdhcp.c @@ -97,6 +97,7 @@ static unsigned long t1; static int dflag = 1; /* change DNS in /etc/resolv.conf ? */ static int iflag = 1; /* set IP ? */ +static int fflag = 0; /* run in foreground */ #define IP(a,b,c,d) (unsigned char[4]){a,b,c,d} @@ -392,7 +393,7 @@ Requesting: } Bound: fputs("Congrats! You should be on the 'net.\n", stdout); - if(!forked) { + if(!fflag && !forked) { if(fork()) exit(EXIT_SUCCESS); forked = 1; @@ -439,7 +440,7 @@ static void cleanexit(int unused) { static void usage(void) { - eprintf("usage: sdhcp [-i] [-d] [-e program] [ifname] [clientid]\n"); + eprintf("usage: sdhcp [-i] [-d] [-f] [-e program] [ifname] [clientid]\n"); } int @@ -460,6 +461,9 @@ main(int argc, char *argv[]) case 'd': /* don't update DNS in/etc/resolv.conf */ dflag = 0; break; + case 'f': /* run in foreground */ + fflag = 1; + break; default: usage(); break; -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH] tr: Fix -c option when translating
--- tr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tr.c b/tr.c index 38ea6a3..ad5c690 100644 --- a/tr.c +++ b/tr.c @@ -221,6 +221,8 @@ read: else goto write; } + if (cflag) + goto write; for (m = 0; m < i; m++) off1 += rangelen(set1[m]); off1 += r - set1[m].start; -- 2.1.3.1.g339ec9c
Re: [dev] [sbase] [PATCH v2] rm: Fix exit status with -f for nonexistent paths
On Sun, Mar 01, 2015 at 11:51:35PM +0100, FRIGN wrote: > On Sun, 1 Mar 2015 14:44:12 -0800 > Michael Forney wrote: > > That looks good to me. > > Thanks! Applied: > http://git.2f30.org/sbase/commit/?id=48696d8c955db9d0621812aca7ef5caac727da31 I just realized that this could potentially mask an error from a previous rm(). For example, if you run rm -f foo bar where foo exists and can't be removed, but bar does not exist, this will exit with status 0. So I think we need to do if (!(rm_fflag && errno == ENOENT)) rm_status = 1; instead of rm_status = !(rm_fflag && errno == ENOENT); pgpCoZvTvauOb.pgp Description: PGP signature
Re: [dev] [sbase] [PATCH v2] rm: Fix exit status with -f for nonexistent paths
On Sun, Mar 01, 2015 at 11:23:28PM +0100, FRIGN wrote: > I'd do it like this instead, makes it clearer that we're > dealing with one special case: > > if (remove(path) < 0) { > if (!rm_fflag) > weprintf("remove %s:", path); > rm_status = !(rm_fflag && errno == ENOENT); > } > > What do you think? That looks good to me.
[dev] [sbase] [PATCH v2] rm: Fix exit status with -f for nonexistent paths
Under the description for the -f option, POSIX says, "Do not modify the exit status in the case of nonexistent operands". --- Whoops, just realized that simply using the errno from the remove call is way simpler. libutil/rm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libutil/rm.c b/libutil/rm.c index 53ae3f2..54987e5 100644 --- a/libutil/rm.c +++ b/libutil/rm.c @@ -1,4 +1,5 @@ /* See LICENSE file for copyright and license details. */ +#include #include #include "../fs.h" @@ -14,8 +15,9 @@ rm(const char *path, int unused) if (rm_rflag) recurse(path, rm, 'P'); if (remove(path) < 0) { + if (!rm_fflag || errno != ENOENT) + rm_status = 1; if (!rm_fflag) weprintf("remove %s:", path); - rm_status = 1; } } -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH] rm: Fix exit status with -f for nonexistent paths
Under the description for the -f option, POSIX says, "Do not modify the exit status in the case of nonexistent operands". --- libutil/rm.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libutil/rm.c b/libutil/rm.c index 53ae3f2..30a1b41 100644 --- a/libutil/rm.c +++ b/libutil/rm.c @@ -1,5 +1,7 @@ /* See LICENSE file for copyright and license details. */ +#include #include +#include #include "../fs.h" #include "../util.h" @@ -11,11 +13,14 @@ int rm_status = 0; void rm(const char *path, int unused) { + struct stat st; + if (rm_rflag) recurse(path, rm, 'P'); if (remove(path) < 0) { if (!rm_fflag) weprintf("remove %s:", path); - rm_status = 1; + if (!rm_fflag || stat(path, &st) < 0 && errno != ENOENT) + rm_status = 1; } } -- 2.1.3.1.g339ec9c
Re: [dev] [sbase] [PATCH v3] ls: Handle symlinks to directories properly
On Mon, Dec 08, 2014 at 04:21:30PM -0800, Eric Pruitt wrote: > Unless I'm missing something, I still don't see anything in that patch > pertaining to the interpretation of slashes. I'm not sure what you're expecting... When you lstat "foo/", where foo is a symlink to a directory, you look up information about the directory, not the symlink. "ls" does not do anything differently. You can also see that POSIX does not specify anything related to interpretation of slashes in the specification of the "ls" (because it do not need any sort of special interpretation). See, this example (pruned for the system calls that matter) $ strace ls -l foo lstat("foo", {st_mode=S_IFLNK|0777, st_size=3, ...}) = 0 stat("foo", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0 lrwxrwxrwx1 michael michael 3 Dec 09 20:22 foo -> bar $ strace ls -l foo/ lstat("foo/", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0 -rw---1 michael michael 0 Dec 09 20:23 hello -rw---1 michael michael 0 Dec 09 20:23 world $
[dev] [sbase] [PATCH] cp: Rename -d option to -P
The -d option is a GNU extension and is equivalent to its "-P --preserve=links" options. Since we don't implement the --preserve=links functionality anyway (it means preserve hard links between files), just call it -P, which is specified by POSIX. Additionally, there is no need to check for cp_Pflag again before copying the symlink itself because the only way the mode in the stat will indicate a symlink is if we used lstat (which we only do if -P is specified). --- cp.1 | 6 +++--- cp.c | 6 +++--- fs.h | 2 +- libutil/cp.c | 8 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cp.1 b/cp.1 index f0f5b65..95f39c3 100644 --- a/cp.1 +++ b/cp.1 @@ -8,7 +8,7 @@ cp \- copy files and directories .RI [ name ] .P .B cp -.RB [ \-adpRrv ] +.RB [ \-aPpRrv ] .RI [ file ...] .RI [ directory ] .SH DESCRIPTION @@ -21,8 +21,8 @@ they will be copied into the given directory. preserve mode, timestamp, links and permissions. Implies \-d, \-p, \-r. .TP -.B \-d -don't dereference links. preserve links. +.B \-P +don't dereference symbolic links. .TP .B \-p preserve mode, timestamp and permissions. diff --git a/cp.c b/cp.c index f1c3d9b..f3b91f1 100644 --- a/cp.c +++ b/cp.c @@ -19,10 +19,10 @@ main(int argc, char *argv[]) ARGBEGIN { case 'a': /* implies -dpr */ - cp_aflag = cp_dflag = cp_pflag = cp_rflag = 1; + cp_aflag = cp_Pflag = cp_pflag = cp_rflag = 1; break; - case 'd': - cp_dflag = 1; + case 'P': + cp_Pflag = 1; break; case 'p': cp_pflag = 1; diff --git a/fs.h b/fs.h index 18b7f4d..4d65766 100644 --- a/fs.h +++ b/fs.h @@ -1,7 +1,7 @@ /* See LICENSE file for copyright and license details. */ extern int cp_aflag; -extern int cp_dflag; extern int cp_fflag; +extern int cp_Pflag; extern int cp_pflag; extern int cp_rflag; extern int cp_vflag; diff --git a/libutil/cp.c b/libutil/cp.c index f274475..d252e52 100644 --- a/libutil/cp.c +++ b/libutil/cp.c @@ -16,8 +16,8 @@ #include "../util.h" int cp_aflag = 0; -int cp_dflag = 0; int cp_fflag = 0; +int cp_Pflag = 0; int cp_pflag = 0; int cp_rflag = 0; int cp_vflag = 0; @@ -39,14 +39,14 @@ cp(const char *s1, const char *s2) if (cp_vflag) printf("'%s' -> '%s'\n", s1, s2); - r = cp_dflag ? lstat(s1, &st) : stat(s1, &st); + r = cp_Pflag ? lstat(s1, &st) : stat(s1, &st); if (r < 0) { - weprintf("%s %s:", cp_dflag ? "lstat" : "stat", s1); + weprintf("%s %s:", cp_Pflag ? "lstat" : "stat", s1); cp_status = 1; return 0; } - if (cp_dflag && S_ISLNK(st.st_mode)) { + if (S_ISLNK(st.st_mode)) { if (readlink(s1, buf, sizeof(buf) - 1) >= 0) { if (cp_fflag) unlink(s2); -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH] ls: Always leave room for the NULL byte in the link target
Otherwise, if the length of the link target is the same as BUFSIZ, we will try to write past the end of buf. --- ls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ls.c b/ls.c index b48391b..a2fb5cb 100644 --- a/ls.c +++ b/ls.c @@ -291,7 +291,7 @@ output(Entry *ent) printf("%10lu ", (unsigned long)ent->size); printf("%s %s%s", buf, ent->name, indicator(ent->mode)); if (S_ISLNK(ent->mode)) { - if ((len = readlink(ent->name, buf, sizeof buf)) < 0) + if ((len = readlink(ent->name, buf, sizeof buf - 1)) < 0) eprintf("readlink %s:", ent->name); buf[len] = '\0'; mkent(&entlnk, buf, Fflag); -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH v3] ls: Handle symlinks to directories properly
Also, implement the -H and -L options. --- Again, not sure how to handle the long line. ls.1 | 9 - ls.c | 32 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/ls.1 b/ls.1 index ec61bee..792b07b 100644 --- a/ls.1 +++ b/ls.1 @@ -3,7 +3,7 @@ ls \- list directory contents .SH SYNOPSIS .B ls -.RB [ \-adFiltU ] +.RB [ \-adFHhiLlrtU ] .RI [ file ...] .SH DESCRIPTION .B ls @@ -20,12 +20,19 @@ lists directories themselves, not their contents. .B \-F append a file type indicator to files. .TP +.B \-H +list information about the targets of symbolic links specified on the command +line instead of the links themselves. +.TP .B \-h show filesizes in human\-readable format. .TP .B \-i print the index number of each file. .TP +.B \-L +list information about the targets of symbolic links instead of the links +themselves. .B \-l lists detailed information about each file, including their type, permissions, links, owner, group, size, and modification time. diff --git a/ls.c b/ls.c index b48391b..24af998 100644 --- a/ls.c +++ b/ls.c @@ -14,7 +14,7 @@ typedef struct { char *name; - mode_t mode; + mode_t mode, tmode; nlink_t nlink; uid_t uid; gid_t gid; @@ -26,14 +26,16 @@ typedef struct { static int entcmp(const void *, const void *); static void ls(Entry *); static void lsdir(const char *); -static void mkent(Entry *, char *, int); +static void mkent(Entry *, char *, int, int); static void output(Entry *); static int aflag = 0; static int dflag = 0; static int Fflag = 0; +static int Hflag = 0; static int hflag = 0; static int iflag = 0; +static int Lflag = 0; static int lflag = 0; static int rflag = 0; static int tflag = 0; @@ -66,12 +68,18 @@ main(int argc, char *argv[]) case 'F': Fflag = 1; break; + case 'H': + Hflag = 1; + break; case 'h': hflag = 1; break; case 'i': iflag = 1; break; + case 'L': + Lflag = 1; + break; case 'l': lflag = 1; break; @@ -95,7 +103,7 @@ main(int argc, char *argv[]) ents = emalloc(argc * sizeof(*ents)); for (i = 0; i < argc; i++) - mkent(&ents[i], argv[i], 1); + mkent(&ents[i], argv[i], 1, Hflag || Lflag); qsort(ents, argc, sizeof *ents, entcmp); for (i = 0; i < argc; i++) ls(&ents[rflag ? argc-i-1 : i]); @@ -117,7 +125,7 @@ entcmp(const void *va, const void *vb) static void ls(Entry *ent) { - if (S_ISDIR(ent->mode) && !dflag) { + if ((S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag) { lsdir(ent->name); } else { output(ent); @@ -151,13 +159,13 @@ lsdir(const char *path) if (d->d_name[0] == '.' && !aflag) continue; if (Uflag){ - mkent(&ent, d->d_name, Fflag || lflag || iflag); + mkent(&ent, d->d_name, Fflag || lflag || iflag, Lflag); output(&ent); } else { ents = erealloc(ents, ++n * sizeof *ents); p = emalloc((sz = strlen(d->d_name)+1)); memcpy(p, d->d_name, sz); - mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag); + mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag, Lflag); } } closedir(dp); @@ -175,15 +183,15 @@ lsdir(const char *path) } static void -mkent(Entry *ent, char *path, int dostat) +mkent(Entry *ent, char *path, int dostat, int follow) { struct stat st; ent->name = path; if (!dostat) return; - if (lstat(path, &st) < 0) - eprintf("lstat %s:", path); + if ((follow ? stat : lstat)(path, &st) < 0) + eprintf("%s %s:", follow ? "stat" : "lstat", path); ent->mode = st.st_mode; ent->nlink = st.st_nlink; ent->uid= st.st_uid; @@ -191,6 +199,8 @@ mkent(Entry *ent, char *path, int dostat) ent->size = st.st_size; ent->mtime = st.st_mtime; ent->ino= st.st_ino; + if (S_ISLNK(ent->mode)) + ent->tmode = stat(path, &st) == 0 ? st.st_mode : 0; } static char * @@ -225,7 +235,6 @@ output(Entry *ent) struct passwd *pw; char pwname[_SC_LOGIN_NAME_MAX]; char grname[_SC_LOGIN_NAME_MAX]; - Entry entlnk; if (iflag) printf("%lu ", (unsigned long)ent->ino); @@ -294,8 +303,7 @@ output(Entry *ent) if ((len = readlink(ent->name, buf, sizeof buf)) < 0) eprintf("readlink %s:", ent->name); buf[len] = '\0'
Re: [dev] [sbase] [PATCH v2] ls: List directory contents if file is a symlink to a directory
On Sun, Dec 07, 2014 at 03:43:36PM -0800, Eric Pruitt wrote: > I don't know if this is the correct behavior. Whether or not a symlink > to a directory has its contents shown with GNU ls depends on whether or > not there's a slash present and the flags used: > > playground$ mkdir AFolder > playground$ touch AFolder/Horse > playground$ ln -s AFolder SymbolicLinkToAFolder > playground$ ls SymbolicLinkToAFolder > Horse > playground$ ls -l SymbolicLinkToAFolder > lrwxrwxrwx 1 ericpruitt ericpruitt 7 Dec 7 15:35 SymbolicLinkToAFolder > -> AFolder > playground$ ls -l SymbolicLinkToAFolder/ > total 0 > -rw--- 1 ericpruitt ericpruitt 0 Dec 7 15:34 Horse > > Personally, that "-l" made a difference surprised me, but prior to > actually running the command, I would expect "ls ... $SYMLINK" to show > the information for the symlink while "ls ... $SYMLINK/" to show the > contents of the directory. If I recall correctly, historically in things > like Sys V, whether or not a trailing slash was added to a directory > used as a command line argument changed the behaviour of various tools. > Check out http://unix.stackexchange.com/a/50522 which has a few links to > the POSIX docs. Actually, POSIX specifies this behavior (contents of symlink without -l, symlink itself with -l): "If one or more of the -d, -F, or -l options are specified, and neither the -H nor the -L option is specified, for each operand that names a file of type symbolic link to a directory, ls shall write the name of the file as well as any requested, associated information. If none of the -d, -F, or -l options are specified, or the -H or -L options are specified, for each operand that names a file of type symbolic link to a directory, ls shall write the names of files contained within the directory as well as any requested, associated information." I will update the patch to interact correctly with the -l and -F flags, and maybe look at adding the -H and -L flags.
[dev] [sbase] [PATCH v2] ls: List directory contents if file is a symlink to a directory
--- Not sure if you want to break up the long line. Up to you. Another possibility is if (S_ISLINK(ent->mode)) stat(path, &st); ent->isdir = S_ISDIR(st.st_mode); which looks nicer, but I'm not sure if stat(2) is required to not modify the st argument if it fails. ls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ls.c b/ls.c index b48391b..a6e4309 100644 --- a/ls.c +++ b/ls.c @@ -21,6 +21,7 @@ typedef struct { off_t size; time_t mtime; ino_t ino; + int isdir; } Entry; static int entcmp(const void *, const void *); @@ -117,7 +118,7 @@ entcmp(const void *va, const void *vb) static void ls(Entry *ent) { - if (S_ISDIR(ent->mode) && !dflag) { + if (ent->isdir && !dflag) { lsdir(ent->name); } else { output(ent); @@ -191,6 +192,7 @@ mkent(Entry *ent, char *path, int dostat) ent->size = st.st_size; ent->mtime = st.st_mtime; ent->ino= st.st_ino; + ent->isdir = S_ISDIR(ent->mode) || S_ISLNK(ent->mode) && stat(path, &st) == 0 && S_ISDIR(st.st_mode); } static char * -- 2.1.3.1.g339ec9c
[dev] Re: [sbase] [PATCH] ls: List directory contents if file is a symlink to a directory
On Sun, Dec 07, 2014 at 10:40:42PM +, Michael Forney wrote: > --- > ls.c | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/ls.c b/ls.c > index b48391b..90193cc 100644 > --- a/ls.c > +++ b/ls.c > @@ -21,6 +21,7 @@ typedef struct { > off_t size; > time_t mtime; > ino_t ino; > + int isdir; > } Entry; > > static int entcmp(const void *, const void *); > @@ -117,7 +118,7 @@ entcmp(const void *va, const void *vb) > static void > ls(Entry *ent) > { > - if (S_ISDIR(ent->mode) && !dflag) { > + if (ent->isdir && !dflag) { > lsdir(ent->name); > } else { > output(ent); > @@ -191,6 +192,7 @@ mkent(Entry *ent, char *path, int dostat) > ent->size = st.st_size; > ent->mtime = st.st_mtime; > ent->ino= st.st_ino; > + ent->isdir = S_ISLNK(ent->mode) && stat(path, &st) == 0 && > S_ISDIR(st.st_mode); Whoops, this should also have S_ISDIR(ent->mode) || ... Will send a new patch shortly.
[dev] [sbase] [PATCH] ls: List directory contents if file is a symlink to a directory
--- ls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ls.c b/ls.c index b48391b..90193cc 100644 --- a/ls.c +++ b/ls.c @@ -21,6 +21,7 @@ typedef struct { off_t size; time_t mtime; ino_t ino; + int isdir; } Entry; static int entcmp(const void *, const void *); @@ -117,7 +118,7 @@ entcmp(const void *va, const void *vb) static void ls(Entry *ent) { - if (S_ISDIR(ent->mode) && !dflag) { + if (ent->isdir && !dflag) { lsdir(ent->name); } else { output(ent); @@ -191,6 +192,7 @@ mkent(Entry *ent, char *path, int dostat) ent->size = st.st_size; ent->mtime = st.st_mtime; ent->ino= st.st_ino; + ent->isdir = S_ISLNK(ent->mode) && stat(path, &st) == 0 && S_ISDIR(st.st_mode); } static char * -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH] ln: Add support for target directories
Also, now that we are using {sym,}linkat, implement the trivial -L and -P options. --- ln.1 | 11 +-- ln.c | 53 ++--- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/ln.1 b/ln.1 index 4205ea7..3b1ac98 100644 --- a/ln.1 +++ b/ln.1 @@ -3,12 +3,12 @@ ln \- make links between files .SH SYNOPSIS .B ln -.RB [ \-fs ] +.RB [ \-LPfs ] .I file .RI [ name ] .P .B ln -.RB [ \-fs ] +.RB [ \-LPfs ] .RI [ file ...] .RI [ directory ] .SH DESCRIPTION @@ -18,6 +18,13 @@ it is linked into the current directory. If multiple files are listed they will be linked into the given directory. .SH OPTIONS .TP +.B \-L +create links to the files referenced by symbolic link source files (default +behavior). +.TP +.B \-P +create links to symbolic link source files themselves. +.TP .B \-f remove existing destinations. .TP diff --git a/ln.c b/ln.c index d8809ce..0a5bf18 100644 --- a/ln.c +++ b/ln.c @@ -1,9 +1,11 @@ /* See LICENSE file for copyright and license details. */ #include +#include #include #include #include #include +#include #include #include "util.h" @@ -11,16 +13,20 @@ static void usage(void) { - eprintf("usage: %s [-fs] target [linkname]\n", argv0); + eprintf("usage: %1$s [-LPfs] target [linkname]\n" + " %1$s [-LPfs] target... directory\n", argv0); } int main(int argc, char *argv[]) { - int (*flink)(const char *, const char *); char *fname, *to; int sflag = 0; int fflag = 0; + int hasto = 0; + int dirfd = AT_FDCWD; + int flags = AT_SYMLINK_FOLLOW; + struct stat st; ARGBEGIN { case 'f': @@ -29,27 +35,44 @@ main(int argc, char *argv[]) case 's': sflag = 1; break; + case 'L': + flags |= AT_SYMLINK_FOLLOW; + break; + case 'P': + flags &= ~AT_SYMLINK_FOLLOW; + break; default: usage(); } ARGEND; - if (argc == 0 || argc > 2) + if (argc == 0) usage(); - if (sflag) { - flink = symlink; - fname = "symlink"; - } else { - flink = link; - fname = "link"; - } + fname = sflag ? "symlink" : "link"; - to = argc < 2 ? basename(argv[0]) : argv[1]; + if (argc >= 2) { + if (stat(argv[argc - 1], &st) == 0 && S_ISDIR(st.st_mode)) { + if ((dirfd = open(argv[argc - 1], O_RDONLY)) < 0) + eprintf("open:"); + } else if (argc == 2) { + to = argv[1]; + hasto = 1; + } else { + eprintf("destination is not a directory\n"); + } + argc--; + } - if (fflag) - remove(to); - if (flink(argv[0], to) < 0) - eprintf("%s %s <- %s:", fname, argv[0], to); + for (; argc > 0; argc--, argv++) { + if (!hasto) + to = basename(argv[0]); + if (fflag) + remove(to); + if ((!sflag ? linkat(AT_FDCWD, argv[0], dirfd, to, flags) + : symlinkat(argv[0], dirfd, to)) < 0) { + eprintf("%s %s <- %s:", fname, argv[0], to); + } + } return 0; } -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH] sort: Implement -c and -C flags
--- sort.1 | 11 +++ sort.c | 57 +++-- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/sort.1 b/sort.1 index 12fb95d..71c8154 100644 --- a/sort.1 +++ b/sort.1 @@ -15,9 +15,20 @@ writes the sorted concatenation of the given files to stdout. If no file is given, sort reads from stdin. .SH OPTIONS .TP +.B \-C +check that the concatenation of the given files is sorted rather than sorting +them. In this mode, no output is printed to stdout, and the exit status +indicates the result of the check. +.TP .B \-b skip leading whitespace of columns when sorting. .TP +.B \-c +the same as +.B \-C +except that when disorder is detected, a message is printed to stderr +indicating the location of the disorder. +.TP .BI \-k \ key specifies a key definition of the form .BR S [. s ][ f ][, E [. e ][ f ]] diff --git a/sort.c b/sort.c index 2a89870..c4cd81f 100644 --- a/sort.c +++ b/sort.c @@ -32,6 +32,7 @@ static struct kdlist *head = NULL; static struct kdlist *tail = NULL; static void addkeydef(char *, int); +static void check(FILE *); static void freelist(void); static int linecmp(const char **, const char **); static char *skipblank(char *); @@ -40,13 +41,13 @@ static int parse_keydef(struct keydef *, char *, int); static char *nextcol(char *); static char *columns(char *, const struct keydef *); -static int uflag = 0; +static int Cflag = 0, cflag = 0, uflag = 0; static char *fieldsep = NULL; static void usage(void) { - enprintf(2, "usage: %s [-bnru] [-t delim] [-k def]... [file...]\n", argv0); + enprintf(2, "usage: %s [-Cbcnru] [-t delim] [-k def]... [file...]\n", argv0); } int @@ -58,9 +59,15 @@ main(int argc, char *argv[]) int global_flags = 0; ARGBEGIN { + case 'C': + Cflag = 1; + break; case 'b': global_flags |= MOD_STARTB | MOD_ENDB; break; + case 'c': + cflag = 1; + break; case 'k': addkeydef(EARGF(usage()), global_flags); break; @@ -87,22 +94,33 @@ main(int argc, char *argv[]) addkeydef("1", global_flags & MOD_R); if (argc == 0) { - getlines(stdin, &linebuf); + if (Cflag || cflag) { + check(stdin); + } else { + getlines(stdin, &linebuf); + } } else for (; argc > 0; argc--, argv++) { if (!(fp = fopen(argv[0], "r"))) { enprintf(2, "fopen %s:", argv[0]); continue; } - getlines(fp, &linebuf); + if (Cflag || cflag) { + check(fp); + } else { + getlines(fp, &linebuf); + } fclose(fp); } - qsort(linebuf.lines, linebuf.nlines, sizeof *linebuf.lines, - (int (*)(const void *, const void *))linecmp); - for (i = 0; i < linebuf.nlines; i++) { - if (!uflag || i == 0 || linecmp((const char **)&linebuf.lines[i], - (const char **)&linebuf.lines[i-1])) { - fputs(linebuf.lines[i], stdout); + if (!Cflag && !cflag) { + qsort(linebuf.lines, linebuf.nlines, sizeof *linebuf.lines, + (int (*)(const void *, const void *))linecmp); + + for (i = 0; i < linebuf.nlines; i++) { + if (!uflag || i == 0 || linecmp((const char **)&linebuf.lines[i], + (const char **)&linebuf.lines[i-1])) { + fputs(linebuf.lines[i], stdout); + } } } @@ -129,6 +147,25 @@ addkeydef(char *def, int flags) } static void +check(FILE *fp) +{ + static struct { char *buf; size_t size; } prev, cur, tmp; + + if (!prev.buf) + getline(&prev.buf, &prev.size, fp); + while (getline(&cur.buf, &cur.size, fp) != -1) { + if (uflag > linecmp((const char **) &cur.buf, (const char **) &prev.buf)) { + if (!Cflag) + weprintf("disorder: %s", cur.buf); + exit(1); + } + tmp = cur; + cur = prev; + prev = tmp; + } +} + +static void freelist(void) { struct kdlist *node; -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 2/2] chown: Support numeric uids/gids
--- chown.c | 25 - 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/chown.c b/chown.c index 3fd5f87..5d57801 100644 --- a/chown.c +++ b/chown.c @@ -11,8 +11,8 @@ static void chownpwgr(const char *); static bool rflag = false; -static struct passwd *pw = NULL; -static struct group *gr = NULL; +static uid_t uid = -1; +static gid_t gid = -1; static int ret = 0; static void @@ -24,7 +24,9 @@ usage(void) int main(int argc, char *argv[]) { - char *owner, *group; + char *owner, *group, *end; + struct passwd *pw; + struct group *gr; ARGBEGIN { case 'R': @@ -47,20 +49,26 @@ main(int argc, char *argv[]) if(owner && *owner) { errno = 0; pw = getpwnam(owner); - if (!pw) { + if(pw) { + uid = pw->pw_uid; + } else { if(errno != 0) eprintf("getpwnam %s:", owner); - else + uid = strtoul(owner, &end, 10); + if(*end != '\0') eprintf("getpwnam %s: no such user\n", owner); } } if(group && *group) { errno = 0; gr = getgrnam(group); - if (!gr) { + if(gr) { + gid = gr->gr_gid; + } else { if(errno != 0) eprintf("getgrnam %s:", group); - else + gid = strtoul(group, &end, 10); + if(*end != '\0') eprintf("getgrnam %s: no such group\n", group); } } @@ -73,8 +81,7 @@ main(int argc, char *argv[]) void chownpwgr(const char *path) { - if(chown(path, pw ? pw->pw_uid : (uid_t)-1, - gr ? gr->gr_gid : (gid_t)-1) == -1) { + if(chown(path, uid, gid) == -1) { weprintf("chown %s:", path); ret = 1; } -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 1/2] Fix symbolic mode parsing in parsemode
I found quite a lot of bugs, so I ended up pretty much rewriting as I followed the spec¹. Now, it works as follows: - Determine a mask (who) of bits that can be modified for the subsequent operations. If none are specified, select all file mode bits. - In a loop, determine which operation (+, -, =) to apply. - If the next character is a permcopy (u, g, o), set the new permissions (perm) corresponding to the bits set in the user, group or other parts of the existing mode. - Otherwise, set the new permissions by looping through the next r, w, x, s, t characters. - Now, the set of bits we want to add or remove is (who & perm). Set or remove these bits according the the operation (first clearing the appropriate bits if the operation is =). - Continue from the top if the next character is a comma, otherwise, process the next operation. I tested this on some made up inputs, and I believe it is working correctly now: parsemode("g+w", 0644, 0),before: 0606, now: 0664, fixed parsemode("u+rx", 0222, 0), before: 0077, now: 0722, fixed parsemode("+x", 0644, 023), before: 0754, now: 0754, still works parsemode("+w", 0444, 022), before: 0644, now: 0644, still works parsemode("+w", 0444, 0), before: 0666, now: 0666, still works parsemode("+s", 0755, 0), before: 0755, now: 6755, fixed parsemode("u+s", 0755, 0),before: 0055, now: 4755, fixed parsemode("g+s", 0755, 0),before: 0705, now: 2755, fixed parsemode("g=u", 0700, 0),before: , now: 0770, fixed parsemode("go=u-w", 0700, 0), before: , now: 0755, fixed parsemode("o+u-g", 0641, 0), before: , now: 0643, fixed parsemode("u=rx,o+w,g-r", 0654, 0) before: error, now: 0516, fixed parsemode(",", 0654, 0), before: error, now: error, still works ¹ http://pubs.opengroup.org/onlinepubs/9699919799/utilities/chmod.html --- util/mode.c | 129 1 file changed, 95 insertions(+), 34 deletions(-) diff --git a/util/mode.c b/util/mode.c index 4506023..c022e8d 100644 --- a/util/mode.c +++ b/util/mode.c @@ -16,9 +16,9 @@ mode_t parsemode(const char *str, mode_t mode, mode_t mask) { char *end; - const char *p; - int octal, op = '+'; - mode_t gmask = 0, m = 0; + const char *p = str; + int octal, op; + mode_t who, perm, clear; octal = strtol(str, &end, 8); if(*end == '\0') { @@ -41,61 +41,122 @@ parsemode(const char *str, mode_t mode, mode_t mask) if(octal & 1) mode |= S_IXOTH; return mode; } - for(p = str; *p; p++) { +next: + /* first, determine which bits we will be modifying */ + for(who = 0; *p; p++) { switch(*p) { /* masks */ case 'u': - gmask |= S_IRWXU; - break; + who |= S_IRWXU|S_ISUID; + continue; case 'g': - gmask |= S_IRWXG; - break; + who |= S_IRWXG|S_ISGID; + continue; case 'o': - gmask |= S_IRWXO; - break; + who |= S_IRWXO; + continue; case 'a': - gmask |= S_IRWXU|S_IRWXG|S_IRWXO; - break; + who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO; + continue; + } + break; + } + if(who) { + clear = who; + } else { + clear = S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO; + who = ~mask; + } + while(*p) { + switch(*p) { /* opers */ case '=': case '+': case '-': op = (int)*p; break; - /* modes */ - case 'r': - m |= S_IRUSR|S_IRGRP|S_IROTH; - break; - case 'w': - m |= S_IWUSR|S_IWGRP|S_IWOTH; - break; - case 'x': - m |= S_IXUSR|S_IXGRP|S_IXOTH; + default: + eprintf("%s: invalid mode\n", str); + return -1; + } + + perm = 0; + switch(*++p) { + /* copy */ + case 'u': + if(mode & S_IRUSR) + perm |= S_IRUSR|S_IRGRP|S_IROTH; + if(mode & S_IWUSR) + perm |= S_IWUSR|S_IWGRP|S_IWOTH; + if(mode & S_IXUSR) + perm |= S_IXUSR|S_IXGRP|S_IXOTH; + if(mode & S_ISUID) +
[dev] [sbase] [PATCH 2/2] grep: Fix -c flag
--- grep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grep.c b/grep.c index 1376513..489f6e7 100644 --- a/grep.c +++ b/grep.c @@ -42,11 +42,11 @@ main(int argc, char *argv[]) case 'E': flags |= REG_EXTENDED; break; - case 'c': case 'e': addpattern(EARGF(usage())); eflag = true; break; + case 'c': case 'l': case 'n': case 'q': -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 1/2] grep: Remove newlines before matching a line
Otherwise, a pattern with a '$' anchor will never match and POSIX says that "By default, an input line shall be selected if any pattern ... matches any part of the line excluding the terminating " --- grep.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/grep.c b/grep.c index 715f864..1376513 100644 --- a/grep.c +++ b/grep.c @@ -129,6 +129,9 @@ grep(FILE *fp, const char *str) int match = NoMatch; for(n = 1; (len = agetline(&buf, &size, fp)) != -1; n++) { + /* Remove the trailing newline if one is present. */ + if (len && buf[len - 1] == '\n') + buf[len - 1] = '\0'; for(pnode = phead; pnode; pnode = pnode->next) { if(regexec(&pnode->preg, buf, 0, NULL, 0) ^ vflag) continue; @@ -146,9 +149,7 @@ grep(FILE *fp, const char *str) printf("%s:", str); if(mode == 'n') printf("%ld:", n); - printf("%s", buf); - if(len && buf[len - 1] != '\n') - putchar('\n'); + puts(buf); break; } match = Match; -- 2.1.3.1.g339ec9c
Re: [dev] [sbase] [PATCH 1/4] tar: Don't crash when get{pw,gr}uid fails
On Sat, Nov 01, 2014 at 08:57:12PM +, Dimitris Papastamos wrote: > On Sat, Nov 01, 2014 at 08:36:37PM +0000, Michael Forney wrote: > > - snprintf(h->uname, sizeof h->uname, "%s", pw->pw_name); > > - snprintf(h->gname, sizeof h->gname, "%s", gr->gr_name); > > + snprintf(h->uname, sizeof h->uname, "%s", pw ? pw->pw_name : ""); > > + snprintf(h->gname, sizeof h->gname, "%s", gr ? gr->gr_name : ""); > > The patches look good, thanks! > > Just a small clarification on this one, do other tar implementations > do the same here? It looks like GNU tar does¹, but BSD tar uses the string representation of the UID/GID. ¹ http://git.savannah.gnu.org/cgit/tar.git/tree/src/names.c#n66 -- Michael Forney pgpemX9fk9wLs.pgp Description: PGP signature
[dev] [sbase] [PATCH 1/4] tar: Don't crash when get{pw,gr}uid fails
--- tar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tar.c b/tar.c index 4f4abff..c18d89e 100644 --- a/tar.c +++ b/tar.c @@ -177,8 +177,8 @@ archive(const char* path) putoctal(h->mtime, (unsigned)st.st_mtime, sizeof h->mtime); memcpy(h->magic, "ustar", sizeof h->magic); memcpy(h->version, "00", sizeof h->version); - snprintf(h->uname, sizeof h->uname, "%s", pw->pw_name); - snprintf(h->gname, sizeof h->gname, "%s", gr->gr_name); + snprintf(h->uname, sizeof h->uname, "%s", pw ? pw->pw_name : ""); + snprintf(h->gname, sizeof h->gname, "%s", gr ? gr->gr_name : ""); mode = st.st_mode; if(S_ISREG(mode)) { -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 4/4] tar: Handle archives with the prefix field
Also, handle names and prefixes that fill the entire field (and have no NUL byte) by using a precision specifier. --- tar.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tar.c b/tar.c index 47d2334..7588a41 100644 --- a/tar.c +++ b/tar.c @@ -29,6 +29,7 @@ struct Header { char gname[32]; char major[8]; char minor[8]; + char prefix[155]; }; enum { @@ -317,11 +318,14 @@ c(const char * path) static void xt(int (*fn)(char*, int, char[Blksiz])) { - char b[Blksiz], fname[101]; + char b[Blksiz], fname[257], *s; Header *h = (void*)b; while(fread(b, Blksiz, 1, tarfile) && h->name[0] != '\0') { - snprintf(fname, sizeof fname, "%s", h->name); + s = fname; + if (h->prefix[0] != '\0') + s += sprintf(s, "%.*s/", (int)sizeof h->prefix, h->prefix); + sprintf(s, "%.*s", (int)sizeof h->name, h->name); fn(fname, strtol(h->size, 0, 8), b); } } -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 3/4] tar: Implement -m flag
This changes the default behavior to adjust mtimes to what is present in the file header. --- tar.c | 25 ++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tar.c b/tar.c index 7bd709d..47d2334 100644 --- a/tar.c +++ b/tar.c @@ -2,9 +2,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -49,13 +51,15 @@ static FILE *tarfile; static ino_t tarinode; static dev_t tardev; +static bool mflag = false; + static void usage(void) { - eprintf("usage: tar [-f tarfile] [-C dir] [-]x|t\n" + eprintf("usage: tar [-f tarfile] [-C dir] [-]x[m]|t\n" " tar [-f tarfile] [-C dir] [-]c dir\n" " tar [-C dir] cf tarfile dir\n" - " tar [-C dir] x|tf tarfile\n"); + " tar [-C dir] x[m]|tf tarfile\n"); } int @@ -79,6 +83,9 @@ main(int argc, char *argv[]) case 'f': file = EARGF(usage()); break; + case 'm': + mflag = true; + break; default: usage(); } ARGEND; @@ -108,6 +115,9 @@ main(int argc, char *argv[]) argc--, argv++; dir = argv[0]; break; + case 'm': + mflag = true; + break; default: usage(); } @@ -224,9 +234,12 @@ unarchive(char *fname, int l, char b[Blksiz]) { char lname[101]; FILE *f = NULL; - unsigned long mode, major, minor, type; + unsigned long mode, major, minor, type, mtime; + struct timeval times[2] = {0}; Header *h = (void*)b; + if(!mflag) + mtime = strtoul(h->mtime, 0, 8); unlink(fname); switch(h->type) { case REG: @@ -276,6 +289,12 @@ unarchive(char *fname, int l, char b[Blksiz]) } if(f) fclose(f); + + if(!mflag) { + times[0].tv_sec = times[1].tv_sec = mtime; + if(utimes(fname, times)) + perror(fname); + } return 0; } -- 2.1.3.1.g339ec9c
[dev] [sbase] [PATCH 2/4] tar: Support typeflag '\0' when extracting
POSIX recommends that "For backwards-compatibility, a typeflag value of binary zero ( '\0' ) should be recognized as meaning a regular file when extracting files from the archive". --- tar.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tar.c b/tar.c index c18d89e..7bd709d 100644 --- a/tar.c +++ b/tar.c @@ -34,7 +34,7 @@ enum { }; enum Type { - REG = '0', HARDLINK = '1', SYMLINK = '2', CHARDEV = '3', + REG = '0', AREG = '\0', HARDLINK = '1', SYMLINK = '2', CHARDEV = '3', BLOCKDEV = '4', DIRECTORY = '5', FIFO = '6' }; @@ -230,6 +230,7 @@ unarchive(char *fname, int l, char b[Blksiz]) unlink(fname); switch(h->type) { case REG: + case AREG: mode = strtoul(h->mode, 0, 8); if(!(f = fopen(fname, "w")) || chmod(fname, mode)) perror(fname); -- 2.1.3.1.g339ec9c
Re: [dev] [st] will global-less changes be wanted upstream?
On Sat, Aug 16, 2014 at 06:32:01PM -0500, Steven Degutis wrote: > > What is the point? > > One obvious cons is that it will bloat the code, make it less readable. > > First of all, I would not agree that it would bloat the code or make > it less readable. In fact I think it will increase readability, as > object structure and hierarchy will be more readily apparent. Plus, it > would make for a more clean and obvious separation of > responsibilities, such as terminal logic and logic for drawing to the > screen, &c. > > As a consequence, it might become easier for contributions to my fork > of the terminal logic (i.e. if my users submit bug fixes or new > features, &c.) to be merged upstream to st, where they would also be > relevant. I am interested in a separation of terminal and windowing system logic for my wayland port[0] of st. That said, I don't really see how moving globals into a Term structure would help with this. I think you could accomplish this by moving any X-related code to an x.c, and then you could drop in a wayland.c or whatever.c, and have config.mk choose which one gets built into st. I think it would also be beneficial because it is difficult (at least for me) to keep track of a single ~4k line c file. [0]: https://github.com/michaelforney/st.git
[dev] [st] [PATCH] Fix disabling of bold and fastblink
According to ECMA-48¹ 8.3.117, an attribute value of 21 is "doubly underlined", while 22 is "normal colour or normal intensity (neither bold nor faint)". Additionally, 25 is "steady (not blinking)", which likely means neither slow blink nor fast blink. ¹: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf --- st.c | 10 ++ 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/st.c b/st.c index 546db41..0c917fd 100644 --- a/st.c +++ b/st.c @@ -1718,11 +1718,8 @@ tsetattr(int *attr, int l) { case 9: term.c.attr.mode |= ATTR_STRUCK; break; - case 21: - term.c.attr.mode &= ~ATTR_BOLD; - break; case 22: - term.c.attr.mode &= ~ATTR_FAINT; + term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT); break; case 23: term.c.attr.mode &= ~ATTR_ITALIC; @@ -1731,10 +1728,7 @@ tsetattr(int *attr, int l) { term.c.attr.mode &= ~ATTR_UNDERLINE; break; case 25: - term.c.attr.mode &= ~ATTR_BLINK; - break; - case 26: - term.c.attr.mode &= ~ATTR_FASTBLINK; + term.c.attr.mode &= ~(ATTR_BLINK | ATTR_FASTBLINK); break; case 27: term.c.attr.mode &= ~ATTR_REVERSE; -- 1.8.5.1
Re: [dev] swc: A small Wayland compositor
On Sun, 26 Jan 2014 02:09:31 +0100, Markus Teich wrote: > Heyho, > > why do you not put the VT switching and input dev fd handling code into swc. > In > this case the developer implementing a wm would have to do priviledge > dropping. > This leads to one suid executable per wm without the need of a launcher. Am I > missing something here? Hi Markus, The VT/TTY related code could go into swc, but having the window manager drop privileges by itself won't work because it needs those again to reopen input devices and regain DRM master when it's VT is activated again. Also, it is quite handy to have your VT restored upon a crash (instead of leaving it in graphics mode with the keyboard turned off). On Sun, 26 Jan 2014 19:06:21 +0100, FRIGN wrote: > Why not specify this part in a config.h? Given the resulting wm is very > small, this suckless-concept applied would be very convenient. If I do end up adding such a list of allowed display servers, this does seem like a good way to do it. In any case, I think that this issue is fairly minor (at first glance, it looks like systemd's logind acts the same way as swc-launch with respect to opening and revoking devices) and for now I will probably leave it as-is. As swc matures, we could revisit this if it does present any problems. -- Michael Forney
Re: [dev] swc: A small Wayland compositor
On Fri, 24 Jan 2014 09:23:20 +0100, Silvan Jegen wrote: > > This is very exciting. I hope to play with this in the next few days. > > I agree! I hope I'll find the time to look into the code base some I've added a minimal example window manager in example/. It can be built with "make example", and run with "launch/swc-launch example/wm". Note that swc-launch needs either setuid root or to be run as root in order to open input devices and to obtain DRM modesetting privileges. Possible security concern: swc-launch passes opened input device file descriptors to the user-specified display server process (which is run with reduced privileges). However, it also switches to a new unused VT, and revokes them when this VT is switched away from. One potential issue with this is that it doesn't prevent a malicious program from pretending to be swc-launch and starting a trusted display server to appear normal, but underneath intercept any key presses. Though, I'm also not sure that the situation is any better on X ("xev -id window-id" can dump input events sent to window-id). Weston solves this problem by hardcoding the display server path in weston-launch. For swc, this would imply a separate launcher program for each window manager, which doesn't seem like a good solution to me. On a single-user development machine, it is quite convenient to be able to run, for example, "swc-launch -- valgrind example/wm" to debug crashes. However, I do see the potential risk. Another solution could be having a configuration file in /etc containing a list of allowed display servers. Thoughts? -- Michael Forney
[dev] swc: A small Wayland compositor
Hi suckless, As discussed in the previous thread (swc library to implement dwm under Wayland), I've been working on a Wayland compositor library, and after several redesigns, I'm pretty happy with where it is now. You can find the source here: https://github.com/michaelforney/swc There is still some more work to be done, in particular moving/resizing windows with the mouse, and more careful handling of special window states (for example transient and fullscreen). However, for basic usage it should work fine. Here is the current output of sloccount: SLOCDirectory SLOC-by-Language (Sorted) 5801libswc ansic=5801 533 launch ansic=533 409 cursor ansic=409 launch/ contains code for swc-launch, a privileged launcher that handles VTs, managing DRM master, and opening/revoking input devices. cursor/ contains a program taken from wayland to extract cursors from the X server cursor font. As far as dependencies go, currently you need wayland, libdrm, libevdev, libxkbcommon, pixman, and wld[0]. wld contains the buffer management and rendering code used by swc and Wayland versions of st and dmenu. Optionally, you can use libudev for input hotplugging. This is the only way I know to accomplish this, and I am open to suggestions for alternatives (I'd still like to remain compatible with systems running udevd though). I'd also like suggestions for how to deal with configuration for things like what settings to use for XKB (keyboard layout, etc). This is a per-user setting, so I don't think setting it in a config.h would be appropriate. I have not begun any process of porting/rewriting dwm to use swc. I figured I'd see where people want to go from here. One potential obstacle that might show up is the status bar. Since with swc the window manager is in the same process as the compositor, currently the status bar would have to go in to a separate process. I accomplished this in the video below by adding a protocol extension which can notify clients when certain things happen in the window manager (like workspace or focus change). I'm not sure if this is the best approach though. I made a demo video showing some of swc's features (as well as Wayland st and dmenu) here: http://www.youtube.com/watch?v=5thcLnLHkjs&hd=1 The window manager used in the video is one that I started quite a while ago, which I hacked up to use swc instead. It suits my needs for developing swc, but I'd like to see what others can come up with! The public API is available in swc.h[1]. Comments, questions, and criticism are welcome! You can find me on freenode or OFTC under the nick tridactyla. [0]: https://github.com/michaelforney/wld [1]: https://github.com/michaelforney/swc/blob/master/libswc/swc.h -- Michael Forney
Re: swc library to implement dwm under Wayland (was Re: [dev] gtk3 support for surf?)
On Tue, 14 Jan 2014 20:41:40 +0100, Hadrian WÄgrzynowski wrote: > EGL as API is quite lean. There could be small implementation not > depending on Mesa 3D. > > Is there another problem with EGL? EGL is fine, but it implies an implementation of OpenGL, which would be quite complicated to implement. > I am just curious: > 1. Can Wayland clients use just simple blitting without special kernel > infrastructures? Yes, there is an interface wl_shm in the core protocol which allows clients to create a shared memory buffer, render to it by whatever means it wants, and then pass the file descriptor to the server. > 2. Can Wayland Compositor work without special kernel infrastructures? The protocol allows it, but at some stage your screen buffer needs to get scanned out to your monitor, which requires some sort of kernel interface. > 3. Are Wayland clients using evdev or is it just for server? Just the server. Clients receive input events via the wl_keyboard and wl_pointer interfaces. > 4. Does anybody know how good is pixman library (AFAIK software renderer > used by Weston)? I've found that while it isn't documented that well, it is very useful and well optimized (from what I can tell). Text rendering was a bit tough to get working because you have to do glyph arrangement and rendering yourself (probably using FreeType). -- Michael Forney
Re: swc library to implement dwm under Wayland (was Re: [dev] gtk3 support for surf?)
ager can specify a border width and color for each window, just like in X. My st and dmenu ports do nothing in terms of borders/window decorations (same as they currently work in X). Now, as far as other applications go, Gtk+ currently draws these massive decorations around everything when running under Wayland. Given that the Qt/KDE guys want to use server-side decorations, I'm sure that there will be some setting you can disable to get rid of the borders (maybe there already is, I haven't looked into it). I'm in agreement that Weston is not the way to go. I think it would be quite difficult to add server-side borders to the existing Weston code-base, and would almost certainly not be accepted upstream. > -4) Sucklessness > What should we do then? > My advice would be to take a look at tinyx[2] and tinyxlib[3], which is > relatively small and fitting the purpose well (dwm runs on it). > > Let's see what the future will bring us, but it now is all about making > a decision. I don't think it is so important to make a decision as much as to be aware of all the possibilities. Also, while I'm happy that swc is getting attention, it is perhaps happening just a little too early; don't expect to be able to try it out right now, I have a lot of changes pending in my working tree which I hope to get committed over the next few days. Additionally, there are a couple of final things I need to finish up (mainly VT switching). -- Michael Forney
Re: [dev] gtk3 support for surf?
Hi, On Fri, 10 Jan 2014 17:05:17 +0100, FRIGN wrote: > On Fri, 10 Jan 2014 18:49:13 +0100 > Markus Teich wrote: > > > If I can, I would like to help. Where is the code hosted? I also found > > swc[0] > > written by the same guy who wrote the st port to wayland. However I feel it > > is > > not really as simple as it claims to be. > > The code is hosted here[1]. > Thanks for linking me to swc! I'll check it out and combine it with my > ideas. There really is a lot of code in that library! I'm glad others are interested in this! In response to your comments about it being a lot of code: writing a display server turns out to be a lot of work, which I'm sure you will discover for yourself :) Although perhaps it appears larger than it is; I tend to prefer working with many small files instead of several large ones. While there are a lot of source files, my current working tree sits at < 6k SLOC. Additionally, I am quite open to suggestions about how certain portions could be simplified or done differently. I am definitely interested in combining efforts/ideas if possible. I've been working on this off and on for about a year now, and I have learned a lot in that time. Feel free to use swc as a reference for your project if you want (I do believe it to be quite a bit simpler than weston). Perhaps the biggest obstacle I've come across is how to do rendering in a simple and efficient way, yet retain hardware support. I opted to create a very primitive drawing library (which is also used by my st and dmenu ports), which I am currently in the middle of a major refactor. It currently only supports software and intel hardware rendering. There is of course OpenGL, and while it will most likely be available on the majority of systems, it is fairly heavyweight for the job. > I'll definitely give you guys an update on my status, but I'm sure > there should be a way to write a simple tiling-wm in less than 5k SLOC. I'm of the opinion that the compositor and window manager should be separate projects, which is why I implemented swc as a library. Look at the number of tiling X11 window managers out there. It doesn't make sense to have each of them implement their own compositing code. Please let me know if you have any questions! I would be happy to help! -- Michael Forney
Re: [dev] [st] [PATCH] Fix some bugs in mouse tracking logic
On Thu, 01 Aug 2013 10:10:23 +0200, "Roberto E. Vargas Caballero" wrote: > > This suggests that we should still add 32 to the button value when in > > MODE_MOUSEX10. > > It is no clear for me if we have to add it or not, did you test it with > other emulators? Hi, I apologize for the delay in getting back to you (I've been distracted by other projects). I'm fairly certain that we are supposed to always add 32 unless in SGR mode. I've just now confirmed with the xterm (version 296) source code: button.c:4254 > static unsigned > EmitButtonCode(TScreen * screen, > Char * line, > unsigned count, > XButtonEvent * event, > int button) > { > int value; > > if (screen->send_mouse_pos == X10_MOUSE) { > value = CharOf(' ' + button); > } else { > value = BtnCode(event, button); > } > > switch (screen->extend_coords) { > default: > line[count++] = CharOf(value); > break; > case SET_SGR_EXT_MODE_MOUSE: > value -= 32;/* encoding starts at zero */ > /* FALLTHRU */ > case SET_URXVT_EXT_MODE_MOUSE: > count += (unsigned) sprintf((char *) line + count, "%d", value); > break; > case SET_EXT_MODE_MOUSE: > if (value < 128) { > line[count++] = CharOf(value); > } else { > line[count++] = CharOf(0xC0 + (value >> 6)); > line[count++] = CharOf(0x80 + (value & 0x3F)); > } > break; > } > return count; > } As you can see, value begins as ' ' (== 32) + the button value (BtnCode also adds 32), and then 32 is subtracted only when in SGR mode. -- Michael Forney
Re: [dev] Wayland st!!??
On Mon, 29 Jul 2013 12:47:49 +0200, Silvan Jegen wrote: > So the reason you would not want dwm to be a shell plugin for Weston is > that Weston is too focused on fancy modern features, correct? Eh, maybe I am being a bit too hard on Weston. It just seems to be growing quite steadily which scares me and I wasn't thrilled with it overall. > Implementing a proxy wl_shell for this hypothetical blitting compositor > and having dwm as a separate process communicating with it would be > another possible approach. Yeah, that's what I tried to describe. -- Michael Forney
Re: [dev] Wayland st!!??
On Mon, 29 Jul 2013 09:59:06 +0200, Silvan Jegen wrote: > I am very interested in st (as well as other suckless projects) > on weston/wayland as well. > > The wayland protocol seems to be very concise and it certainly does not > come with all of the legacy baggage of X. That said, I noticed that the > wayland port of the st code is around 70 lines longer than the X > version[1]. I have not investigated way that is though. It's mostly because of the many event handlers. In Wayland, you don't have to register listeners for objects, but if you do, you have to implement all of it's events. Mostly this is okay, but in a few places, there were some events that I didn't use, like the drag and drop facilities in wl_data_device. Also, Wayland uses separate events for button/key press/release as well as axis (which required a new axis binding shortcut list in config.h and handling in st.c). These little changes add up (function prototypes as well as definitions), which account for the difference in code size. However, nearly all of this is cosmetic and doesn't really affect the code's complexity. > As far as I know dwm would have to be ported as a wayland-compositor > (which does not do any composing). Does anyone know of a > dwm-port/suckless-compositor for the wayland protocol that is still > being actively developed? Making dwm act as a Wayland shell (what Wayland calls a window manager), wouldn't be too difficult. Many of the X11 related bits correspond fairly closely to wl_shell bits, and the ones that don't probably aren't even necessary under Wayland. However, the compositor part is tricky. The easiest method would be to make dwm a shell plugin for Weston. I don't like this approach because Weston seems to be focusing on a more "modern" desktop features like animation, transparency, window decorations, etc. I also dislike the idea of dwm being loaded as a plugin. I don't think that implementing a compositor from scratch (which would do nothing more than blit the windows onto your screen, and maybe draw some borders) is out of the question. I'm estimating that it could be done in ~4000 lines (maybe more, maybe less). The question in this scenario is where does the window manager fit in? I don't like the idea of the window manager being in the same project as the compositor, as they do two different jobs and other window managers should be able to make use of it as well. However, there has to be some implementation of wl_shell on the compositor side. One solution would be to make a protocol extension (which are really easy to do) and use it to communicate with a separate window manager process. This would be similar to how an X window manager works, but it would require implementing a wl_shell that kind of acts as a proxy. Another option would be to make the compositor into a library that a window manager can link with. The wl_shell implementation would be more direct but then we would have to deal with giving the window manager/compositor special privileges (Weston does this by using a suid launcher which does stuff like open input devices and manage drm master through a socket pair). Another problem is that we would have a single program which does quite a lot of stuff. I'd love to hear other people's opinions on this topic. -- Michael Forney
Re: [dev] Wayland st!!??
On Sat, 27 Jul 2013 14:17:42 -0400, Carlos Torres wrote: > I didn't know about this > > http://www.phoronix.com/scan.php?page=news_item&px=MTQyMTQ > > I'm both excited or looking to troll I'm the author of the port. I'm not sure how the suckless community feels about Wayland, but it seems like the core protocol is fairly lightweight, depends only on libffi, and is refreshing to work with compared to X. Weston's goals are perhaps more orthogonal to suckless, but I think there is potential for a suckless compositor. I don't really expect there to be a suckless Wayland environment for a while, and maybe something better will come around before there is, but I think my rendering library could be useful in either case (the Wayland part is just buffer creation/management and is separate from the rendering part). -- Michael Forney
[dev] [st] [PATCH] Fix blink mode check
ATTR_BLINK is an attribute for a Glyph and will not be set in term.mode. --- Again, I haven't actually run into any problems caused by this, but this seems like a typo to me. st.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/st.c b/st.c index 8992998..734c345 100644 --- a/st.c +++ b/st.c @@ -3544,8 +3544,8 @@ run(void) { ttyread(); if(blinktimeout) { blinkset = tattrset(ATTR_BLINK); - if(!blinkset && term.mode & ATTR_BLINK) - term.mode &= ~(MODE_BLINK); + if(!blinkset) + MODBIT(term.mode, 0, MODE_BLINK); } } -- 1.8.3